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