在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膨胀处理

#include <imgproc\imgproc.hpp>
#include <highgui\highgui.hpp>
#include <photo\photo.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膨胀处理

#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:

图像复原结果:

选定区域之外的图像不受修复影响,没有额外的损伤。


方法三、鼠标划定整个区域作为修复对象

这个方法选定一个矩形区域,把整个矩形区域作为要修复的对象,该方法适用于图像结构比较简单,特别是纯色图像,并且选定区域面积占比不大的情况,效果较好。

#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);
}
}

原始图像:

图像复原结果:

OpenCV图像修复的更多相关文章

  1. opencv 图像修复函数

    void cv::inpaint( const Mat& src, const Mat& mask, Mat& dst, double inpaintRange, int fl ...

  2. OpenCV探索之路(十):图像修复技术

    在实际应用中,我们的图像常常会被噪声腐蚀,这些噪声或是镜头上的灰尘或水滴,或是旧照片的划痕,或者是图像遭到人为的涂画(比如马赛克)或者图像的部分本身已经损坏.如果我们想让这些受到破坏的额图片尽可能恢复 ...

  3. OpenCV学习2-----使用inpaint函数进行图像修复

    安装opencv时,在opencv的安装路径下, sources\samples\cpp\  路径里面提供了好多经典的例子,很值得学习. 这次的例子是利用inpaint函数进行图像修复. CV_EXP ...

  4. OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    这篇已经写得很好,真心给作者点个赞.题目都是直接转过来的,直接去看吧. Reference Link : http://blog.csdn.net/poem_qianmo/article/detail ...

  5. 【OpenCV新手教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...

  6. Opencv 图像叠加 添加水印

    Opencv 图像叠加 添加水印 C++: void Mat::copyTo(OutputArray m) const C++: void Mat::copyTo(OutputArray m, Inp ...

  7. opencv图像读取-imread

    前言 图像的读取和保存一定要注意imread函数的各个参数及其意义,尽量不要使用默认参数,否则就像数据格式出现错误(here)一样,很难查找错误原因的: re: 1.opencv图像的读取与保存; 完

  8. 学习 opencv---(12)OpenCV 图像金字塔:高斯金字塔,拉普拉斯金字塔与图片尺寸缩放

    在这篇文章里,我们一起学习下 图像金字塔 的一些基本概念,如何使用OpenCV函数pyrUp和pyrDown 对图像进行向上和向下采样,以及了解专门用于缩放图像尺寸的resize函数的用法.此博文一共 ...

  9. [OpenCV Qt教程] 在Qt图形界面中显示OpenCV图像的OpenGL Widget(第二部分)

    本文译自:http://www.robot-home.it/blog/en/software/tutorial-opencv-qt-opengl-widget-per-visualizzare-imm ...

随机推荐

  1. Oracle以系统管理员的方式登录失败

    解决方法: 因为SYS是在数据库之外的超级管理员,所以我们在登录的时候输入sys后在输入命令:password as sysdba 就可以!例如:输入口令: m1234 as sysdba 参考文章 ...

  2. php面试题二--解决网站大流量高并发方案(从url到硬盘来解决高并发方案总结)

    php面试题二--解决网站大流量高并发方案(从url到硬盘来解决高并发方案总结) 一.总结 从外到内解决网站大流量高并发问题---从提交一个url开始(从用户按下搜索栏回车键开始) url最开始会到d ...

  3. [转载]Surging教学视频资源汇总

    surging是什么 surging 是一个分布式微服务框架,提供高性能RPC远程服务调用,采用Zookeeper.Consul作为surging服务的注册中心,集成了哈希,随机,轮询.压力最小优先作 ...

  4. xv6 gdb

    The "remote" target does not support "run". https://sourceware.org/gdb/onlinedoc ...

  5. .NET-架构优化实战-底层服务优化

    原文:.NET-架构优化实战-底层服务优化 前言 问题分析 在本系列第一篇文章我们提到,底层问题主要存在以下两点: 代码冗余 时效低 代码冗余 例如: 领奖方法不统一,一次性的写一套,可循环的又写一套 ...

  6. 《Kinect应用开发实战》读书笔记---干货集合

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接: http://blog.csdn.net/cartzhang/article/details/45029841 作者:ca ...

  7. 解决ThinkPad x1 发热的问题

    F1进入BIOS界面 将intel speedstep设置为禁用 将CPU Power Manager设置为禁用 重启电脑 电脑不再发热

  8. 5.3.3.1 deque其他使用方式

    在本节里提供了一些关于deque其他使用方式. 提供相似UNIX中的命令tail的功能,显示一个文件最后面一段文本: def tail(filename, n=10): '返回文件最后的n行文本' w ...

  9. Mac下新安装的MySQL无法登陆root用户(安装时没有设置密码)

    1.也不知是何原因,新安装好的MySQL,如果尝试用mysql -u root -p登陆就会出现这样的错误,但是root用户根本就没有设置密码. $ cd /usr/local$ cd mysql $ ...

  10. activity-alias详解及应用

    activity-alias标签元素众所周知,AndroidManifest是一个xml文件,它包含很多标签元素,如application.activity.receiver等,其中有一个叫做acti ...