OpenCV圖像修復

RapHqi 8年前發布 | 44K 次閱讀 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);
    }
}

原始圖像:

圖像復原結果:

 

來自:http://blog.csdn.net/dcrmg/article/details/53792061

 

 本文由用戶 RapHqi 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!