您的位置:首页 > 大数据 > 人工智能

Opencv之实现图像修复intpaint()函数

2016-09-17 16:56 441 查看
无意中看到inpaint()这个函数,它具有图像修复功能,这个应该很有趣,故查找了相关资料,整理好并呈现在这里。

一、inpaint()函数介绍

void inpaint( const Mat& src, const Mat& inpaintMask,
Mat& dst, double inpaintRange, int flags );
第一个参数InputArray类型的src,为8位单通道或者三通道图像的输入图像(要修复的图像);
第二个参数inpaintMask为修复掩膜,为8位单通道图像,其中非零像素表示要修补的区域;
第三个参数为dst,该函数的输出结果就放在这里,它和src图像类型是一样的;
第四个参数是double类型的inpaintRadius,需要修复点的附近的圆形区域,该值为修复区域的半径;
最后一个参数是int型的flags,为修补方法的标识符,两种修饰方法见下表:

标识符说明
INPAINT_NS基于Navier-Stokes方法
INPAINT_TEELEAA了先倒入Telea方法
CV_INPAINT_NS - 基于Navier-Stokes的方法。

比较难懂,贴个链接:

http://wenku.baidu.com/link?url=aut0V0I8ngmDiQOl6uvjZqAukhfAYeiF38C2-EMS8NScb5VKB3ZMBTpicbO7hU_22yP7zcH2Lz9PDVQrzOYWIthrLWBqYNRAvHCuSZqD6qa

CV_INPAINT_TELEA - Alexandru Telea[Telea04]的方法。

Telea在2004年提出的基于快速行进的修复算法(后面简称FMM算法)。

论文题目:An Image Inpainting Technique Based on the Fast Marching Method (2004)

作者主页:http://www.cs.rug.nl/~alext/

论文下载: http://www.cs.rug.nl/~alext/PAPERS/index.html (编号36的那篇)
[align=left]在opencv中实现修复有两种算法,这里介绍Telea的算法,即基于快速行进(FMM)的修复算法。[/align]

一、先说一下如何修复一个像素点的。





参考上图,Ω区域是待修复的区域;δΩ指Ω的边界);要修复Ω中的像素,就需要计算出新的像素值来代替原值。

现在假设p点是我们要修复的像素。以p为中心选取一个小邻域B(ε),该邻域中的点像素值都是已知的(只要已知的)。(这个ε就是opencv函数中参数 inpaintRadius)

显然,我们需要的是用邻域Bε(p)中的所有点计算p点的新灰度值。显然,各个像素点所起的作用应该是不同的,也就引入了权值函数来决定哪些像素的值对新像素值影响更大,哪些比较小。采用下面的公式(公式2):

 



这里的w(p, q)就是权值函数,是用来限定邻域中各像素的贡献大小的。

 w(p, q) = dir(p, q) · dst(p, q) · lev(p, q)

 



其中,d0和 T0分别为距离参数和水平集参数,一般都取为 1。方向因子 dir(p,q)保证了越靠近法线方向 N =  ?T的像素点对 p 点的贡献最大;几何距离因子 dst(p,q)保证了离 p 点越近的像素点对p 点贡献越大;水平集距离因子lev(p,q)保证了离经过点 p 的待修复区域的轮廓线越近的已知像素点对点 p 的贡献越大。

二、测试小程序

到底哪种方法更好呢?既然两种方法都收集到opencv库函数里,我认为它们难分仲伯。

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

#define WINDOW_NAME1 "原始图"
#define WINDOW_NAME2 "修补方法:_TELEA"
#define WINDOW_NAME3 "修补方法:_NS"

Mat srcImage, srcImage1, inpaintMask;
Point previousPoint;//原来的点坐标

static void On_Mouse(int event, int x, int y, int flags, void*)
{
if (event == EVENT_LBUTTONDOWN)
previousPoint = Point(x, y);

else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
{
Point pt(x, y);
line(inpaintMask, previousPoint, pt, Scalar::all(255), 5, 8, 0);//单通道掩膜,需要修复的像素此时为白色
line(srcImage, previousPoint, pt, Scalar::all(255), 5, 8, 0);
previousPoint = pt;
imshow(WINDOW_NAME1, srcImage);
}
}
int main()
{
srcImage = imread("D:\\vvoo\\baboon.jpg", 1);//三通道彩色图像
if (!srcImage.data)
{
cout << "读取图片错误,请确定目录下是否有imread函数指定图片存在~!" << endl;
return false;
}
inpaintMask = Mat::zeros(srcImage.size(), CV_8UC1);
imshow(WINDOW_NAME1, srcImage);

//设置鼠标回调消息
setMouseCallback(WINDOW_NAME1, On_Mouse, 0);

while (1)
{
int key = waitKey(10);
switch (key)
{

case 'a':
{
Mat inpaintedImage;
inpaint(srcImage, inpaintMask, inpaintedImage, 3, INPAINT_TELEA);
imshow(WINDOW_NAME2, inpaintedImage);
}
break;
case 'b':
{
Mat inpaintedImage;
inpaint(srcImage, inpaintMask, inpaintedImage, 3, INPAINT_NS);
imshow(WINDOW_NAME3, inpaintedImage);
}
break;
}
if (key == 27)
break;
}

waitKey(0);
return 0;
}


结果:没看出来哪个好,可能选的图片不适合



三、资料参考

1.http://blog.csdn.net/sunboyiris/article/details/23554351?utm_source=tuicool&utm_medium=referral

2.Opencv编程入门  作者:浅墨
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  inpaint 图像修复