<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      OpenCV 2.4+ C++ 邊緣梯度計(jì)算

      2012-11-23 09:11  Justany_WhiteSnow  閱讀(28202)  評(píng)論(7)    收藏  舉報(bào)

      圖像的邊緣

      圖像的邊緣從數(shù)學(xué)上是如何表示的呢?

      How intensity changes in an edge

      圖像的邊緣上,鄰近的像素值應(yīng)當(dāng)顯著地改變了。而在數(shù)學(xué)上,導(dǎo)數(shù)是表示改變快慢的一種方法。梯度值的大變預(yù)示著圖像中內(nèi)容的顯著變化了。

      用更加形象的圖像來(lái)解釋,假設(shè)我們有一張一維圖形。下圖中灰度值的“躍升”表示邊緣的存在:

          Intensity Plot for an edge

      使用一階微分求導(dǎo)我們可以更加清晰的看到邊緣“躍升”的存在(這里顯示為高峰值):

          First derivative of Intensity - Plot for an edge

      由此我們可以得出:邊緣可以通過(guò)定位梯度值大于鄰域的相素的方法找到。

       

      卷積

      卷積可以近似地表示求導(dǎo)運(yùn)算。

      那么卷積是什么呢?

      卷積是在每一個(gè)圖像塊與某個(gè)算子(核)之間進(jìn)行的運(yùn)算。

      核?!

      核就是一個(gè)固定大小的數(shù)值數(shù)組。該數(shù)組帶有一個(gè)錨點(diǎn) ,一般位于數(shù)組中央。

      kernel example

       可是這怎么運(yùn)算啊?

      假如你想得到圖像的某個(gè)特定位置的卷積值,可用下列方法計(jì)算:

      1. 將核的錨點(diǎn)放在該特定位置的像素上,同時(shí),核內(nèi)的其他值與該像素鄰域的各像素重合;
      2. 將核內(nèi)各值與相應(yīng)像素值相乘,并將乘積相加;
      3. 將所得結(jié)果放到與錨點(diǎn)對(duì)應(yīng)的像素上;
      4. 對(duì)圖像所有像素重復(fù)上述過(guò)程。

      用公式表示上述過(guò)程如下:

          H(x,y) = \sum_{i=0}^{M_{i} - 1} \sum_{j=0}^{M_{j}-1} I(x+i - a_{i}, y + j - a_{j})K(i,j)

      在圖像邊緣的卷積怎么辦呢?

      計(jì)算卷積前,OpenCV通過(guò)復(fù)制源圖像的邊界創(chuàng)建虛擬像素,這樣邊緣的地方也有足夠像素計(jì)算卷積了。

       

      近似梯度

      比如內(nèi)核為3時(shí)。

      首先對(duì)x方向計(jì)算近似導(dǎo)數(shù):

      G_{x} = \begin{bmatrix}
-1 & 0 & +1  \\
-2 & 0 & +2  \\
-1 & 0 & +1
\end{bmatrix} * I

      然后對(duì)y方向計(jì)算近似導(dǎo)數(shù):

      G_{y} = \begin{bmatrix}
