编程实验
OpenCV真的有这个妙手回春的功能!别以为图像修补的工作只能用PS或者美图秀秀那些软件去做,其实由程序员自己写代码去做更加高效!
图像修复技术的原理是什么呢?
简而言之,就是利用那些已经被破坏的区域的边缘, 即边缘的颜色和结构,根据这些图像留下的信息去推断被破坏的信息区的信息内容,然后对破坏区进行填补 ,以达到图像修补的目的。
在OpenCV的“photo.hpp”中定义了一个inpaint函数,可以用来实现图像的修复和复原功能,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;
函数实现关键是图像掩码的确定,可以通过阈值筛选或者手工选定,按照这个思路,用三种方法生成掩码,对比图像修复的效果。
[cpp] view plain copy print?
#include 《imgprocimgproc.hpp》
#include 《highguihighgui.hpp》
#include 《photophoto.hpp》
using namespace cv;
//全区域阈值处理+Mask膨胀处理
int main()
{
Mat imageSource = imread(“Test.jpg”);
if (!imageSource.data)
{
return -1;
}
imshow(“原图”, imageSource);
Mat imageGray;
//转换为灰度图
cvtColor(imageSource, imageGray, CV_RGB2GRAY, 0);
Mat imageMask = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));
//通过阈值处理生成Mask
threshold(imageGray, imageMask, 240, 255, CV_THRESH_BINARY);
Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
//对Mask膨胀处理,增加Mask面积
dilate(imageMask, imageMask, Kernel);
//图像修复
inpaint(imageSource, imageMask, imageSource, 5, INPAINT_TELEA);
imshow(“Mask”, imageMask);
imshow(“修复后”, imageSource);
waitKey();
}
原始图像:
根据阈值处理得到的图像掩码:
图像复原结果:
由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。
[cpp] view plain copy print?
#include 《imgproc/imgproc.hpp》
#include 《highgui/highgui.hpp》
#include 《core/core.hpp》
#include 《photo/photo.hpp》
using namespace cv;
Point ptL, ptR; //鼠标画出矩形框的起点和终点
Mat imageSource, imageSourceCopy;
Mat ROI; //原图需要修复区域的ROI
//鼠标回调函数
void OnMouse(int event, int x, int y, int flag, void *ustg);
//鼠标圈定区域阈值处理+Mask膨胀处理
int main()
{
imageSource = imread(“Test.jpg”);
if (!imageSource.data)
{
return -1;
}
imshow(“原图”, imageSource);
setMouseCallback(“原图”, OnMouse);
waitKey();
}
void OnMouse(int event, int x, int y, int flag, void *ustg)
{
if (event == CV_EVENT_LBUTTONDOWN)
{
ptL = Point(x, y);
ptR = Point(x, y);
}
if (flag == CV_EVENT_FLAG_LBUTTON)
{
ptR = Point(x, y);
imageSourceCopy = imageSource.clone();
rectangle(imageSourceCopy, ptL, ptR, Scalar(255, 0, 0));
imshow(“原图”, imageSourceCopy);
}
if (event == CV_EVENT_LBUTTONUP)
{
if (ptL != ptR)
{
ROI = imageSource(Rect(ptL, ptR));
imshow(“ROI”, ROI);
waitKey();
}
}
//单击鼠标右键开始图像修复
if (event == CV_EVENT_RBUTTONDOWN)
{
imageSourceCopy = ROI.clone();
Mat imageGray;
cvtColor(ROI, imageGray, CV_RGB2GRAY); //转换为灰度图
Mat imageMask = Mat(ROI.size(), CV_8UC1, Scalar::all(0));
//通过阈值处理生成Mask
threshold(imageGray, imageMask, 235, 255, CV_THRESH_BINARY);
Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imageMask, imageMask, Kernel); //对Mask膨胀处理
inpaint(ROI, imageMask, ROI, 9, INPAINT_TELEA); //图像修复
imshow(“Mask”, imageMask);
imshow(“修复后”, imageSource);
}
}
鼠标圈定的ROI:
图像复原结果:
选定区域之外的图像不受修复影响,没有额外的损伤。
这个方法选定一个矩形区域,把整个矩形区域作为要修复的对象,该方法适用于图像结构比较简单,特别是纯色图像,并且选定区域面积占比不大的情况,效果较好。
[cpp] view plain copy print?
#include 《imgproc/imgproc.hpp》
#include 《highgui/highgui.hpp》
#include 《core/core.hpp》
#include 《photo/photo.hpp》
using namespace cv;
Point ptL, ptR; //鼠标画出矩形框的起点和终点
Mat imageSource, imageSourceCopy;
Mat ROI; //原图需要修复区域的ROI
//鼠标回调函数
void OnMouse(int event, int x, int y, int flag, void *ustg);
//鼠标圈定区域
int main()
{
imageSource = imread(“Test.jpg”);
if (!imageSource.data)
{
return -1;
}
imshow(“原图”, imageSource);
setMouseCallback(“原图”, OnMouse);
waitKey();
}
void OnMouse(int event, int x, int y, int flag, void *ustg)
{
if (event == CV_EVENT_LBUTTONDOWN)
{
ptL = Point(x, y);
ptR = Point(x, y);
}
if (flag == CV_EVENT_FLAG_LBUTTON)
{
ptR = Point(x, y);
imageSourceCopy = imageSource.clone();
rectangle(imageSourceCopy, ptL, ptR, Scalar(255, 0, 0));
imshow(“原图”, imageSourceCopy);
}
if (event == CV_EVENT_LBUTTONUP)
{
if (ptL != ptR)
{
ROI = imageSource(Rect(ptL, ptR));
imshow(“ROI”, ROI);
waitKey();
}
}
//单击鼠标右键开始图像修复
if (event == CV_EVENT_RBUTTONDOWN)
{
imageSourceCopy = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));
Mat imageMask = imageSourceCopy(Rect(ptL, ptR));
//生成一个跟ROI大小一样的值全为1的区域
Mat imageMaskCopy = Mat(imageMask.size(), CV_8UC1, Scalar::all(1));
imageMaskCopy.copyTo(imageMask);
inpaint(imageSource, imageSourceCopy, imageSource, 9, INPAINT_TELEA); //图像修复
imshow(“Mask”, imageSourceCopy);
imshow(“修复后”, imageSource);
}
}
原始图像:
图像复原结果:
全部0条评论
快来发表一下你的评论吧 !