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 <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);
        }
    }
原始图像:


图像复原结果:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微笑点燃希望

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值