圖像處理_濾波器ios
(1)圖像的平滑處理算法
圖像的平滑也稱模糊,平滑處理須要一個濾波器,最經常使用的濾波器就是線性濾波器,線性濾波器的輸出像素值是g(x,y),是輸入像素值是 f(x,y)的加權和: windows
h( k,l )稱爲核,它僅僅是一個加權係數,那麼濾波器有不少種,最經常使用的濾波器介紹以下:數組
歸一化塊濾波器:是比較簡單的濾波器,輸出的像素值是核窗口內像素值的均值(全部像素的加權係數相等),核以下:函數
高斯濾波器:最有用的濾波器。高斯濾波器是將輸入數組的每個像素點與高斯內核卷積,將卷積看成輸出像素值,好比一維高斯函數的:ui
能夠發現中間像素的加權係數最大,周邊的像素的加權係數隨着它們遠離中間像素的距離的增大而減少,二維高斯函數的表達式是spa
其中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; }
結果爲
腐蝕與膨脹(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):是經過對圖像先腐蝕後膨脹實現 , 可以排除小團塊物體(假設物體較背景明亮)
閉運算:(closing):使用過先膨脹後腐蝕實現的, 可以排除小型黑洞(黑色區域)
形態梯度(morphological Gradient):膨脹圖與腐蝕圖之差 , 可以保留物體的邊緣輪廓
頂帽(Top Hat):原圖像與開運算結果圖之差
黑帽(black Hat):閉運算結果圖與原圖像之差
源碼
#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 ); }