• OpenCV图像修复


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


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


    原始图像:


    图像复原结果:

  • 相关阅读:
    Linux ALSA音频库(一) 交叉编译 详细说明
    在KEIL下查看单片机编程内存使用情况
    Linux Socket
    QT报错随手记
    Cortex-M3双堆栈MSP和PSP+函数栈帧
    Linux命令
    cdev_alloc与cdev_init区别
    一些编译报错
    SFUD+FAL+EasyFlash典型场景需求分析,并记一次实操记录
    RTThread DFS文件系统使用: 基于使用SFUD驱动的SPI FLASH之上的ELM FATFS文件系统
  • 原文地址:https://www.cnblogs.com/lykbk/p/dfdfgfgdfgfgfgfgfgfgfgfgff.html
Copyright © 2020-2023  润新知