1. 程式人生 > >基於OpenCV的影象恢復

基於OpenCV的影象恢復

根據自適應濾波原理,設計一種可較好的保留底紋細節的自適應中值濾波器,對下圖1進行恢復(5%椒鹽噪聲),要求達到圖2的效果。
在這裡插入圖片描述
圖1
在這裡插入圖片描述
圖2

用visual studio 2012實現的程式碼如下:
特別注意的是,把要處理的圖片放在工程目錄下!!!
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/photo/photo.hpp>
#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 <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/photo/photo.hpp>
#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<uchar>(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<uchar>(y, x) = stmImage.at<uchar>(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;
}
}

要達到兩次修補的效果

在這裡插入圖片描述
總結:影象恢復的程式碼的思想大致為:
1 載入原始圖進行掩膜的初始化
2 多原圖進行去噪並顯示
3 設定滑鼠回撥函式
4 輪詢按鍵,根據不同的按鍵進行處理