灰度图像孔洞填补C++实现

由于项目需要,需要对灰度图进行孔洞填补,在网上查找了一圈发现基本都是将灰度图二值化在通过漫水填充的方法来实现的(imfill)。但是由于我的灰度图中包含有重要信息,二值化会导致关键信息的丢失。没办法只有自己想了个笨办法解决。(一个数学、逻辑、编程都菜的扣jio的菜狗能想到办法并将之实现是件很不容易的事所以特此记录,代码里面n的初始值为1)

- 根据所得到的灰度图像特点,检测图像中每个像素点的灰度值,如果检测结果为“当前像素灰度值为0,而下一个像素值不为0”则将该点坐标存入DeleteHeadMinuend;
- 如果检测结果为“当前像素灰度值不为0,而下一个像素值为0”则将该点放入DeleteEndSubtraction;
- 去除DeleteHeadMinuend中的首个元素;
- 去除DeleteEndSubtraction中最后一个元素;
- 然后以DeleteEndSubtraction和DeleteHeadMinuend数组中对应位置的元素区间填补其中的点;
- 填补的点的像素值与其前一个点的像素值相同;
/*************************************************************************************/
		for (int x = 0; x < Dst.rows; x++)
		{
			for (int y = 0; y < Dst.cols; y++)
			{
				if (Dst.ptr<uchar>(x)[y]!=0 && Dst.ptr<uchar>(x)[y+1] ==0)
				{
					DeleteEndSubtraction.push_back(Point2d(x, y));
				}
				if (Dst.ptr<uchar>(x)[y] == 0 && Dst.ptr<uchar>(x)[y+1] != 0)
				{
					DeleteHeadMinuend.push_back(Point2d(x, y));
				}
			}
		}
		if (DeleteEndSubtraction.size()>1 && DeleteHeadMinuend.size()>1)
		{
			//将包含在对应区域内的像素点进行填充
			for (int m = 0; m < DeleteEndSubtraction.size()-1; m++)
			{	
				if (DeleteHeadMinuend[n].y-DeleteEndSubtraction[m].y<=8)
				{
					for (int Y = DeleteEndSubtraction[m].y; Y <= DeleteHeadMinuend[n].y; Y++)
					{
						Dst.ptr<uchar>(DeleteEndSubtraction[m].x)[Y] = Dst.ptr<uchar>(DeleteEndSubtraction[m].x)[Y - 1];
					}
				}
					n++;
			}
		}

实验效果:

### 如何使用 C++ 和 OpenCV 实现图像孔洞填充 #### 孔洞填充的概念 在计算机视觉领域,孔洞是指二值化后的前景对象内部存在的黑色区域。这些孔洞可能会影响后续的分析工作,因此通常需要对其进行填充。 #### 方法一:利用形态学操作 通过膨胀和腐蚀的操作组合来实现孔洞填充是一种常见的方式。这种方法的核心在于先找到背景部分并将其标记出来,再用这个标记图去指导最终的修复过程[^1]。 对于C++编程环境下的OpenCV库来说,可以采用如下策略: - 将输入图片转换成灰度模式; - 对原图做阈值分割得到二值化的结果; - 创建一个新的掩膜用于保存临时数据; - 找到最外层轮廓并将该位置设置为白色像素点作为种子点; - 应用`floodFill()`函数从指定的位置开始向四周扩散直到遇到边界为止; - 反转上述获得的结果并与原始二值图相减即完成整个流程; 下面是具体的代码示例: ```cpp #include <opencv2/opencv.hpp> using namespace cv; Mat fillHoles(const Mat& inputImage){ // Copy the thresholded image. Mat imFloodfill = inputImage.clone(); // Mask used to flood filling. // Notice the size needs to be 2 pixels than the image. Mat mask(inputImage.rows + 2, inputImage.cols + 2, CV_8UC1, Scalar(0)); // Floodfill from point (0, 0). floodFill(imFloodfill, mask, Point(0,0), Scalar(255)); // Invert floodfilled image bitwise_not(imFloodfill, imFloodfill); // Combine the two images to get the foreground. Mat filledImg; add(inputImage, imFloodfill, filledImg); return filledImg; } ``` 这段程序实现了基本的功能需求——给定一张已经过预处理(比如边缘检测之后)的二值图像,返回经过孔洞填补的新版本。 #### 方法二:基于连通域分析 另一种思路是从连通分量的角度出发解决问题。具体做法是遍历每一个非零元素所在的连通区,并判断其是否位于物体外部还是内部。如果是后者,则保持不变;反之则设为最大亮度值表示被填满的状态。此法适用于更复杂的场景下精确控制哪些特定类型的空隙应该保留下来而不受影响[^3]。 以上两种方案各有优劣,在实际项目开发过程中可以根据具体情况灵活选用合适的算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值