OpenCV2鄰域和模板操作


在圖像處理中,通過當前位置的鄰域像素計算新的像素值是很常見的操作。當鄰域包含圖像的上幾行和下幾行時,就需要同時掃描圖像的若干行,這就是圖像的鄰域操作了。至於模板操作是實現空間濾波的基礎,通常是使用一個模板(一個的矩形)滑過整幅圖像產生新的像素。下面介紹通過使用OpenCV2實現Laplace算子銳化圖像,來介紹OpenCV2中對鄰域和模板的操作。

銳化處理主要的目的是突出灰度的過渡部分,通常由微分來定義和實現銳化算子的各種方法。Laplace算子是最賤的各向同性微分算子,常用的Laplace模板如下:

image

使用Laplace算子銳化圖像時需要注意模板中心的系數,如果中心系數是負的,就需要將原圖像減去經過Laplace算子處理后的圖像,得到銳化后的結果。如果中心系數是正的,則相反。

銳化圖像時不能以In-Place的方式來完成,需要提供一個輸出圖像。在對圖像遍歷時使用兩個3個指針:一個指向當前行,一個指向當前行的上一行,一個指向當前行的下一行。而且,由於每個像素值的計算都需要它的上下左右四個相鄰像素,所以無法對圖像的邊界進行計算,需要另作處理。具體實現代碼如下:

   1:  /*
   2:      0    -1    0
   3:      -1    4    -1
   4:      0    -1    0
   5:  */
   6:  void sharpen(const Mat & image,Mat & result)
   7:  {
   8:      CV_Assert(image.depth() == CV_8U);
   9:   
  10:      result.create(image.size(),image.type());
  11:   
  12:      const int channels = image.channels() ;
  13:      for(int j = 1 ;j < image.rows - 1 ; j ++){
  14:          const uchar * previous = image.ptr<const uchar>(j - 1) ; // 當前行的上一行
  15:          const uchar * current = image.ptr<const uchar>(j) ; //當前行
  16:          const uchar * next = image.ptr<const uchar>(j + 1) ; //當前行的下一行
  17:   
  18:          uchar * output = result.ptr<uchar>(j) ;  // 輸出行
  19:          for(int i = channels ; i < channels * (image.cols - 1) ; i ++) {
  20:              * output ++ = saturate_cast<uchar>( 4 * current[i] - previous[i] - next[i] - current[i - channels] - current[ i + channels]) ;
  21:          }
  22:      }
  23:   
  24:      //對圖像邊界進行處理
  25:      //邊界像素設置為0
  26:      result.row(0).setTo(Scalar(0));
  27:      result.row(result.rows-1).setTo(Scalar(0)) ;
  28:      result.col(0).setTo(Scalar(0));
  29:      result.col(result.cols-1).setTo(Scalar(0));
  30:  }

這里使用指針遍歷整個圖像,使用三個指針同時掃描圖像的三行,另外使用一個指針指向輸出行。在計算輸出像素時,使用模板函數saturate_cast<uchar>對計算結果進行調整。這是因為對像素值的計算有可能導致結果超出了像素允許的范圍,即小於0或者大於255,當計算結果是浮點數時,該函數會將結果取整至最近的整數。

由於邊界的像素沒有完整的鄰域,無法使用模板計算其值,需要單獨處理。這里只是簡單的將其值設為0.

測試代碼:

   1:      Mat image = imread("d:\\lenna.jpg") ;
   2:      Mat result ;
   3:      sharpen(image,result) ;
   4:      imwrite("d:\\lenna1.jpg",result) ;
   5:      imwrite("d:\\lenna2.jpg",image + result) ;

結果如下:

imageimage

這里需要說明,在OpenCV2中對Mat進行了大量的運算符重載,例如上面,兩幅圖像相加直接使用image + result即可。另外,如位操作符:&,|,^,~;函數max,min,abs;比較操作符:<,<=,>,>=,比較操作符返回一個8位二進制圖像。另外矩陣乘法m1 * m2,矩陣求逆 m1.inv(),矩陣轉置m.t(),舉證的行列式m.determinate(),向量的模v.norm(),向量叉乘v.corss(v1),向量的點乘v.dot(v1)等。

由於使用模板實現空間濾波在圖像處理中非常的常用,在OpenCV中專門定義了一個特殊的函數來完成該處理:
filter2D.

函數原型:

   1:  void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )

參數:
src,輸入圖像
dst 輸出圖像,和輸入圖像有相同的大小和通道
ddepth 輸出圖像的depth,如果為負數,則和輸入圖像的depth相同
kernel 模板
anchor 進行卷積運算的中心位置,默認的是kernel的中心
delta 可選值,加到輸出像素上的值
bordertype 對輸出圖像邊界的處理。

使用filter2D實現Laplace算子

   1:      Mat kern = (Mat_<char> (3,3) << 1,1,1,
   2:                                      1,-8,1,
   3:                                      1,1,1) ;
   4:      filter2D(image,result,image.depth(),kern) ;
這里只需要定義好kernel調用filter2D即可,而且OpenCV對該函數進行了優化,其效率要比上面使用指針實現的要高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM