基于OpenCV的图像恢复

根据自适应滤波原理,设计一种可较好的保留底纹细节的自适应中值滤波器,对下图1进行恢复(5%椒盐噪声),要求达到图2的效果。
基于OpenCV的图像恢复_第1张图片
图1
基于OpenCV的图像恢复_第2张图片
图2

用visual studio 2012实现的代码如下:
特别注意的是,把要处理的图片放在工程目录下!!!
#include
#include
#include
#include
using namespace cv;
using namespace std;
#define WINDOW_NAME0 “原始图”
#define WINDOW_NAME1 “中值滤波图”
#define WINDOW_NAME2 “修补后的效果图”
Point previousPoint(-1,-1);
Mat picture,medianBlurImage,impaintMask;
static void On_Mouse(int event,int x,int y,int flage,void*);
int main(int argc,char** argv)
{
picture=imread(“2.jpg”);
if(!picture.data)
{
printf(“图片打开错误\n”);
return false;
}
namedWindow(WINDOW_NAME0);
imshow(WINDOW_NAME0,picture);
picture=picture.clone();
medianBlurImage=picture.clone();
impaintMask=Mat::zeros(medianBlurImage.size(),CV_8U);
medianBlur(picture,medianBlurImage,7);
imshow(WINDOW_NAME1,medianBlurImage);
setMouseCallback(WINDOW_NAME1,On_Mouse,0);
while(1)
{
char c=(char)waitKey();
if(c27)
{
break;
}
if(c
’1’)
{
Mat inpaintedImage;
inpaint(medianBlurImage , impaintMask , inpaintedImage ,3 ,CV_INPAINT_TELEA);
imshow(WINDOW_NAME2,inpaintedImage);
}
}
return 0;
}
static void On_Mouse(int event,int x,int y,int flages,void )
{
if(eventCV_EVENT_LBUTTONUP|| !(flages&CV_EVENT_FLAG_LBUTTON))
previousPoint=Point(-1,-1);
else if(event
CV_EVENT_LBUTTONDOWN)
previousPoint=Point(x,y);
else if(event==CV_EVENT_MOUSEMOVE&& (flages&CV_EVENT_FLAG_LBUTTON))
{
Point pt(x,y);
if(previousPoint.x<0)
previousPoint=pt;
line(impaintMask,previousPoint,pt,Scalar::all(255),5,8,0);
line(medianBlurImage, previousPoint, pt , Scalar::all(255),5,8,0);
previousPoint=pt;
imshow(WINDOW_NAME1,medianBlurImage);
}
}
达到的效果如下所示

2、进一步对10%的椒盐噪声的线条图像和5%椒盐噪声的lena图像进行处理,滤除噪声的同事保留良好的文理细节。
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
#define WINDOW_NEME0 “原始图”
#define WINDOW_NEME1 “中值滤波”
#define WINDOW_NEME2 “第一次修补后的图像”
#define WINDOW_NEME3 “第二次修补后的图像”
Mat srcImage, meduimBlurImage, inpaintMask;
Point previousPoint(-1, -1);
int minSize = 3; // 滤波器窗口的起始尺寸
int maxSize = 7; // 滤波器窗口的最大尺寸
static void On_Mouse( int event, int x, int y, int flags, void
);
uchar adaptiveProcess(const Mat &im, int row, int col, int kernelSize, int maxSize);
Mat FliterProcss(const Mat ime, void*);

