zoukankan      html  css  js  c++  java
  • OpenCV探索之路(十):图像修复技术

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

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

    #include <imgprocimgproc.hpp>
    #include <highguihighgui.hpp>
    #include <photophoto.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);
        }
    }

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

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

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

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

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

  • 相关阅读:
    HDU 1102 Constructing Roads
    HDU 1285 确定比赛名次。
    最小生成树 HDU 各种畅通工程的题,prim和kru的模板题
    HDU Jungle Roads 1301 最小生成树、
    并查集小结(转)
    HDU hdu 2094 产生冠军 拓扑排序 判定环
    模运算(转)
    拓扑排序(主要是确定环和加法) HDU 2647 Reward
    HDU 1372 Knight Moves 简单BFS
    用计算机模型浅析人与人之间沟通方式 (一)如何谈话
  • 原文地址:https://www.cnblogs.com/xieyulin/p/7060910.html
Copyright © 2011-2022 走看看