其实主要是imfill(matrix, 'holes'); 的openCV/C++ 实现。


Overview:


imfill是matlab的一个函数,在http://www.mathworks.cn/cn/help/images/ref/imfill.html 中有详细的讲解。这个函数有好几种不同的签名。在这里我的侧重点是imfill(m, 'holes'),以及如何用openCV来实现imfill一样的功能。本文有三部分组成。



1. 使用Matlab 的imfill 进行填充图像



在Matlab中简单的几行代码就能实现:

clc;          
 clear;          
 BW           =           im2bw(           imread(          'imfilltest.tif'));          
 imshow(BW);          
 holes           =           imfill(BW,           'holes');          

 BW(~holes)           =           1;           
 figure,imshow(holes);



左图为填充前的图像,右图是填充后的图像:



[原]imfill <wbr>的openCV实现

2. 用opencv来实现imfill(bw, 'holes')



opencv 在这里不像matlab那么好用了,matlab调用下。




#include            
#include            
#include            

using            namespace            std;           
using            namespace            cv;           

void            my_imfillholes(Mat            &src)           
 {           
                                     // detect external contours
                                    //
                                    vector            >            contours;           
                                     vector            hierarchy;           
                                     findContours(src,            contours,            hierarchy,            CV_RETR_EXTERNAL,            CV_CHAIN_APPROX_SIMPLE);           
                                     //
                                    // fill external contours
                                    //
                                    if(            !contours.empty()            &&            !hierarchy.empty()            )           
                                     {           
                                                                         for            (           int            idx=           0;idx            <            contours.size();idx++)           
                                                                         {           
                                                                                                             drawContours(src,contours,idx,Scalar::all(           255),CV_FILLED,           8);           
                                                                         }           
                                     }           
 }           

void            test_my_imfillholes()           
 {           
                                     Mat            m            =            imread(filltestName,IMREAD_GRAYSCALE);           
                                     //threshold, (i,j)>100 -->255
                                    Mat            th_m;           
                                     threshold(m,            th_m,            100,            255,            THRESH_BINARY);           
                                     my_imfillholes(th_m);           
                                     namedWindow(WinName,            CV_WINDOW_AUTOSIZE);           
                                     imshow(WinName,            th_m);           
                                     waitKey(           0);            
 }           

void            main()           
 {           
                                     test_my_imfillholes();           
                                     system(           "pause");           
 }


[原]imfill <wbr>的openCV实现




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 =
     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    



然后用第2部分所说的opencv的方法也试一下,结果发现是这样的:



without_holes =
     0     0     0     0     0     0     0     0
     0     1     1     0     1     1     0     0
     0     1     1     0     1     1     0     0
     0     1     1     0     1     1     1     0
     0     1     1     0     1     1     1     0
     0     1     1     0     1     1     1     0
     0     1     1     0     0     1     1     0
     0     0     0     0     0     0     0    



是不一样的。这个问题折腾了我一个晚上,终于,我在



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 account 1-pixel border



它的意思是,findCountours 是不会包含1-pixel的边界的。所以这就是为啥opencv计算的结果中边界的1都消失的原因。 我想,既然边界不被包含,那么我给它上下左右加一个1-pixel的框,这样边界点就变成了内部点,就能成功的用findCountours了。于是乎:我写了下面的code:




#include            
#include            
#include            

using            namespace            std;           
using            namespace            cv;           

void            my_imfillholes_v2()           
 {           
                                     //step 1: make a border
                                    Mat            m(           8,            8,            CV_8UC1,            data);           
                                     Mat            m_with_border;           
                                     copyMakeBorder(m,            m_with_border,            1,            1,            1,            1,            BORDER_CONSTANT,            Scalar());           
                                     cout<<m_with_border<<endl;           

                                     //setp 2: find the contour fill holes
                                    vector            >            contours;           
                                     vector            hierarchy;           
                                     findContours(m_with_border,            contours,            hierarchy,            CV_RETR_CCOMP,            CV_CHAIN_APPROX_NONE);           
                                     //
                                    // fill external contours
                                    // 
                                    if(            !contours.empty()            &&            !hierarchy.empty()            )           
                                     {           
                                                                         for            (           int            idx=           0;idx            <            contours.size();idx++)           
                                                                         {           
                                                                                                             drawContours(m_with_border,contours,idx,Scalar::all(           1),CV_FILLED,           8);           
                                                                         }           
                                     }           
                                     //cout<<m_with_border<<endl;
                                    //step 3: remove the border
                                    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;           
 }           

void            main()           
 {           
                                     my_imfillholes_v2();           
                                     system(           "pause");           
 }


先加一个全0的1-pixel的框,然后在findCountours填充,最后把框给去了。这样结果就完全和matlab中的imfill一致了。


result =
 
  
    1     1     1     0     0     0     0    
 
  
    1     1     1     0     1     1     0    
 
  
    1     1     1     0     1     1     0    
 
  
    1     1     1     0     1     1     1    
 
  
    1     1     1     0     1     1     1    
 
  
    1     1     1     0     1     1     1    
 
  
    1     1     1     0     0     1     1    
 
  
    1     1     1     0     0     0     0