my work based on images array of dots (fig. 1), , final result shown in fig. 4. explain work step step.
fig. 1 original image

step 1: detect edge of every object, including dots , "ring" want delete better performance. , result of edge detection shown in fig.2. used canny edge detector didn't work light-gray dots. my first question how close contours of dots , reduce other noise as possible?
fig. 2 edge detection

step 2: dilate every object. didn't find way fill holes, dilate them directly. shown in fig.3, holes seem enlarged , other noise. my second question how fill or dilate holes in order make them filled circles in same/similar size?
fig. 3 dilation

step 3: find , draw mass center of every dot. shown in fig. 4, due coarse image processing, there exist mark of "ring" , of dots shown in 2 white pixels. the result wanted should show dots , 1 white pixel 1 dot.
fig. 4: mass centers

here code these 3 steps. can make work better?
#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 mat mat imgmat(img); src = img; namedwindow("step 1: edge", cv_window_autosize); imshow("step 1: edge", src); // apply 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)); // moments vector<moments> mu(contours.size()); for(int = 0; < contours.size(); i++) { mu[i] = moments(contours[i], false); } // mass centers vector<point2f> mc(contours.size()); for(int = 0; < 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 = 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); }
there few things can improve results. reduce noise in image, can apply median blur before applying canny operator. common de-noising technique. also, try avoid using c api , iplimage.
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); this reduces amount of noise in edge image: 
to better retain original sizes of dots, can perform few iterations of morphological closing smaller kernel rather dilation. reduce joining of dots circle:
// replaces call dilate() cv::morphologyex(src, dilation, morph_close, cv::noarray(),cv::point(-1,-1),2); this perform 2 iterations 3x3 kernel, indicated using cv::noarray().
the result cleaner, , dots filled:

leaving rest of pipeline unmodified gives final result. there still few spurious mass centers circle, considerably fewer original method:

if wanted attempt removing circle results entirely, try using cv::houghcircles() , adjusting parameters until result. might have difficulties because entire circle not visible in image, segments, recommend experiment it. if did detect innermost circle, use mask filter out external mass centers.
Comments
Post a Comment