1. 使用Matlab 的imfill进行填充图像在Matlab中简单的几行代码就能实现:
1 2 3 4 5 6 7 8 | clc; clear; BW=im2bw(imread('imfilltest.tif')); imshow(BW); holes=imfill(BW,'holes'); BW(~holes)=1; figure,imshow(holes); |
2.用opencv来实现imfill(bw, 'holes')opencv在这里不像matlab那么好用了,matlab调用下。C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #include #include #include usingnamespacestd; usingnamespacecv; voidmy_imfillholes(Mat&src) { //detectexternalcontours // vector>contours; vectorhierarchy; findContours(src,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE); // //fillexternalcontours // if(!contours.empty()&&!hierarchy.empty()) { for(intidx=0;idx<contours.size();idx++) { drawContours(src,contours,idx,Scalar::all(255),CV_FILLED,8); } } } voidtest_my_imfillholes() { Matm=imread(filltestName,IMREAD_GRAYSCALE); //threshold,(i,j)>100-->255 Matth_m; threshold(m,th_m,100,255,THRESH_BINARY); my_imfillholes(th_m); namedWindow(WinName,CV_WINDOW_AUTOSIZE); imshow(WinName,th_m); waitKey(0); } voidmain() { test_my_imfillholes(); system("pause"); } |
3. imfill和opencv实现的imfill 对矩阵进行操作的对比我仍有点不放心,觉得尽管2幅图看起来差不多,但是是不是完全一样呢,然后我觉得用个矩阵试一下。m = [1, 1, 1, 0, 0, 0,0, 0; 1, 0, 1, 0, 1, 1, 0, 0; 1, 0, 1, 0, 1, 1, 0, 0; 1, 1, 1, 0, 1, 0, 1, 0; 1, 0, 1, 0, 1, 0, 1, 0; 1, 1, 1, 0, 1, 0, 1, 0; 1, 0, 1, 0, 0, 1, 1, 0; 1, 1, 1, 0, 0, 0, 0, 0];without_holes =imfill(m, 'holes')
得到结果:without_holes=
11100000
11101100
11101100
11101110
11101110
11101110
11100110
11100000然后用第2部分所说的opencv的方法也试一下,结果发现是这样的:without_holes=
00000000
0 1101100
01101100
0 1101110
01101110
01101110
01100110
00000000是不一样的。这个问题折腾了我一个晚上,终于,我在http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours中的findContours找到了这样的一个note:Note:Source image is modified by this function. Also,the function does not take into account1-pixel border of the image (it’s filled with 0’s andused for neighbor analysis in the algorithm), therefore thecontours touching the image border will be clipped.它的意思是,findCountours是不会包含1-pixel的边界的。所以这就是为啥opencv计算的结果中边界的1都消失的原因。我想,既然边界不被包含,那么我给它上下左右加一个1-pixel的框,这样边界点就变成了内部点,就能成功的用findCountours了。于是乎:我写了下面的code:C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include #include #include usingnamespacestd; usingnamespacecv; voidmy_imfillholes_v2() { //step1:makeaborder Matm(8,8,CV_8UC1,data); Matm_with_border; copyMakeBorder(m,m_with_border,1,1,1,1,BORDER_CONSTANT,Scalar()); cout<<m_with_border<<endl; //setp2:findthecontourfillholes vector>contours; vectorhierarchy; findContours(m_with_border,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE); // //fillexternalcontours // if(!contours.empty()&&!hierarchy.empty()) { for(intidx=0;idx<contours.size();idx++) { drawContours(m_with_border,contours,idx,Scalar::all(1),CV_FILLED,8); } } //cout<<m_with_border<<endl; //step3:removetheborder m_with_border=m_with_border.rowRange(Range(1,m_with_border.rows-1)); //cout<<m_with_border<<endl; m_with_border=m_with_border.colRange(Range(1,m_with_border.cols-1)); cout<<m_with_border<<endl; } voidmain() { my_imfillholes_v2(); system("pause"); } |
先加一个全0的1-pixel的框,然后在findCountours填充,最后把框给去了。这样结果就完全和matlab中的imfill一致了。result= 1 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 1 1 1 0 1 1 0 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 0 1 1 0 1 1 1 0 0 0 0 0