1. 程式人生 > >opencv學習筆記七十一:影象修復

opencv學習筆記七十一:影象修復

當我們的照片有劃痕或遭到人為的塗鴉(比如馬賽克)時, 如果我們想讓這些遭到破壞的圖片儘可能恢復到原樣,Opencv能幫我們做到嗎?答案是肯定的。

那麼影象修復技術的原理是什麼呢?

簡而言之,就是利用那些已經被破壞的區域的邊緣, 即邊緣的顏色和結構,根據這些影象留下的資訊去推斷被破壞的資訊區的資訊內容,然後對破壞區進行填補 ,以達到影象修補的目的。

OpenCV中就是利用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;

#include<opencv2\opencv.hpp>
using namespace cv;
int main()
{
    imshow("原圖", imageSource);
    Mat imageGray;

    //轉換為灰度圖
    cvtColor(imageSource, imageGray, CV_RGB2GRAY, 0);
    imshow("gray", imageGray);

    //通過閾值處理生成Mask
    Mat imageMask = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));
    imshow("imageMask", imageMask);
    threshold(imageGray, imageMask, 240, 255, THRESH_BINARY);

    //對Mask膨脹處理,增加Mask面積
    Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));   
    dilate(imageMask, imageMask, Kernel);

    //影象修復
    inpaint(imageSource, imageMask, imageSource, 5, INPAINT_TELEA);
    imshow("Mask", imageMask);
    imshow("修復後", imageSource);
    waitKey();
}

下面是修復效果,效果看上去很不錯,但仔細一看 ,還是有些細節跟原圖發生了差異,比如刀和頭上那個亮點,這是因為生成掩模的時候這些區域的亮度和白色的叉痕亮度相近,所以也成為了被修復的的物件。

想要消除這些差異,可設定ROI區域,只對ROI區域的影象形成掩模和修復,其它區域不動。

//影象修復
#include<opencv2\opencv.hpp>
using namespace cv;
void callback(int event, int x, int y, int flags, void* userdata);
Point ptL, ptR;
Mat src, srcCopy,ROI,gray;
int main()
{
	src = imread("6.jpg");
	if (src.empty()) 
	{
		printf("could not load image!");
		return -1;
	}
	namedWindow("input");
	imshow("input", src);
	
	setMouseCallback("input", callback);
	waitKey();
}
void callback(int event, int x, int y, int flags, void* userdata)
{
	if (event == CV_EVENT_LBUTTONDOWN)
	{
		 ptL = Point(x, y);
		 ptR = Point(x, y);
	}
	if (flags == CV_EVENT_FLAG_LBUTTON)
	{
		ptR = Point(x, y);
		srcCopy = src.clone();
		rectangle(srcCopy, ptL, ptR, Scalar(255, 0, 0),2);
		imshow("srcCopy", srcCopy);
	}
	if (event == CV_EVENT_LBUTTONUP)
	{
		if (ptL!= ptR)
		{
			ROI = src(Rect(ptL, ptR));
			imshow("ROI", ROI);
		}
	}
	if (event == CV_EVENT_RBUTTONDOWN)
	{
                //灰度化
		cvtColor(ROI, gray, CV_BGR2GRAY);

                //通過閾值處理生成Mask
		Mat imageMask = Mat(ROI.size(), CV_8UC1, Scalar::all(0));
		threshold(gray, imageMask, 240, 255, THRESH_BINARY);

                //對Mask膨脹處理,增加Mask面積
		Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
		dilate(imageMask, imageMask, Kernel);
		imshow("Mask", imageMask);

		//影象修復
		inpaint(ROI, imageMask, ROI, 5, INPAINT_TELEA);
		imshow("修復後", src);
	}
}

下面是修復效果,效果比上面好很多: