OpenCV-16图像修复

       在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膨胀处理
void mainFun()
{
	Mat imageSource = imread("D:\\test\\imageRecover1.jpg");
	if (!imageSource.data)
	{
		return;
	}
	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();
}


//-----开始------
void COpenCVLearningDlg::OnBnClickedStartButton()
{
	mainFun();
}

效果:

       由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。

方法二、鼠标框选区域+阈值处理+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膨胀处理
void mainFun()
{
	imageSource = imread("D:\\test\\imageRecover1.jpg");
	if (!imageSource.data)
	{
		return ;
	}
	imshow("原图", imageSource);
	setMouseCallback("原图", OnMouse);
	waitKey();

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


//-----开始------
void COpenCVLearningDlg::OnBnClickedStartButton()
{
	mainFun();
}

效果:

      选定区域之外的图像不受修复影响,没有额外的损伤。

方法三、鼠标划定整个区域作为修复对象

代码:

#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 mainFun()
{
	imageSource = imread("D:\\test\\imageRecover2.jpg");
	if (!imageSource.data)
	{
		return -1;
	}
	imshow("原图", imageSource);
	setMouseCallback("原图", OnMouse);
	waitKey();
	return -1;
}

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

//-----开始------
void COpenCVLearningDlg::OnBnClickedStartButton()
{
	mainFun();
}

结果:

       这个方法选定一个矩形区域,把整个矩形区域作为要修复的对象,该方法适用于图像结构比较简单,特别是纯色图像,并且选定区域面积占比不大的情况,效果较好。

欢迎扫码关注我的微信公众号

 原文地址:https://blog.csdn.net/dcrmg/article/details/53792061

猜你喜欢

转载自blog.csdn.net/sxlsxl119/article/details/86478537
今日推荐