-1 & -2 & -1  \\
0 & 0 & 0  \\
+1 & +2 & +1
\end{bmatrix} * I

      然后計(jì)算梯度:

      G = \sqrt{ G_{x}^{2} + G_{y}^{2} }

      當(dāng)然你也可以寫(xiě)成:

      G = |G_{x}| + |G_{y}|

       

      開(kāi)始求梯度

      #include "opencv2/imgproc/imgproc.hpp"
      #include "opencv2/highgui/highgui.hpp"
      #include <stdlib.h>
      #include <stdio.h>
      
      using namespace cv;
      
      int main( int argc, char** argv ){
      
          Mat src, src_gray;
          Mat grad;
          char* window_name = "求解梯度";
          int scale = 1;
          int delta = 0;
          int ddepth = CV_16S;
      
          int c;
      
          src = imread( argv[1] );
      
          if( !src.data ){ 
              return -1; 
          }
      
          //高斯模糊
          GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
      
          //轉(zhuǎn)成灰度圖
          cvtColor( src, src_gray, CV_RGB2GRAY );
      
          namedWindow( window_name, CV_WINDOW_AUTOSIZE );
      
          Mat grad_x, grad_y;
          Mat abs_grad_x, abs_grad_y;
      
          Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
          convertScaleAbs( grad_x, abs_grad_x );
      
          Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
          convertScaleAbs( grad_y, abs_grad_y );
      
          addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
      
          imshow( window_name, grad );
      
          waitKey(0);
      
          return 0;
      }

       

      Sobel函數(shù)

      索貝爾算子(Sobel operator)計(jì)算。

      C++: void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta=0, intborderType=BORDER_DEFAULT )
      參數(shù)
      • src – 輸入圖像。
      • dst – 輸出圖像,與輸入圖像同樣大小,擁有同樣個(gè)數(shù)的通道。
      • ddepth –
        輸出圖片深度;下面是輸入圖像支持深度和輸出圖像支持深度的關(guān)系:
        • src.depth() = CV_8Uddepth = -1/CV_16S/CV_32F/CV_64F
        • src.depth() = CV_16U/CV_16Sddepth = -1/CV_32F/CV_64F
        • src.depth() = CV_32Fddepth = -1/CV_32F/CV_64F
        • src.depth() = CV_64Fddepth = -1/CV_64F

        當(dāng) ddepth為-1時(shí), 輸出圖像將和輸入圖像有相同的深度。輸入8位圖像則會(huì)截取頂端的導(dǎo)數(shù)。

      • xorder – x方向?qū)?shù)運(yùn)算參數(shù)。
      • yorder – y方向?qū)?shù)運(yùn)算參數(shù)。
      • ksize – Sobel內(nèi)核的大小,可以是:1,3,5,7。
      • scale – 可選的縮放導(dǎo)數(shù)的比例常數(shù)。
      • delta – 可選的增量常數(shù)被疊加到導(dǎo)數(shù)中。
      • borderType – 用于判斷圖像邊界的模式。

      代碼注釋:

      //在x方向求圖像近似導(dǎo)數(shù)
      Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
      
      //在y方向求圖像近似導(dǎo)數(shù)
      Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );

      如果我們打印上面兩個(gè)輸出矩陣,可以看到grad_x和grad_y中的元素有正有負(fù)。

      當(dāng)然,正方向遞增就是正的,正方向遞減則是負(fù)值。

      這很重要,我們可以用來(lái)判斷梯度方向。

       

      convertScaleAbs函數(shù)

      線性變換轉(zhuǎn)換輸入數(shù)組元素成8位無(wú)符號(hào)整型。

      C++: void convertScaleAbs(InputArray src, OutputArray dst, double alpha=1, double beta=0)
      參數(shù)
      • src – 輸入數(shù)組。
      • dst – 輸出數(shù)組。
      • alpha – 可選縮放比例常數(shù)。
      • beta – 可選疊加到結(jié)果的常數(shù)。

      對(duì)于每個(gè)輸入數(shù)組的元素函數(shù)convertScaleAbs 進(jìn)行三次操作依次是:縮放,得到一個(gè)絕對(duì)值,轉(zhuǎn)換成無(wú)符號(hào)8位類型。

      \texttt{dst} (I)= \texttt{saturate\_cast<uchar>} (| \texttt{src} (I)* \texttt{alpha} +  \texttt{beta} |)

      對(duì)于多通道矩陣,該函數(shù)對(duì)各通道獨(dú)立處理。如果輸出不是8位,將調(diào)用Mat::convertTo 方法并計(jì)算結(jié)果的絕對(duì)值,例如:

      Mat_<float> A(30,30);
      randu(A, Scalar(-100), Scalar(100));
      Mat_<float> B = A*5 + 3;
      B = abs(B);

      為了能夠用圖像顯示,提供一個(gè)直觀的圖形,我們利用該方法,將-256 — 255的導(dǎo)數(shù)值,轉(zhuǎn)成0 — 255的無(wú)符號(hào)8位類型。

       

      addWeighted函數(shù)

      計(jì)算兩個(gè)矩陣的加權(quán)和。

      C++: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, intdtype=-1)
      參數(shù)
      • src1 – 第一個(gè)輸入數(shù)組。
      • alpha – 第一個(gè)數(shù)組的加權(quán)系數(shù)。
      • src2 – 第二個(gè)輸入數(shù)組,必須和第一個(gè)數(shù)組擁有相同的大小和通道。
      • beta – 第二個(gè)數(shù)組的加權(quán)系數(shù)。
      • dst – 輸出數(shù)組,和第一個(gè)數(shù)組擁有相同的大小和通道。
      • gamma – 對(duì)所有和的疊加的常量。
      • dtype – 輸出數(shù)組中的可選的深度,當(dāng)兩個(gè)數(shù)組具有相同的深度,此系數(shù)可設(shè)為-1,意義等同于選擇與第一個(gè)數(shù)組相同的深度。

      函數(shù)addWeighted 兩個(gè)數(shù)組的加權(quán)和公式如下:

          \texttt{dst} (I)= \texttt{saturate} ( \texttt{src1} (I)* \texttt{alpha} +  \texttt{src2} (I)* \texttt{beta} +  \texttt{gamma} )

      在多通道情況下,每個(gè)通道是獨(dú)立處理的,該函數(shù)可以被替換成一個(gè)函數(shù)表達(dá)式:

          dst = src1*alpha + src2*beta + gamma;

      利用convertScaleAbs和addWeighted,我們可以對(duì)梯度進(jìn)行一個(gè)可以用圖像顯示的近似表達(dá)。

      這樣我們就可以得到下面的效果:

      Result of applying Sobel operator to lena.jpg

       

      梯度方向

      但有時(shí)候邊界還不夠,我們希望得到圖片色塊之間的關(guān)系,或者研究樣本的梯度特征來(lái)對(duì)機(jī)器訓(xùn)練識(shí)別物體時(shí)候,我們還需要梯度的方向。

      二維平面的梯度定義為:

          

      這很好理解,其表明顏色增長(zhǎng)的方向與x軸的夾角。

      但Sobel算子對(duì)于沿x軸和y軸的排列表示的較好,但是對(duì)于其他角度表示卻不夠精確。這時(shí)候我們可以使用Scharr濾波器。

      Scharr濾波器的內(nèi)核為:

          G_{x} = \begin{bmatrix}
