当我们的照片有划痕或遭到人为的涂鸦(比如马赛克)时, 如果我们想让这些遭到破坏的图片尽可能恢复到原样,Opencv能帮我们做到吗?答案是肯定的。
那么图像修复技术的原理是什么呢?
简而言之,就是利用那些已经被破坏的区域的边缘, 即边缘的颜色和结构,根据这些图像留下的信息去推断被破坏的信息区的信息内容,然后对破坏区进行填补 ,以达到图像修补的目的。
OpenCV中就是利用inpaint()这个函数来实现修复功能的。
void inpaint( InputArray src, InputArray inpaintMask,
OutputArray dst, double inpaintRadius, int flags );
- 第一个参数src,输入的单通道或三通道图像;
- 第二个参数inpaintMask,图像的掩码,单通道图像,大小跟原图像一致,inpaintMask图像上除了需要修复的部分之外其他部分的像素值全部为0;
- 第三个参数dst,输出的经过修复的图像;
- 第四个参数inpaintRadius,修复算法取的邻域半径,用于计算当前像素点的差值;
- 第五个参数flags,修复算法,有两种:INPAINT_NS 和I NPAINT_TELEA;
#include<opencv2\opencv.hpp>
using namespace cv;
int main()
{
imshow("原图", imageSource);
Mat imageGray;
//转换为灰度图
cvtColor(imageSource, imageGray, CV_RGB2GRAY, 0);
imshow("gray", imageGray);
//通过阈值处理生成Mask
Mat imageMask = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));
imshow("imageMask", imageMask);
threshold(imageGray, imageMask, 240, 255, THRESH_BINARY);
//对Mask膨胀处理,增加Mask面积
Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imageMask, imageMask, Kernel);
//图像修复
inpaint(imageSource, imageMask, imageSource, 5, INPAINT_TELEA);
imshow("Mask", imageMask);
imshow("修复后", imageSource);
waitKey();
}
下面是修复效果,效果看上去很不错,但仔细一看 ,还是有些细节跟原图发生了差异,比如刀和头上那个亮点,这是因为生成掩模的时候这些区域的亮度和白色的叉痕亮度相近,所以也成为了被修复的的对象。
想要消除这些瑕疵,可设置ROI区域,只对ROI区域的图像形成掩模和修复,其它区域不动。
//图像修复
#include<opencv2\opencv.hpp>
using namespace cv;
void callback(int event, int x, int y, int flags, void* userdata);
Point ptL, ptR;
Mat src, srcCopy,ROI,gray;
int main()
{
src = imread("6.jpg");
if (src.empty())
{
printf("could not load image!");
return -1;
}
namedWindow("input");
imshow("input", src);
setMouseCallback("input", callback);
waitKey();
}
void callback(int event, int x, int y, int flags, void* userdata)
{
if (event == CV_EVENT_LBUTTONDOWN)
{
ptL = Point(x, y);
ptR = Point(x, y);
}
if (flags == CV_EVENT_FLAG_LBUTTON)
{
ptR = Point(x, y);
srcCopy = src.clone();
rectangle(srcCopy, ptL, ptR, Scalar(255, 0, 0),2);
imshow("srcCopy", srcCopy);
}
if (event == CV_EVENT_LBUTTONUP)
{
if (ptL!= ptR)
{
ROI = src(Rect(ptL, ptR));
imshow("ROI", ROI);
}
}
if (event == CV_EVENT_RBUTTONDOWN)
{
//灰度化
cvtColor(ROI, gray, CV_BGR2GRAY);
//通过阈值处理生成Mask
Mat imageMask = Mat(ROI.size(), CV_8UC1, Scalar::all(0));
threshold(gray, imageMask, 240, 255, THRESH_BINARY);
//对Mask膨胀处理,增加Mask面积
Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imageMask, imageMask, Kernel);
imshow("Mask", imageMask);
//图像修复
inpaint(ROI, imageMask, ROI, 5, INPAINT_TELEA);
imshow("修复后", src);
}
}
下面是修复效果,效果比上面好很多: