2013-07-19 4 views
7

제 작품은 도트 배열 (그림 1)이있는 이미지를 기반으로하며, 최종 결과는 그림 4에 나와 있습니다. 단계별로 설명하겠습니다.Opencv : 가장자리 감지, 확장 및 질량계 도면

그림 1 개 원본 이미지

enter image description here

1 단계 :. 내가 더 나은 성능을 위해 삭제하려는 점과 "링"을 포함한 모든 객체의 가장자리를 감지합니다. 그리고 엣지 검출의 결과가 그림 2에 나와 있습니다. 나는 Canny 엣지 디텍터를 사용했으나 일부 ​​밝은 회색 점에서는 잘 작동하지 않았습니다. 첫 번째 질문은 도트의 윤곽을 닫고 가능한 한 다른 노이즈를 줄이는 방법입니다.

도 2 에지 검출

enter image description here

. 단계 2 : 팽창 모든 개체. 나는 구멍을 채우기위한 좋은 방법을 찾지 못했고 그래서 나는 그것들을 직접 넓혔다. 도 3에 도시 된 바와 같이, 홀은 너무 많이 확대되는 것처럼 보이고 다른 노이즈도 증가한다. 두 번째 질문은 구멍을 채우거나 확장하여 구멍을 같은 크기로 채우는 방법입니다.

도 3 팽창 시킴

enter image description here

3 단계 :. 찾아서 각 도트의 질량 중심을 그린다. 도 4에 도시 된 바와 같이, 거친 화상 처리로 인해, "링"의 마크가 존재하고, 몇몇 도트는 2 개의 백색 픽셀로 도시된다. 원하는 결과는 점 하나에 하나의 흰색 픽셀 만 표시해야합니다.

그림 4. 질량 센터

enter image description here

다음은이 3 단계에 대한 나의 코드입니다. 누구든지 내 일을 더 잘하도록 도와 줄 수 있습니까?

#include "opencv2/imgproc/imgproc.hpp" 
#include "opencv2/highgui/highgui.hpp" 
#include <stdlib.h> 
#include <stdio.h> 
#include <cv.h> 
#include <highgui.h> 
using namespace std; 
using namespace cv; 

// Global variables 
Mat src, edge, dilation; 
int dilation_size = 2; 

// Function header 
void thresh_callback(int, void*); 

int main(int argc, char* argv) 
{ 
    IplImage* img = cvLoadImage("c:\\dot1.bmp", 0);   // dot1.bmp = Fig. 1 

    // Perform canny edge detection 
    cvCanny(img, img, 33, 100, 3); 

    // IplImage to Mat 
    Mat imgMat(img); 
    src = img; 

    namedWindow("Step 1: Edge", CV_WINDOW_AUTOSIZE); 
    imshow("Step 1: Edge", src); 

    // Apply the dilation operation 
    Mat element = getStructuringElement(2, Size(2 * dilation_size + 1, 2 * dilation_size + 1), 
        Point(dilation_size, dilation_size));  // dilation_type = MORPH_ELLIPSE 
    dilate(src, dilation, element); 
    // imwrite("c:\\dot1_dilate.bmp", dilation);    

    namedWindow("Step 2: Dilation", CV_WINDOW_AUTOSIZE); 
    imshow("Step 2: Dilation", dilation); 

    thresh_callback(0, 0); 

    waitKey(0); 
    return 0; 
} 

