加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

[原]imfill 的openCV实现

(2013-03-05 00:43:37)
标签:

it

分类: 图像处理/openCV
其实主要是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中简单的几行代码就能实现:
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);
左图为填充前的图像,右图是填充后的图像:
http://s1/mw690/79bb01d0td71c1b8a7590&690的openCV实现" TITLE="[原]imfill 的openCV实现" />

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 

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 imread(filltestName,IMREAD_GRAYSCALE);
   //threshold, (i,j)>100 -->255
   Mat th_m;
   threshold(m, th_m, 100255THRESH_BINARY);
   my_imfillholes(th_m);
   namedWindow(WinName, CV_WINDOW_AUTOSIZE);
   imshow(WinName, th_m);
   waitKey(0); 
}

void main()
{
   test_my_imfillholes();
   system("pause");
}
http://s5/bmiddle/79bb01d0td71c1c0fa824&690的openCV实现" TITLE="[原]imfill 的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 =
                          0
                          0
                          0
                          0
                          0
                          0
                          0
                          0
然后用第2部分所说的opencv的方法也试一下,结果发现是这样的:
without_holes =
                          0
     0                       0
                          0
     0                       0
                          0
                          0
                          0
                          0
是不一样的。这个问题折腾了我一个晚上,终于,我在
中的 findContours找到了这样的一个note:
Note:
Source image is modified by this function. Also, the function does not take into account 1-pixel border of the image (it’s filled with 0’s and used for neighbor analysis in the algorithm), therefore the contours 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 

using namespace std;
using namespace cv;

void my_imfillholes_v2()
{
   //step 1: make border
   Mat m(88CV_8UC1, data);
   Mat m_with_border;
   copyMakeBorder(m, m_with_border, 1111BORDER_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(1m_with_border.rows-1));
   //cout<<m_with_border<<endl;
   m_with_border m_with_border.colRange(Range(1m_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     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

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有