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

无意中看到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_TEELEA A了先倒入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的那篇)

在opencv中实现修复有两种算法,这里介绍Telea的算法,即基于快速行进(FMM)的修复算法。

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

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

现在假设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 
#include 
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;
}






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

Opencv之实现图像修复intpaint()函数_第1张图片


三、资料参考

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

2.Opencv编程入门  作者:浅墨


你可能感兴趣的:(Opencv常用函数介绍)