1. 程式人生 > >Android opencv(三) 邊緣檢測Sobel、Canny

Android opencv(三) 邊緣檢測Sobel、Canny

Sobel

Sobel是檢測邊緣的一階導數,在檢測邊緣前需要通過濾波(blur)去噪來使圖片光滑,一般使用高斯濾波,大小取7x7.

  //高斯濾波
    public static Mat removeNoiseGaussianBlur(Mat srcMat){
        final Mat blurredImage=new Mat();
        Size size=new Size(7,7);
        Imgproc.GaussianBlur(srcMat,blurredImage,size,0,0);
        return blurredImage;
    }

之後進行灰度處理

  //灰度處理
    public static Mat grayImage(Mat srcMat){
        Mat grayImg=new Mat();
        Imgproc.cvtColor(srcMat,grayImg,Imgproc.COLOR_RGB2GRAY);
        return grayImg;
    }

下面是sobel進行過程

         //宣告x,y的一階導數
        Mat xDervative=new Mat();
        Mat yDervative=new Mat();
        /*一般輸入圖片的depth與輸出圖片的depth值相同,但是當我們一階導數的時候會出現負數-255—255,使用unsignded 8-bit depth只能包含0-255,因此採用了16-bit
        */
int ddepth= CvType.CV_16S; //計算x,y的一階導數,引數1,0來設定x,y軸 Imgproc.Sobel(srcMat,xDervative,ddepth,1,0); Imgproc.Sobel(srcMat,yDervative,ddepth,0,1); Mat absXD=new Mat(); Mat absYD=new Mat(); //Mat轉換 Core.convertScaleAbs(xDervative,absXD); Core.convertScaleAbs(yDervative,absYD); //根號(x*x+y*y)
Mat edgeImage=new Mat(); Core.addWeighted(absXD,0.5,absYD,0.5,0,edgeImage);

Canny

canny檢測僅在灰度圖下,同時濾波只能採用高斯濾波,原因如下:
Canny運算元在選擇濾波器時有兩個標準,首先濾波器在頻域中應該是有限頻寬的,這樣才能保證減少由於頻率的變化而導致的影象函式的變化;其次,canny經典論文中“Good Localization”標準要求濾波器的響應需要來自於影象中鄰近的點。要知道,上述兩個標準相互間是矛盾的,頻域有限說明時域無限,而高斯分佈可以較好的使上述兩個標準得到優化,因為高斯函式的離中心超過3倍標準差以外的畫素的影響可以忽略不計,同時高斯函式在頻域上也是有限頻寬的,因此才使用高斯濾波

在Canny邊緣檢測演算法中,將影象中的點歸為三類:

被抑制點

灰度梯度值 < 低閾值

弱邊緣點

低閾值 <= 灰度梯度值 <= 高閾值

強邊緣點
高閾值 < 灰度梯度值
ps:canny邊緣檢測是通過梯度與夾角進行檢測,具體原理參考下面連結,大於最大閾值的線被確認是邊緣線條,小於最小閾值的線被拋棄,在最大閾值與最小閾值之間的線條如果線條的邊緣有明確的邊緣線交點則被認為是在一條線上,從而被保留,否則被拋棄。

 //canny邊緣檢測
    public static Mat cannyEdge(Mat srcMat){
        final Mat edgeImage=new Mat();
        //100低閾值 200:高閾值
        Imgproc.Canny(srcMat,edgeImage,100,200);
        return edgeImage;
    }