前言
在实际应用中,我们的图像常常会被噪声腐蚀,这些噪声或是镜头上的灰尘或水滴,或是旧照片的划痕,或者是图像遭到人为的涂画(比如马赛克)或者图像的部分本身已经损坏。如果我们想让这些受到破坏的额图片尽可能恢复到原样,opencv能帮我们做到吗?
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;
函数实现关键是图像掩码的确定,可以通过阈值筛选或者手工选定,按照这个思路,用三种方法生成掩码,对比图像修复的效果。
方法一、全区域阈值处理+mask膨胀处理
[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();
}
原始图像:
根据阈值处理得到的图像掩码:
图像复原结果:
由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。
方法二、鼠标框选区域+阈值处理+mask膨胀处理
[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);
}
}
原始图像:
图像复原结果:
贴片编程的原始资料
CAN总线通讯中终端电阻的作用
产品数据分析报告如何撰写
反激式适配器同步整流芯片U7710SG简介
机械变阻器的控制器设计原理及控制命令
OpenCV图像修复
到底什么是BRAS?
如何使用Ubuntu Linux使其物联网平台更安全更快
3D打印迷你CNC绘图机设计
TE线对板高性能互连(HPI)连接器建立可靠、安全的连接
铲雪机器人的设计具有自动化、智能化的特点
嵌入式工程师去面试可能被问到的问题集锦
道路纵横断面测量的高效方法来了!
电力电容器的维护与运行管理技术
英特尔用软件优化技术来带动硬件性能的提升
中国新能源汽车市场出现40%左右的“断崖式”下滑
垃圾处理设备远程调试远程运维系统
Linux中如何开启端口
设计超酷!苹果全新Mac Pro概念图曝光:垃圾桶变盒子
浅析继电器原理的特性和工作原理与技术参数及其测试与应用