1. 程式人生 > >OpenCV影象處理篇之影象平滑

OpenCV影象處理篇之影象平滑

影象平滑演算法

影象平滑與影象模糊是同一概念,主要用於影象的去噪。平滑要使用濾波器,為不改變影象的相位資訊,一般使用線性濾波器,其統一形式如下:

其中h稱為濾波器的核函式,說白了就是權值。不同的核函式代表不同的濾波器,有不同的用途。

在影象處理中,常見的濾波器包括:

  1. 歸一化濾波器(Homogeneous blur)

    也是均值濾波器,用輸出畫素點核視窗內的畫素均值代替輸出點畫素值。

  2. 高斯濾波器(Guassian blur)

    是實際中最常用的濾波器,高斯濾波是將輸入陣列的每一個畫素點與 高斯核心 卷積將卷積和當作輸出畫素值。高斯核相當於對輸出畫素的鄰域賦予不同的權值,輸出畫素點所在位置的權值最大(對應高斯函式的均值位置)。二維高斯函式為,

  1. 中值濾波器(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; } } }

上面程式的邏輯非常清晰:

  1. 讀入灰度圖,並新增椒鹽噪聲(6000個噪聲點):

    Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
    salt(I, 6000);

    LenaNoise

  2. disp_captiondisp_image函式分別是用於顯示提示文字和平滑過程中的變化影象的,平滑過程中影象的變化如下圖:

    blur

    注意觀察上面的圖,中值濾波(Median Blur)對椒鹽噪聲的效果最好!

  3. 四種濾波方法分別使用到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 );
  4. 本程式使用的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