-3 & 0 & +3  \\
-10 & 0 & +10  \\
-3 & 0 & +3
\end{bmatrix}

G_{y} = \begin{bmatrix}
-3 & -10 & -3  \\
0 & 0 & 0  \\
+3 & +10 & +3
\end{bmatrix}

      這樣能提供更好的角度信息,現(xiàn)在我們修改原程序,改為使用Scharr濾波器進(jìn)行計(jì)算:

      #include "opencv2/imgproc/imgproc.hpp"
      #include "opencv2/highgui/highgui.hpp"
      #include <stdlib.h>
      #include <stdio.h>
      
      using namespace cv;
      
      int main( int argc, char** argv ){
      
          Mat src, src_gray;
          Mat grad;
          char* window_name = "梯度計(jì)算";
          int scale = 1;
          int delta = 0;
          int ddepth = CV_16S;
      
          int c;
      
          src = imread( argv[1] );
      
          if( !src.data ){ 
              return -1; 
          }
      
          GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
      
          cvtColor( src, src_gray, CV_RGB2GRAY );
      
          namedWindow( window_name, CV_WINDOW_AUTOSIZE );
      
          Mat grad_x, grad_y;
          Mat abs_grad_x, abs_grad_y;
      
          //改為Scharr濾波器計(jì)算x軸導(dǎo)數(shù)
          Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
          convertScaleAbs( grad_x, abs_grad_x );
      
          //改為Scharr濾波器計(jì)算y軸導(dǎo)數(shù)
          Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
          convertScaleAbs( grad_y, abs_grad_y );
      
          addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
      
          imshow( window_name, grad );
      
          waitKey(0);
      
          return 0;
      }

      Scharr函數(shù)接受參數(shù)與Sobel函數(shù)相似,這里就不敘述了。

      下面我們通過(guò)divide函數(shù)就能得到一個(gè)x/y的矩陣。

      對(duì)兩個(gè)輸入數(shù)組的每個(gè)元素執(zhí)行除操作。

      C++: void divide(InputArray src1, InputArray src2, OutputArray dst, double scale=1, int dtype=-1)
      C++: void divide(double scale, InputArray src2, OutputArray dst, int dtype=-1)
      參數(shù)
      • src1 – 第一個(gè)輸入數(shù)組。
      • src2 – 第二個(gè)輸入數(shù)組,必須和第一個(gè)數(shù)組擁有相同的大小和通道。
      • scale – 縮放系數(shù)。
      • dst – 輸出數(shù)組,和第二個(gè)數(shù)組擁有相同的大小和通道。
      • dtype – 輸出數(shù)組中的可選的深度,當(dāng)兩個(gè)數(shù)組具有相同的深度,此系數(shù)可設(shè)為-1,意義等同于選擇與第一個(gè)數(shù)組相同的深度。

      該函數(shù)對(duì)兩個(gè)數(shù)組進(jìn)行除法:

        \texttt{dst(I) = saturate(src1(I)*scale/src2(I))}

      或則只是縮放系數(shù)除以一個(gè)數(shù)組:

        \texttt{dst(I) = saturate(scale/src2(I))}

      這種情況如果src2是0,那么dst也是0。不同的通道是獨(dú)立處理的。

       

      被山寨的原文

      Sobel Derivatives . OpenCV.org

      Image Filtering . OpenCV.org

      主站蜘蛛池模板: 免费午夜无码片在线观看影院| 国产高清一区二区不卡| 蜜臀av无码一区二区三区| 99久久99这里只有免费费精品| 国产丰满乱子伦无码专区| 国产精品三级中文字幕| 亚洲国产五月综合网| 亚洲成a人无码av波多野| 国产 麻豆 日韩 欧美 久久| 伊人欧美在线| 黄色亚洲一区二区三区四区| 精品无码一区二区三区电影| 春色校园综合人妻av| 国产一区二区三区四区激情| 亚洲第一狼人天堂网伊人| 99精品偷自拍| 狠狠色噜噜狠狠狠777米奇小说| 好吊视频一区二区三区人妖| 国产一区二区三区色噜噜| 亚洲免费网站观看视频 | 成在线人永久免费视频播放| 26uuu另类亚洲欧美日本| 国产专区一va亚洲v天堂| 国产精品三级黄色小视频| 鄱阳县| 日韩精品福利一二三专区| 国产无人区码一区二区| 国产成人AV国语在线观看| 18禁免费无码无遮挡网站| 国产精品+日韩精品+在线播放| 日韩丝袜人妻中文字幕| 国产69精品久久久久人妻刘玥| 亚洲av优女天堂熟女久久| 麻豆亚洲精品一区二区| 99欧美日本一区二区留学生| 日韩人妻精品中文字幕专区 | 伊人成伊人成综合网222| 久热这里只有精品视频六| 国产亚洲人成网站在线观看| 婷婷色综合成人成人网小说| 泸溪县|