前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【OpenCV入门之八】如何看到某些被盖住的画面

【OpenCV入门之八】如何看到某些被盖住的画面

作者头像
小白学视觉
发布2019-05-29 16:38:19
9260
发布2019-05-29 16:38:19
举报

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

OpenCV真的有这个妙手回春的功能!别以为图像修补的工作只能用PS或者美图秀秀那些软件去做,其实由程序员自己写代码去做更加高效!

图像修复技术的原理是什么呢?

简而言之,就是利用那些已经被破坏的区域的边缘, 即边缘的颜色和结构,根据这些图像留下的信息去推断被破坏的信息区的信息内容,然后对破坏区进行填补 ,以达到图像修补的目的。

OpenCV中就是利用inpaint()这个函数来实现修复功能的。

void inpaint( InputArray src, InputArray inpaintMask,OutputArray dst, double inpaintRadius, int flags );
  • 第一个参数src,输入的单通道或三通道图像;
  • 第二个参数inpaintMask,图像的掩码,单通道图像,大小跟原图像一致,inpaintMask图像上除了需要修复的部分之外其他部分的像素值全部为0;
  • 第三个参数dst,输出的经过修复的图像;
  • 第四个参数inpaintRadius,修复算法取的邻域半径,用于计算当前像素点的差值;
  • 第五个参数flags,修复算法有两种:INPAINT_NSI NPAINT_TELEA

函数实现关键是图像掩码的确定,可以通过阈值筛选或者手工选定,按照这个思路,用三种方法生成掩码,对比图像修复的效果。

#include <imgproc\imgproc.hpp>
#include <highgui\highgui.hpp>
#include <photo\photo.hpp>

using namespace cv;

//全区域阈值处理+Mask膨胀处理
int main()
{
    Mat imageSource = imread("lol17.png");
    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();

下面就是修复效果,感觉很不错吧!不过仔细一看,感觉跟原图还是发生了一些差异,比如图中剑圣头上的那颗亮点,颜色发生了变化。这个就是修复后的副作用!毕竟作出了修复,付点代价还是要的。受损是由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。

有些图片可能就会修复得很好,比如以下这幅,你根本看不出哪里有明显的副作用。

是不是所有受损的图片都能较好地还原呢?那当然不是,有些图片受损太严重的,或者在某些复杂区域受损的,OpenCV也很难帮你修复过来。

比如以下这幅,因为受损有些区域在一些很复杂的位置,所以修复起来效果不怎么样。

上面提到其他无辜的而区域会受损,这个问题能解决一下吗?可以的,那就得自己定义一块需要修复的而区域,不需要修复的区域我们不动它就是了。

#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("lol17.png");
    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, Gray, 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);
    }
}

这种方法就需要我们人为地画出要修复的区域,这样就不会影响区域之外的图像了。

首先按住鼠标左键将待修复区域框出来。

然后对框出来的区域点击鼠标右键,就可以进行修复了。

修复的而效果确实比上面的方法要好!

总而言之,图像修复技术在一些简单,颜色单调的图像上进行修复得到的而效果是相当好的,而在一些细节或者复杂的部分进行修复,得到的复原图像的效果就比较一般了。比如在一些背景部分进行修复效果都不错,而在边缘细节上的修复就能看出问题了!

本文主要借鉴”Madcola“和”Micheal超“两位大神的文章。两位大神的博客主页是: https://www.cnblogs.com/skyfsm/(Madcola) https://blog.csdn.net/qq_42887760(Micheal超)

结束语

由于时间和文章篇幅有限,本次总结先到这里,下次小白会为小伙伴们带来OpenCV的轮廓查找和多边形包围轮廓,各位小伙伴敬请期待。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小白学视觉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档