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());
			}
			
		}
	}
}


猜你喜欢

转载自blog.csdn.net/jkjj2015/article/details/80037174