2014-10-27 163 views
3

我試圖在圖像中間檢測到一個圓形對象。下面是一個示例圖像:在閾值之前對Opencv感興趣的圓形區域

左半是greyscaled和高斯模糊輸入圖像;右半部分是大津閾值後的相同圖像。左下角的陰影銀色將大津的門檻引向歧途。有沒有辦法設置一個圓形的感興趣區域,這樣可以避免角落的噪音?

+0

我不想讓你泄氣,而是要能夠找到足夠的精度,你得到一個圓形的投資回報率擺脫黑暗的角落,您需要首先對物體進行二值化處理以找到其中心和大小。雞和雞蛋的問題。 – 2014-10-27 19:58:50

+0

我寧願不要模糊這麼多,它是溶解邊緣。同樣,在陰影類型的情況下,我傾向於應用自適應閾值或漸變來僅獲得原則邊緣,以避免像左下角那樣的情況。之後,您可以應用霍夫圈或輪廓等。 – 2014-10-28 06:24:35

回答

5

使用Hough Circle Transform直接上好的限圖像樣的作品對於這種特殊情況下,即使檢測到的圈子有點偏差:

cv::Mat thres; 
cv::threshold(gray, thres, 110, 255, cv::THRESH_BINARY); 

std::vector<cv::Vec3f> circles; 
cv::HoughCircles(thres, circles, cv::HOUGH_GRADIENT, 1, thres.rows/2, 20, 15); 
for (size_t i = 0; i < circles.size(); i++) 
{ 
    cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 
    int radius = cvRound(circles[i][2]); 
    cv::circle(input, center, 3, cv::Scalar(0, 255, 255), -1); 
    cv::circle(input, center, radius, cv::Scalar(0, 0, 255), 1); 
} 

在更復雜的情況下,你可能要嘗試其他閾值法,以及fill the internal parts(holes) of the segments重建他們回到一個橢圓形。

下面示出的處理流水線執行以下操作以提高硬幣的檢測:

  • 輸入圖像爲灰度轉換;
  • 應用閾值;
  • 執行形態學操作以連接附近的片段;
  • 填充段內的孔;
  • 最後,調用cv::HoughCircles()來檢測圓形。

有可能注意到,硬幣檢測是多一點點集中使用這種方法。總之,這裏的這樣神奇的C++代碼示例:

// Load input image 
cv::Mat input = cv::imread("coin.jpg"); 
if (input.empty()) 
{ 
    std::cout << "!!! Failed to open image" << std::endl; 
    return -1; 
} 

// Convert it to grayscale 
cv::Mat gray; 
cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY); 

// Threshold the grayscale image for segmentation purposes 
cv::Mat thres; 
cv::threshold(gray, thres, 110, 255, cv::THRESH_BINARY); 
//cv::imwrite("threhsold.jpg", thres); 

// Dirty trick to join nearby segments 
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(15, 15)); 
cv::morphologyEx(thres, thres, cv::MORPH_OPEN, element); 
//cv::imwrite("morph.jpg", thres); 

// Fill the holes inside the segments 
fillHoles(thres); 
//cv::imwrite("filled.jpg", thres); 

// Apply the Hough Circle Transform to detect circles 
std::vector<cv::Vec3f> circles; 
cv::HoughCircles(thres, circles, cv::HOUGH_GRADIENT, 1, thres.rows/2, 20, 15); 
std::cout << "* Number of detected circles: " << circles.size() << std::endl; 

for (size_t i = 0; i < circles.size(); i++) 
{ 
    cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); 
    int radius = cvRound(circles[i][2]); 
    cv::circle(input, center, 3, cv::Scalar(0,255,255), -1); 
    cv::circle(input, center, radius, cv::Scalar(0,0,255), 1); 
} 

cv::imshow("Output", input); 
//cv::imwrite("output.jpg", input); 

cv::waitKey(0); 

Helper function

void fillHoles(cv::Mat& img) 
{ 
    if (img.channels() > 1) 
    { 
     std::cout << "fillHoles !!! Image must be single channel" << std::endl; 
     return; 
    } 

    cv::Mat holes = img.clone(); 
    cv::floodFill(holes, cv::Point2i(0,0), cv::Scalar(1)); 

    for (int i = 0; i < (img.rows * img.cols); i++) 
     if (holes.data[i] == 255) 
      img.data[i] = 0; 
} 
+1

非常感謝!但是我仍然想知道,現在我大概知道硬幣的位置,有沒有辦法在大津閾值之前設置一個感興趣的圓形區域,以便可以忽略黑暗的角落?我試圖儘可能找到最精確的硬幣位置。 – 2014-10-28 18:40:46

+1

因爲OTSU(或任何其他閾值操作)是定位該區域的過程的一部分,所以在執行OTSU之前,您無法定義該圖像中的感興趣區域。 :)但是你可以嘗試其他的東西,如直方圖均衡,模糊或其他過濾操作,以在圖像閾值之前嘗試去除黑點。 – karlphillip 2014-10-28 18:49:02

1

你可以使用霍夫的finding circles

/// Apply the Hough Transform to find the circles 
HoughCircles(src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0); 

你找到的最大的循環後,可以設置爲0,所有的像素外

相關問題