图像轮廓与图像分隔修复(9):图像修补

一,图像修补的概念认知;

二,实现图像修补:inpaint()函数;

三,综合示例程序:图像修补;

一,图像修补的概念认知

在实际应用中,我们的图像常常会被噪声腐蚀,这些噪声或者是镜头上的灰尘或水滴,或者是旧照片的划痕,或者由于图像的部分本身已经损坏。而“图像修复”( Inpainting),就是妙手回春,解决这些问题的良方。图像修复技术简单来说,就是利用那些已经被破坏区域的边缘,即边缘的颜色和结构,繁殖和混合到损坏的图像中,以达到图像修补的目的。图8.34~8.36就是示例程序截图,演示将图像中的字迹移除的效果。如图:

opencvsharp在印刷行业的应用 opencv inpaint_opencvsharp在印刷行业的应用


如果被破坏的区域不是太大,并且在被破坏区域边缘包含足够多的纹理和颜色,那么图像修补技术可以很好地恢复图像。当然,当图像损坏区域过大时,我们“妙手回春”的能力也是有限的。如图8.37、8.38所示。

opencvsharp在印刷行业的应用 opencv inpaint_opencv_02

二,实现图像修补:inpaint()函数

在新版OpenCV中,图像修补技术由 inpaint函数实现,它可以用来从扫描的照片中清除灰尘和划痕,或者从静态图像或视频中去除不需要的物体。其原型声明如下。

第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为8位单通道或者三通道图像。
第二个参数,InputArray类型的 inpaintMask,修复掩膜,为8位的单通道图像。其中的非零像素表示需要修补的区域。
第三个参数,OutputArray类型的 dst,函数调用后的运算结果存在这里,和源图片有一样的尺寸和类型。
第四个参数,double类型的inpaintRadius,需要修补的每个点的圆形邻域,为修复算法的参考半径。
第五个参数,int类型的flags,修补方法的标识符,可以是表8.4所示两者之一。

三,综合示例程序:图像修补

函数和概念讲解完毕,下面我们依然是学习一个以本节所讲内容为核心的示例程序,将本节所学内容付诸实践,融会贯通。此示例程序会先让我们在图像中用鼠标绘制出白色的线条破坏图像,然后按下键盘按键【1】或【SPACE】进行图像修补操作。且如果对自己的绘制不够满意,可以按下键盘按键【2】恢复原始图像。操作说明如图所示。

opencvsharp在印刷行业的应用 opencv inpaint_示例程序_03

代码如下:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/utils/logger.hpp>
#include "opencv2/photo/photo.hpp"
#include <iostream>
using namespace cv;
using namespace std;


//-----------------------------------【宏定义部分】-------------------------------------------- 
//  描述:定义一些辅助宏 
//----------------------------------------------------------------------------------------------
#define WINDOW_NAME0 "【原始图参考】"        //为窗口标题定义的宏 
#define WINDOW_NAME1 "【原始图】"        //为窗口标题定义的宏 
#define WINDOW_NAME2 "【修补后的效果图】"        //为窗口标题定义的宏 


//-----------------------------------【全局变量声明部分】--------------------------------------
//          描述:全局变量声明
//-----------------------------------------------------------------------------------------------
Mat srcImage0, srcImage1, inpaintMask;
Point previousPoint(-1, -1);//原来的点坐标


//-----------------------------------【ShowHelpText( )函数】----------------------------------
//          描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
	//输出欢迎信息和OpenCV版本
	printf("

			非常感谢购买《OpenCV3编程入门》一书!
");
	printf("

			此为本书OpenCV3版的第78个配套示例程序
");
	printf("

			   当前使用的OpenCV版本为:" CV_VERSION);
	printf("

  ----------------------------------------------------------------------------
");

	//输出一些帮助信息
	printf("


	欢迎来到【图像修复】示例程序~
");
	printf("
	请在进行图像修复操作之前,在【原始图】窗口中进行适量的绘制"
		"

	按键操作说明: 

"
		"		【鼠标左键】-在图像上绘制白色线条

"
		"		键盘按键【ESC】- 退出程序

"
		"		键盘按键【1】或【SPACE】-进行图像修复操作 

");
}


//-----------------------------------【On_Mouse( )函数】--------------------------------
//          描述:响应鼠标消息的回调函数
//----------------------------------------------------------------------------------------------
static void On_Mouse(int event, int x, int y, int flags, void*)
{
	//鼠标左键弹起消息
	if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
		previousPoint = Point(-1, -1);
	//鼠标左键按下消息
	else if (event == EVENT_LBUTTONDOWN)
		previousPoint = Point(x, y);
	//鼠标按下并移动,进行绘制
	else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
	{
		Point pt(x, y);
		if (previousPoint.x < 0)
			previousPoint = pt;
		//绘制白色线条
		line(inpaintMask, previousPoint, pt, Scalar::all(255), 5, 8, 0);
		line(srcImage1, previousPoint, pt, Scalar::all(255), 5, 8, 0);
		previousPoint = pt;
		imshow(WINDOW_NAME1, srcImage1);
	}
}


//--------------------------------------【main( )函数】-----------------------------------------
//          描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
	cv::utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//控制台不在输出日志文件

	//改变console字体颜色
	system("color 2F");

	//显示帮助文字
	ShowHelpText();

	//载入原始图并进行掩膜的初始化
	Mat srcImage = imread("E:/pictures/2.jpg", -1);
	if (!srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! 
"); return false; }
	srcImage0 = srcImage.clone();
	srcImage1 = srcImage.clone();
	inpaintMask = Mat::zeros(srcImage1.size(), CV_8U);

	//显示原始图参考
	imshow(WINDOW_NAME0, srcImage0);
	//显示原始图
	imshow(WINDOW_NAME1, srcImage1);
	//设置鼠标回调消息
	setMouseCallback(WINDOW_NAME1, On_Mouse, 0);

	//轮询按键,根据不同的按键进行处理
	while (1)
	{
		//获取按键键值
		char c = (char)waitKey();

		//键值为ESC,程序退出
		if (c == 27)
			break;

		//键值为2,恢复成原始图像
		if (c == '2')
		{
			inpaintMask = Scalar::all(0);
			srcImage.copyTo(srcImage1);
			imshow(WINDOW_NAME1, srcImage1);
		}

		//键值为1或者空格,进行图像修补操作
		if (c == '1' || c == ' ')
		{
			Mat inpaintedImage;
			inpaint(srcImage1, inpaintMask, inpaintedImage, 3, INPAINT_TELEA);
			imshow(WINDOW_NAME2, inpaintedImage);
		}
	}

	return 0;
}

运行截图:

opencvsharp在印刷行业的应用 opencv inpaint_示例程序_04


opencvsharp在印刷行业的应用 opencv inpaint_计算机视觉_05


opencvsharp在印刷行业的应用 opencv inpaint_opencv_06