int main( int args, char** argv)
{
srcImage = imread(“3(椒盐噪声5%).jpg”,0);
//srcImage = imread(“C:\Users\81051\Desktop\4(椒盐噪声10%).jpg”,0);
if(!srcImage.data)
{
printf(“读取图像错误!”);
return false;
}
imshow(WINDOW_NEME0,srcImage);

srcImage = FliterProcss(srcImage, 0);
imshow(WINDOW_NEME2, srcImage);
srcImage = FliterProcss(srcImage, 0);
srcImage = FliterProcss(srcImage, 0);
imshow(WINDOW_NEME3, srcImage);
waitKey();
return 0;

}
static void On_Mouse( int event, int x, int y, int flags, void*)
{
if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )
previousPoint == Point(-1, -1);
else if( event == CV_EVENT_LBUTTONDOWN )
previousPoint == Point(x, y);
else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))
{
Point pt(x,y);
if( previousPoint.x < 0 )
previousPoint = pt;
line( inpaintMask, previousPoint, pt, Scalar::all(255), 5);
line( meduimBlurImage, previousPoint, pt, Scalar::all(255), 5);
previousPoint = pt;
imshow(WINDOW_NEME1, meduimBlurImage);
}
}

Mat FliterProcss(const Mat ime, void*)
{
Mat border_Image, stmImage;

copyMakeBorder(srcImage, border_Image, maxSize/2, maxSize/2, maxSize/2, maxSize/2, BORDER_REFLECT);
border_Image.copyTo(stmImage);
for (int y = maxSize / 2; y < border_Image.rows-maxSize / 2; y++)
{
	for (int x = maxSize/2; x < border_Image.cols*border_Image.channels()-maxSize/2; x++)
	{
		stmImage.at(y, x) = adaptiveProcess(border_Image, y, x, minSize, maxSize);
	}
}
for (int y = 0; y < srcImage.rows; y++)
{
	for (int x = 0; x < srcImage.cols*srcImage.channels(); x++)
	{
		srcImage.at(y, x) = stmImage.at(y+maxSize / 2, x+maxSize / 2);
	}
}
return srcImage;

}

uchar adaptiveProcess(const Mat &im, int row, int col, int kernelSize, int maxSize)
{
int black = 0;
int white = 0;
vector pixels; //将滑窗内的所有元素放入该容器内
for (int i = -kernelSize/2; i <= kernelSize/2; i++)//滑窗进行
{
for (int j = -kernelSize / 2; j <= kernelSize / 2; j++)
{
pixels.push_back(im.at(row + i, col + j));//
}
}
sort(pixels.begin(), pixels.end()); //对数组内的元素进行排序
//auto min = pixels[0]; //取最小值 放在数组的第一位
//auto max = pixels[kernelSize * kernelSize - 1];//取最大值 放在数组最后一位
auto medium = pixels[kernelSize*kernelSize/2+1];//取中间值
auto grayScale = im.at(row, col);//实际点的灰度值
for (int i = 0; i < kernelSize * kernelSize; i++)
{
if (pixels[i]>127)
white++;
else
black++;
}
if (black > white)//检测背景是黑色还是白色,当背景是黑色时候
{
if (white > kernelSize-1) //如果某个区域内白色点比较多,就说明是线要留着
return grayScale;
else if (white == kernelSize-1)//如果该白色点是噪点还是线无法确定,就要窗口方放大来确定
{
kernelSize = kernelSize + 2;//窗口放大
if (kernelSize < maxSize)
{
return adaptiveProcess(im, row, col, kernelSize, maxSize);
}// 增大窗口尺寸,继续A过程。
else
{
return grayScale;
}
}
else
return medium; //如果某个区域内白色点较少,就是噪点要祛除
}
else
{
if (black > kernelSize-1)
return grayScale;
else if (black == kernelSize-1)
{
if (kernelSize < maxSize)
{
kernelSize = kernelSize + 2;
return adaptiveProcess(im, row, col, kernelSize, maxSize); // 增大窗口尺寸,继续A过程。
}
else return grayScale;
}
else
return medium;
}
}

要达到两次修补的效果

基于OpenCV的图像恢复_第3张图片
总结:图像恢复的代码的思想大致为:
1 载入原始图进行掩膜的初始化
2 多原图进行去噪并显示
3 设置鼠标回调函数
4 轮询按键,根据不同的按键进行处理

你可能感兴趣的:(OpenCV,简单的图像恢复)