OpenCV4学习笔记(14)——图像修复

本次要记录的内容是:OpenCV中的图像修复函数inpaint(),以及OpenCV中的有关鼠标操作函数。

  • 图像修复函数
    首先是cv::inpaint()这个API,官方文档中的描述是:在图像中利用选取的区域邻域,来修复该区域。个人认为它的作用是:获取被选取区域的邻域的像素值,经过某种处理后,赋值给被选取区域,将被选取区域中原有的像素值覆盖掉,这就实现了修复图像中一些瑕疵的效果。

  • 鼠标操作函数
    OpenCV中的有关鼠标操作函数,主要是鼠标操作的回调函数static void on_Mouse(int event, int x, int y, int flag, void)*,以及控制是否执行回调函数的函数setMouseCallback("windowName", on_Mouse, 0)

在这里,将这两种操作结合起来,写成一个可以实时利用鼠标指定修复区域的函数。下面来整理一下具体的代码实现过程:

//分别定义:待修复的目标图像、需要修复的区域(掩膜)、进行修复的图像
Mat temp, inpainMask, inpain_image;
Point prePoint;				//定义鼠标指向的上一个点
static void on_Mouse(int event, int x, int y, int flag, void*);			//定义鼠标操作的回调函数
Mat image;			//定义原图像

 void image_inpaint(Mat inputsrc)
{
	image = inputsrc.clone();			//用于修复的原图像
	temp = image.clone();			   //在该目标图像上标识需要修复区域
	inpain_image = image.clone();			//执行inpaint操作的图像
	inpainMask = Mat::zeros(image.size(), CV_8UC1);					//用于inpaint的掩膜必须为单通道图
	imshow("待修复图像", temp);
	setMouseCallback("待修复图像", on_Mouse, 0);			
	while (true)			//循环接收用户指令
	{
		int ch = waitKey();
		switch (ch)
		{
		case 'a':
		{
			//当输入‘a’时执行opencv的第一种修复方法INPAINT_TELEA
			Mat inpaintedImage;
			inpaint(inpain_image, inpainMask, inpaintedImage, 3, INPAINT_TELEA);
			imshow("INPAINT_TELEA修复", inpaintedImage);
			break;
		}
		case 'b':
		{
			//当输入‘b’时执行opencv的第二种修复方法INPAINT_NS
			Mat inpaintedImage;
			inpaint(inpain_image, inpainMask, inpaintedImage, 3, INPAINT_NS);
			imshow("INPAINT_NS修复", inpaintedImage);
			break;
		}
		}
		if(ch == 27)
		{
			break;
		}
	}

}

static void on_Mouse(int event, int x, int y, int flag, void*)
{
	if (event == EVENT_LBUTTONDOWN)			//当鼠标左键按下,获取该点坐标
	{
		prePoint = Point(x, y);
	}
	//当鼠标左键保持按下标志,且鼠标移动
	else if (event == EVENT_MOUSEMOVE && (flag & EVENT_FLAG_LBUTTON))	
	{
		Point nowPoint(x, y);
		//以绘制的线段区域更新掩膜
		line(inpainMask, nowPoint, prePoint, Scalar(255), 2, LINE_AA, 0);		
		//在目标图像上更新绘制的需要修复区域
		line(temp, nowPoint, prePoint, Scalar(255, 255, 255), 2, LINE_AA, 0);
		prePoint = nowPoint;		//将鼠标的当前点作为上个点位,以开始下一个线段区域的绘制
		imshow("待修复图像", temp);			//在窗口更新目标图像
	}
	//当鼠标右键按下时
	else if (event == EVENT_RBUTTONDOWN)
	{
		temp = image.clone();			//重置目标图像,使之恢复为原图像
		inpainMask = Mat::zeros(image.size(), CV_8UC1);				//重置掩膜
		imshow("待修复图像", temp);			//在窗口更新目标图像
	}
}

通过setMouseCallback("待修复图像", on_Mouse, 0)来定义鼠标操作。第一个参数是指定窗口的窗口名称;第二个参数是要执行的回调函数;第三个参数是传入回调函数的用户数据,直接传入0。当鼠标位于该指定窗口上时,执行回调函数。
定义鼠标回调函数static void on_Mouse(int event, int x, int y, int flag, void*),其中第一个参数是鼠标产生的事件,第二和第三个参数是鼠标指向的点,第四个参数可以为理解是鼠标的状态,第五个参数是执行回调函数时传入的数据,只是一个空指针。
event == EVENT_LBUTTONDOWN时,表示鼠标按下了左键,就获取当前鼠标坐标位置,意味着用户打算从这个位置来选取修复区域;
event == EVENT_MOUSEMOVE && (flag & EVENT_FLAG_LBUTTON),表示鼠标事件是正在移动,且鼠标处于左键按下的状态,这时候就将获取到的鼠标指向点与上一个指向点之间绘制直线并以inpant操作的掩膜输出,并在窗口显示中绘制该直线,最后将当前点设为上个指向点,以便开始下一次绘制;
event == EVENT_RBUTTONDOWN,将显示的图像和要修复的图像重置。
定义完鼠标回调函数就可以在主函数中调用它,使用while循环来重复接收用户指令,根据不断更新的掩膜去调用inpaint()函数,实现图像修复。

inpaint(inpain_image, inpainMask, inpaintedImage, 3, INPAINT_TELEA)

这个函数第一个参数是要修复的图像,第二个参数是要修复的选取区域,第三个函数是输出的图像,第四个参数是要修复区域的半径大小,第五个参数是可选的修复方式,OpenCV提供了两种修复方式,在上述代码中可以通过输入“a“和”b“来选择查看效果。
下面可以看一下修复的效果:
原图:在这里插入图片描述
选择区域:在这里插入图片描述
两种修复方式的效果:在这里插入图片描述
在这里插入图片描述
太阳消失术:
在这里插入图片描述

好了本次整理到此结束,下次考虑换一下图片,不要一直用这只猫猫了哈哈哈,那是自己跑来宿舍的流浪猫,后来也不知道又跑哪儿去了。。。

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

发布了36 篇原创文章 · 获赞 43 · 访问量 1812

猜你喜欢

转载自blog.csdn.net/weixin_45224869/article/details/104615397
今日推荐