opencv实现二值图像孔洞填充
Posted matlab和opencv数字图像处理笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv实现二值图像孔洞填充相关的知识,希望对你有一定的参考价值。
matlab中的imfill函数可以方便得实现二值图像的孔洞填充,而在opencv中并没有相同功能的函数。因此,在opencv的基础上编写实现孔洞填充的函数,并且能够设定阈值,对面积大于阈值的孔洞不进行填充。使用形态学重建的算法能够有效地实现孔洞填充,具体算法原理参照《数字图像处理》第三版9.5.9节,孔洞填充。
主要实现代码如下所示:其中imfill函数即为空洞填充的实现函数,第一个参数是二值图像(0~1),第二个参数是填充孔洞的阈值。若孔洞面积大于阈值则不填充,反之则填充。
#include "iostream"
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
Mat inv_board(Mat src);
Mat inv_img(Mat src);
void delarea(Mat& bw, int max);
Mat imfill(Mat I, int max);
void main()
{
Mat scr = imread("2.png");
Mat I, src_gray, F_B, F_BI_C, temp, H, I_fill;
cvtColor(scr, src_gray, COLOR_BGR2GRAY);
threshold(src_gray, I, 0.1, 1,0);
I_fill = imfill(I,40);
imshow("原二值图", I * 255);
imshow("填充图", I_fill*255);
waitKey(0);
}
Mat imfill(Mat I,int max)
{
Mat src_gray, F_B, F_BI_C, temp, H, I_fill;
I_fill = I.clone();
Mat F = inv_board(I);
Mat I_C = inv_img(I);
Mat element = getStructuringElement(0, Size(3, 3), Point(1, 1));
while (1)
{
dilate(F, F_B, element);
F_BI_C = F_B.mul(I_C);
temp = F_BI_C - F;
if (sum(temp) == Scalar(0))
break;
else
F = F_BI_C.clone();
}
H = inv_img(F_BI_C);
Mat H_IC = H.mul(I_C);
delarea(H_IC, max);
for (int i = 0; i < H_IC.rows; i++)
{
for (int j = 0; j < H_IC.cols; j++)
{
if (H_IC.at<uchar>(i, j) == 1)
I_fill.at<uchar>(i, j) = 1;
}
}
return I_fill;
}
Mat inv_board(Mat src)
{
int rows = src.rows;
int cols = src.cols;
Mat dst = Mat::zeros(rows, cols, CV_8UC1);
for (int i = 0; i < cols; i++)
{
dst.at<uchar>(0, i) = 1 - src.at<uchar>(0, i);
}
for (int i = 0; i < cols; i++)
{
dst.at<uchar>(rows-1, i) = 1 - src.at<uchar>(rows - 1, i);
}
for (int i = 1; i < rows-1; i++)
{
dst.at<uchar>(i, 0) = 1 - src.at<uchar>(i, 0);
}
for (int i = 1; i < rows - 1; i++)
{
dst.at<uchar>(i, cols-1) = 1 - src.at<uchar>(i, cols-1);
}
return dst;
}
Mat inv_img(Mat src)
{
int rows = src.rows;
int cols = src.cols;
Mat dst = src.clone();
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
dst.at<uchar>(i, j) = 1 - src.at<uchar>(i, j);
return dst;
}
void delarea(Mat& bw, int max )
{
Mat bw_copy = bw.clone();
int flag = 0;
Mat H_b, H_bw, temp;
Mat H = Mat::zeros(bw.size(), bw.type());
for (int i = 0; i < bw.rows; i++)
{
for (int j = 0; j < bw.cols; j++)
{
if (bw_copy.at<uchar>(i, j) == 1)
{
H.at<uchar>(i, j) = 1;
Mat element = getStructuringElement(0, Size(3, 3), Point(1, 1));
while (1)
{
dilate(H, H_b, element);
H_bw = H_b.mul(bw);
temp = H_bw - H;
if (sum(temp) == Scalar(0))
break;
else
H = H_bw.clone();
}
bw_copy = bw_copy - H_bw;
if (sum(H_bw).val[0] > max)
{
bw = bw - H_bw;
}
H = Mat::zeros(bw.size(), bw.type());
}
}
}
}
效果图如下:
以上是关于opencv实现二值图像孔洞填充的主要内容,如果未能解决你的问题,请参考以下文章