OpenCV图像修复
Published on 2022-06-21 09:38 in 分类: opencv with 萧海~
分类: opencv

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

    原始图像:
    在这里插入图片描述
    图像复原结果:
    在这里插入图片描述
    原文:https://blog.csdn.net/dcrmg/article/details/53792061

    posted @   萧海~  阅读(325)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 全程不用写代码,我用AI程序员写了一个飞机大战
    · DeepSeek 开源周回顾「GitHub 热点速览」
    · 记一次.NET内存居高不下排查解决与启示
    · MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
    · .NET10 - 预览版1新功能体验(一)
    点击右上角即可分享
    微信分享提示
    电磁波切换