OpenCV影象處理篇之影象平滑
影象平滑演算法
影象平滑與影象模糊是同一概念,主要用於影象的去噪。平滑要使用濾波器,為不改變影象的相位資訊,一般使用線性濾波器,其統一形式如下:
其中h稱為濾波器的核函式,說白了就是權值。不同的核函式代表不同的濾波器,有不同的用途。
在影象處理中,常見的濾波器包括:
歸一化濾波器(Homogeneous blur)
也是均值濾波器,用輸出畫素點核視窗內的畫素均值代替輸出點畫素值。
高斯濾波器(Guassian blur)
是實際中最常用的濾波器,高斯濾波是將輸入陣列的每一個畫素點與 高斯核心 卷積將卷積和當作輸出畫素值。高斯核相當於對輸出畫素的鄰域賦予不同的權值,輸出畫素點所在位置的權值最大(對應高斯函式的均值位置)。二維高斯函式為,
中值濾波器(median blur)
中值濾波將影象的每個畫素用鄰域(以當前畫素為中心的正方形區域)畫素的中值代替。對椒鹽噪聲最有效的濾波器,去除跳變點非常有效。
下面的程式將先給標準Lena影象新增椒鹽噪聲,分別使用4種不同的濾波器進行平滑操作,請注意觀察不同濾波器對椒鹽噪聲的去噪效果!
程式分析及結果
/*
* FileName : image_smoothing.cpp
* Author : xiahouzuoxin @163.com
* Version : v1.0
* Date : Wed 17 Sep 2014 08:30:25 PM CST
* Brief :
*
* Copyright (C) MICL,USTB
*/
#include "cv.h"
#include "imgproc/imgproc.hpp"
#include "highgui/highgui.hpp"
using namespace std;
using namespace cv;
const int MAX_KERNEL_LENGTH = 10;
const char *wn_name = "Smoothing";
static void salt(Mat &I, int n);
static void disp_caption(const char *wn_name, Mat src, const char *caption);
static void disp_image(const char *wn_name, Mat I);
/*
* @brief
* @inputs
* @outputs
* @retval
*/
int main(int argc, char *argv[])
{
if (argc<2) {
cout<<"Usage: ./image_smoothing [file name]"<<endl;
return -1;
}
Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
salt(I, 6000);
imshow(wn_name, I);
waitKey(0);
Mat dst; // Result
/* Homogeneous blur */
disp_caption(wn_name, I, "Homogeneous blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
blur(I, dst, Size(i, i), Point(-1,-1));
disp_image(wn_name, dst);
}
/* Guassian blur */
disp_caption(wn_name, I, "Gaussian blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
GaussianBlur(I, dst, Size(i, i), 0, 0);
disp_image(wn_name, dst);
}
/* Median blur */
disp_caption(wn_name, I, "Median blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
medianBlur(I, dst, i);
disp_image(wn_name, dst);
}
/* Bilatrial blur */
disp_caption(wn_name, I, "Bilatrial blur");
for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
bilateralFilter(I, dst, i, i*2, i/2);
disp_image(wn_name, dst);
}
waitKey(0);
return 0;
}
/*
* @brief 顯示提示文字(濾波方法)
* @inputs
* @outputs
* @retval
*/
static void disp_caption(const char *wn_name, Mat src, const char *caption)
{
Mat dst = Mat::zeros(src.size(), src.type());
putText(dst, caption, Point(src.cols/4, src.rows/2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255,255,255));
imshow(wn_name, dst);
waitKey(0);
}
/*
* @brief 顯示影象
* @inputs
* @outputs
* @retval
*/
static void disp_image(const char *wn_name, Mat I)
{
imshow(wn_name, I);
waitKey(1000);
}
/*
* @brief 新增椒鹽噪聲
* @inputs
* @outputs
* @retval
*/
static void salt(Mat &I, int n=3000)
{
for (int k=0; k<n; k++) {
int i = rand() % I.cols;
int j = rand() % I.rows;
if (I.channels()) {
I.at<uchar>(j,i) = 255;
} else {
I.at<Vec3b>(j,i)[0] = 255;
I.at<Vec3b>(j,i)[1] = 255;
I.at<Vec3b>(j,i)[2] = 255;
}
}
}
上面程式的邏輯非常清晰:
讀入灰度圖,並新增椒鹽噪聲(6000個噪聲點):
Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); salt(I, 6000);
disp_caption
和disp_image
函式分別是用於顯示提示文字和平滑過程中的變化影象的,平滑過程中影象的變化如下圖:注意觀察上面的圖,中值濾波(Median Blur)對椒鹽噪聲的效果最好!
四種濾波方法分別使用到4個OpenCV函式,這些函式的宣告都在
imgproc.hpp
中,這些函式的前2個引數都是原影象和濾波後圖像。歸一化濾波器
blur
的第3個引數為濾波核視窗的大小,Size(i,i)表示ixi大小的視窗。高斯濾波器
GaussianBlur
第3個引數也是濾波核視窗的大小,第4、第5個引數分辨表示x方向和y方向的δ。中值濾波器
medianBlur
第3個引數是濾波器的長度,該濾波器的視窗為正方形。雙邊濾波器的函式原型如下:
//! smooths the image using bilateral filter CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
本程式使用的Makefile檔案為:
TARG=image_smoothing SRC=image_smoothing.cpp LIB=-L/usr/local/lib/ INC=-I/usr/local/include/opencv/ -I/usr/local/include/opencv2 CFLAGS= $(TARG):$(SRC) g++ -g -o [email protected] ${CFLAGS} $(LIB) $(INC) \ -lopencv_core -lopencv_highgui -lopencv_imgproc \ $^ .PHONY:clean clean: -rm $(TARG) tags -f