/* function thresh_callback */ 
void thresh_callback(int, void*) 
{ 
    vector<vector<Point>> contours; 
    vector<Vec4i> hierarchy; 

    // Find contours 
    findContours(dilation, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 

    // Get the moments 
    vector<Moments> mu(contours.size()); 
    for(int i = 0; i < contours.size(); i++) { 
     mu[i] = moments(contours[i], false); 
    } 

    // Get the mass centers 
    vector<Point2f> mc(contours.size()); 
    for(int i = 0; i < contours.size(); i++) { 
     mc[i] = Point2f(mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00); 
    } 

    // Draw mass centers 
    Mat drawing = Mat::zeros(dilation.size(), CV_8UC1); 
    for(int i = 0; i< contours.size(); i++) { 
     Scalar color = Scalar(255, 255, 255); 
     line(drawing, mc[i], mc[i], color, 1, 8, 0); 
    } 

    namedWindow("Step 3: Mass Centers", CV_WINDOW_AUTOSIZE); 
    imshow("Step 3: Mass Centers", drawing); 
} 
+0

[여기] (http://stackoverflow.com/questions/1716274/fill-the-holes-in-opencv)에서 아무 것도 시도하지 않으셨습니까? – William

답변

9

결과를 향상시키기 위해 할 수있는 몇 가지 방법이 있습니다. 이미지의 노이즈를 줄이려면 Canny 연산자를 적용하기 전에 중간 흐림 효과를 적용 할 수 있습니다. 이것은 일반적인 노이즈 제거 기술입니다. 또한 C API 및 IplImage을 사용하지 마십시오. Canny result

더 나은 점의 원래 크기를 유지하려면, 당신은 작은 커널보다는와 형태 폐쇄 몇 반복을 수행 할 수 있습니다

cv::Mat img = cv::imread("c:\\dot1.bmp", 0);   // dot1.bmp = Fig. 1 

    cv::medianBlur(img, img, 7); 

    // Perform canny edge detection 
    cv::Canny(img, img, 33, 100); 

이것은 상당히 에지 이미지의 노이즈의 양을 감소 팽창. 이것은 또한 원 점의 결합을 감소시킬 것이다 : 이것은 cv::noArray()를 사용하여 표시되는 3 × 3 커널, 두 개의 반복을 수행합니다

// This replaces the call to dilate() 
cv::morphologyEx(src, dilation, MORPH_CLOSE, cv::noArray(),cv::Point(-1,-1),2); 

.

결과는 깨끗하고, 점 완전히 채워됩니다

Closing result

는 수정되지 않은 최종 결과를 제공 파이프 라인의 나머지 부분을 떠난다. 기존 방법보다 훨씬 적은이 원에서 몇 가짜 질량 센터는 여전히 있지만 : 당신은 완전히 결과에서 원을 제거하는 시도를하고 싶었다면

Mass centers

, 당신은 cv::HoughCircles()을 사용하고 조정을 시도 할 수 당신이 좋은 결과를 얻을 때까지 매개 변수. 전체 원이 이미지에 표시되지 않고 세그먼트 만 표시되기 때문에 약간의 어려움이있을 수 있지만 실험 해 보시기 바랍니다. 가장 안쪽의 원을 감지했다면, 그것을 외부 매스 센터를 걸러 내기위한 마스크로 사용할 수 있습니다.

+0

감사합니다. 내 작업을 개선했습니다. 또 다른 질문 : 나는 cv :: Canny와 cvCanny 사이에 약간의 차이가 있음을 발견했다. 왜 그들은 두 개의 비슷한 함수를 만들었고 어떤 함수 (접두어'cv ::'와'cv')를 더 자주 사용해야합니까? – WangYudong

+0

둘 사이에는 차이가 없어야합니다. 내부적으로 동일한 구현을 사용합니다. 'cv :: Canny()'는 C++ API에서'cv :: Mat'과 함께 사용됩니다. 'cvCanny()'는'IplImage'를 사용하는 C API에서 왔으며 더 이상 사용되지 않습니다. – Aurelius

5

도트의 윤곽을 닫는 방법? 사용 채워진 드로잉 옵션 drawContours 방법 (CV_FILLED 또는 두께 = -1)

노이즈 감소?blurring (저역 필터링) 방법 중 하나를 사용합니다.

비슷한 크기?은 확장 후 침식 = morphological closing을 사용합니다.

하나의 원에 대해 하나의 점, 외부 링이없는 출력? 모두의 평균을 찾으십시오 contour areas. erase contours이 값과 큰 차이가 있습니다. 나머지 센터를 출력하십시오.

Aurelius는 이미 대부분을 언급했지만이 문제는 매우 흥미로 우며 충분히 시간이 지나면 나는 완전한 해결책을 게시하려고합니다. 행운을 빕니다.