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


原始圖像:

 

 


圖像復原結果:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM