圖像處理_imgproc筆記(1)

圖像處理_濾波器ios

(1)圖像的平滑處理算法

    圖像的平滑也稱模糊,平滑處理須要一個濾波器,最經常使用的濾波器就是線性濾波器,線性濾波器的輸出像素值是g(x,y),是輸入像素值是  f(x,y)的加權和:                                                                                     g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l)windows

   h( k,l )稱爲核,它僅僅是一個加權係數,那麼濾波器有不少種,最經常使用的濾波器介紹以下:數組

    歸一化塊濾波器:是比較簡單的濾波器,輸出的像素值是核窗口內像素值的均值(全部像素的加權係數相等),核以下:函數

                                                          K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix}
    1 & 1 & 1 & ... & 1 \\
    1 & 1 & 1 & ... & 1 \\
    . & . & . & ... & 1 \\
    . & . & . & ... & 1 \\
    1 & 1 & 1 & ... & 1
   \end{bmatrix}

高斯濾波器:最有用的濾波器。高斯濾波器是將輸入數組的每個像素點與高斯內核卷積,將卷積看成輸出像素值,好比一維高斯函數的:ui

                                                    ../../../../_images/Smoothing_Tutorial_theory_gaussian_0.jpg

能夠發現中間像素的加權係數最大,周邊的像素的加權係數隨着它們遠離中間像素的距離的增大而減少,二維高斯函數的表達式是spa

                                                             G_{0}(x, y) = A  e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } +  \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } }

其中u爲均值,峯值對應的位置,o是表明標準差,變量x,y各有一個均值,也各有一個標準差.net

 

中值濾波器:將圖像的每個像素用領域像素的中值替代(以當前像素爲中心的正方形區域)orm

雙邊濾波器:相似與高斯濾波器,雙邊濾波器也給每個領域像素分配一個加權係數,這個加權係數包含兩個部分,第一部分加權方式與高斯濾波同樣(是有幾何空間距離決定濾波器的係數),第二部分的權重則取決於該領域像素與當前像素的灰度差值,是一種能夠包邊去噪的濾波器對象

雙邊濾波器中輸出濾波器的值依賴於鄰域像素值的加權組合

                                                                           

權重係數w(i,j,k,l)取決於定義域核

                                                                      

和值域核

                                                                         

的卷積

                                          

源碼與結果

#include <iostream>
#include <vector>

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"

using namespace std;
using namespace cv;

/// 全局變量
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;   //最大的核長度

Mat src; Mat dst;
char window_name[] = "Smoothing Demo";

/// Function headers函數聲明
int display_caption( const char* caption );
int display_dst( int delay );


/**
 * function main
 */
int main( void )
{
  namedWindow( window_name, WINDOW_AUTOSIZE );

  ///載入原圖想
  src = imread( "/home/salm/myopencv/images/cat.jpg", 1 );

  if( display_caption( "Original Image" ) != 0 ) { return 0; }

  dst = src.clone();
  if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }


  /// Applying Homogeneous blur    使用均值平滑
/*blur歸一化塊濾波
   src: 輸入圖像
    dst: 輸出圖像
    Size( w,h ): 定義內核大小( w 像素寬度, h 像素高度)
    Point(-1, -1): 指定錨點位置(被平滑點), 若是是負值,取核的中心爲錨點。
*/
  if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }

  for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
      { blur( src, dst, Size( i, i ), Point(-1,-1) );
        if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }


  /// Applying Gaussian blur     使用高斯平滑
  if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }

  for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
      { GaussianBlur( src, dst, Size( i, i ), 0, 0 ); //Size(w, h): 定義內核的大小(須要考慮的鄰域範圍)。 w 和 h 必須是正奇數,不然將使用 \sigma_{x} 和 \sigma_{y} 參數來計算內核大小
        if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }


  /// Applying Median blur    中值濾波
  if( display_caption( "Median Blur" ) != 0 ) { return 0; }

  for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
      { medianBlur ( src, dst, i );  //i: 內核大小 (只需一個值,由於咱們使用正方形窗口),必須爲奇數
        if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }


  /// Applying Bilateral Filter  雙邊濾波
/*
bilateral執行雙邊濾波操做
    src: 輸入圖像
    dst: 輸出圖像
    d: 像素的鄰域直徑
    sigma_{Color}: 顏色空間的標準方差
    sigma_{Space}: 座標空間的標準方差(像素單位)
*/
  if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }

  for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
      { bilateralFilter ( src, dst, i, i*2, i/2 );
        if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }

  /// Wait until user press a key
  display_caption( "End: Press a key!" );

  waitKey(0);

  return 0;
}

/**
 * @function display_caption
 */
int display_caption( const char* caption )
{
  dst = Mat::zeros( src.size(), src.type() );
  putText( dst, caption,
           Point( src.cols/4, src.rows/2),
           FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );

  imshow( window_name, dst );
  int c = waitKey( DELAY_CAPTION );
  if( c >= 0 ) { return -1; }
  return 0;
}

/**
 * @function display_dst
 */
int display_dst( int delay )
{
  imshow( window_name, dst );
  int c = waitKey ( delay );
  if( c >= 0 ) { return -1; }
  return 0;
}

結果爲

                                                                                 Smoothing with a median filter

 腐蝕與膨脹(Eroding and Dilating)

形態學操做是基於形狀的一系列圖像處理操做,經過結構元素做用於輸入圖像來產生輸出圖像,最基本的形態學操做有兩種:erision  與  dilation  它們的應用普遍,主要有消除噪聲,分割獨立的圖像元素,鏈接相鄰的元素,尋找圖像中明顯的極大值或極小值區域

通俗的說:膨脹算法是圖像擴大一圈,腐蝕算法是圖像縮小一圈,腐蝕是刪除對象邊界的某些元素,膨脹是給圖像的邊界添加某些元素,算法從圖像的角度來看,二值圖像的腐蝕與膨脹就是將一個小型的二值圖像(好比通常爲結構元素  通常爲3*3的)在圖像上進行逐點的運動並比較,根據比較的結果作出相應的處理。

膨脹算法:用3*3的結構元素,掃描二值圖像的每個像素,用結構元素與其覆蓋的二值圖像作「與」運行,若是都爲「0」結構圖像的該元素就爲0  不然就爲1   結果會使得二值圖像擴大一圈

腐蝕算法:用3*3的結果元素,掃描二值圖像的每個像素,用結構元素與其覆蓋的二值圖像作「與」運算,結構都爲1  結構圖像的該元素就爲1  不然就爲0   結果使二值圖像減少一圈

OpenCV裏面的腐蝕膨脹都是針對 白色 目標區域的。說膨脹使圖像 變大一圈, 那是指 圖像中的 白色目標區域 擴大了一圈

 源碼

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>

using namespace cv;

/// Global variables 全局變量
Mat src, erosion_dst, dilation_dst;

int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;

//函數申明
void Erosion( int, void* );
void Dilation( int, void* );

int main( int, char** argv )
{
  /// Load an image
  src = imread( argv[1] );

  if( !src.data )
    { return -1; }

  /// Create windows
  namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
  namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
  moveWindow( "Dilation Demo", src.cols, 0 );

  /// Create Erosion Trackbar
  createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
          &erosion_elem, max_elem,
          Erosion );

  createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo",
          &erosion_size, max_kernel_size,
          Erosion );

  /// Create Dilation Trackbar
  createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
          &dilation_elem, max_elem,
          Dilation );

  createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo",
          &dilation_size, max_kernel_size,
          Dilation );

  /// Default start
  Erosion( 0, 0 );
  Dilation( 0, 0 );

  waitKey(0);
  return 0;
}

/*
內核選擇三種形狀之一:
        矩形: MORPH_RECT
        交叉形: MORPH_CROSS
        橢圓形: MORPH_ELLIPSE
*/
void Erosion( int, void* )
{
  int erosion_type = 0;
  if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
  else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
  else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( erosion_type,
                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                       Point( erosion_size, erosion_size ) );
  /// Apply the erosion operation
  erode( src, erosion_dst, element );
  imshow( "Erosion Demo", erosion_dst );
}

void Dilation( int, void* )
{
  int dilation_type = 0;
  if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
  else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
  else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }

  Mat element = getStructuringElement( dilation_type,
                       Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                       Point( dilation_size, dilation_size ) );
  /// Apply the dilation operation
  dilate( src, dilation_dst, element );
  imshow( "Dilation Demo", dilation_dst );
}

 更改Trackbars的位置就會產生不同的輸出圖像

 更多的形態學變換

開運算(opening):是經過對圖像先腐蝕後膨脹實現  , 可以排除小團塊物體(假設物體較背景明亮)

   dst = open( src, element) = dilate( erode( src, element ) )         

閉運算:(closing):使用過先膨脹後腐蝕實現的,  可以排除小型黑洞(黑色區域)

  dst = close( src, element ) = erode( dilate( src, element ) )           

形態梯度(morphological Gradient):膨脹圖與腐蝕圖之差 , 可以保留物體的邊緣輪廓dst = morph_{grad}( src, element ) = dilate( src, element ) - erode( src, element )

 頂帽(Top Hat):原圖像與開運算結果圖之差   dst = tophat( src, element ) = src - open( src, element )

 黑帽(black Hat):閉運算結果圖與原圖像之差dst = blackhat( src, element ) = close( src, element ) - src

 源碼

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>

using namespace cv;

/// Global variables
Mat src, dst;

int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;

const char* window_name = "Morphology Transformations Demo";


/** Function Headers */
void Morphology_Operations( int, void* );


int main( int, char** argv )
{
  ///  載入圖像
  src = imread( argv[1] );

  if( !src.data )
    { return -1; }

  /// Create window
  namedWindow( window_name, WINDOW_AUTOSIZE );

  /// Create Trackbar to select Morphology operation
  createTrackbar("Operator:\n 0: Opening - 1: Closing  \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );

  /// Create Trackbar to select kernel type
  createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
                  &morph_elem, max_elem,
                  Morphology_Operations );

  /// Create Trackbar to choose kernel size
  createTrackbar( "Kernel size:\n 2n +1", window_name,
                  &morph_size, max_kernel_size,
                  Morphology_Operations );

  /// Default start
  Morphology_Operations( 0, 0 );

  waitKey(0);
  return 0;
}

/**
 * @function Morphology_Operations
 */
void Morphology_Operations( int, void* )
{

  // Since MORPH_X : 2,3,4,5 and 6
  int operation = morph_operator + 2;

  Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );

  /// Apply the specified morphology operation
  morphologyEx( src, dst, operation, element );
  imshow( window_name, dst );
}
相關文章
相關標籤/搜索