圖像邊緣檢測 Sobel邊緣檢測

底下有詳細代碼

一、介紹

1、圖像檢測的原理。

        圖像檢測的原理是檢測相鄰的幾個點像素值之間的變化率,相對於對函數求導。求點P(x,y)的變換率,可以在點P周圍選取一些點,求x方向的距離Gx,再求y方向上的距離Gy。最後變換率G等於Gx平方加上Gy平方的和的平方差,即G=Math.sqrt(Gx^2+Gy^2)。

2、Sobel算子。

        索貝爾算子對噪聲不敏感。是計算機視覺領域的一種重要處理方法。主要用於獲得數字圖像的一階梯度,常見的應用和物理意義是邊緣檢測。索貝爾算子是把圖像中每個像素的上下左右四領域的灰度值加權差,在邊緣處達到極值從而檢測邊緣。
        索貝爾算子主要用作邊緣檢測。在技術上,它是一離散性差分算子,用來運算圖像亮度函數的梯度之近似值。在圖像的任何一點使用此算子,將會產生對應的梯度矢量或是其法矢量。
        索貝爾算子不但產生較好的檢測效果,而且對噪聲具有平滑抑制作用,但是得到的邊緣較粗,且可能出現僞邊緣。

3、Sobel算子模版。

        Gx=f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)-(f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1))
        Gy=f(x-1,y+1)+2f(x,y+1)+f(x+1,y+1)-(f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1))
        Gx=[-1 0  1] , Gy=[-1 -2 -1]
               [-2 0  2]         [ 0  0  0]
               [-1 0  1]         [ 1  2  1]

二、主要代碼

1、EdgeDetectionTest 類。

package com.zxj.reptile.test.image.edge;

import com.zxj.reptile.utils.image.EdgeDetectionUtils;
import com.zxj.reptile.utils.image.ImageService;
import com.zxj.reptile.utils.image.ImageUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * 圖像邊緣檢測
 */
public class EdgeDetectionTest {
    public static void main(String[] args) {
        sobelTest();
    }

    private static void sobelTest() {
        String sourcePath = "G:\\xiaojie-java-test\\img\\邊緣檢測\\Lena灰度圖.jpg";
        String targetPath = "G:\\xiaojie-java-test\\img\\邊緣檢測\\Lena-sobel.jpg";
        sobel(sourcePath, targetPath);
        sobelBinaryTest(128);
        sobelBinaryTest(64);
        sobelBinaryTest(32);
    }

    private static void sobel(String sourcePath, String targetPath) {
        try {
            //獲取原圖像對象,並獲取原圖像的二維數組
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getBytes(image);
            //生成新圖像的二維數組
            int[][] newImgArrays = EdgeDetectionUtils.sobel(imgArrays);
            //生成新圖片對象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            ImageUtils.setIntsForGray(newImage, newImgArrays);
            //生成圖片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void sobelBinaryTest(int threshold) {
        String sourcePath = "G:\\xiaojie-java-test\\img\\邊緣檢測\\Lena-sobel.jpg";
        String targetPath = "G:\\xiaojie-java-test\\img\\邊緣檢測\\Lena-sobel-binary-" + threshold + ".jpg";
        ImageService.toBinaryImg(sourcePath, targetPath, threshold);
    }
}

2、EdgeDetectionUtils 類。

package com.zxj.reptile.utils.image;

/**
 * 圖像邊緣檢測
 */
public class EdgeDetectionUtils {
    /*
     * 一階微分算子:Roberts 、Sobel 、Prewitt
     * G = Math.sqrt(Gx^2 + Gy^2)
     * angle = arctan(Gy / Gx)
     */


    /**
     * 邊緣檢測--Sobel
     * Gx=f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)-(f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1))
     * Gy=f(x-1,y+1)+2f(x,y+1)+f(x+1,y+1)-(f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1))
     * Gx=[-1 0  1] , Gy=[-1 -2 -1]
     * ---[-2 0  2]      [ 0  0  0]
     * ---[-1 0  1]      [ 1  2  1]
     */
    public static int[][] sobel(int[][] array) {
        int row = array.length;
        int column = array[0].length;
        int[][] newArray = new int[row][column];
        //注意:x = j = column , y = i = row
        for (int i = 0; i < row; i++) {//圖片第幾行
            for (int j = 0; j < column; j++) {//圖片第幾列
                int sum, sumX, sumY;
                if (i > 0 && j > 0 && i < row - 1 && j < column - 1) {
                    //Gx=f(x+1,y-1)+f(x+1,y)+f(x+1,y+1)-(f(x-1,y-1)+f(x-1,y)+f(x-1,y+1))
                    //Gy=f(x-1,y+1)+f(x,y+1)+f(x+1,y+1)-(f(x-1,y-1)+f(x,y-1)+f(x+1,y-1))
                    sumX = array[i - 1][j + 1] + 2 * array[i][j + 1] + array[i + 1][j + 1] -
                            (array[i - 1][j - 1] + 2 * array[i][j - 1] + array[i + 1][j - 1]);
                    sumY = array[i + 1][j - 1] + 2 * array[i + 1][j] + array[i + 1][j + 1] -
                            (array[i - 1][j - 1] + 2 * array[i - 1][j] + array[i - 1][j + 1]);
                    sum = (int) Math.sqrt(sumX * sumX + sumY * sumY);
                    newArray[i][j] = sum > 0xff ? 0xff : sum;
                } else if (i < row - 1 && j < column - 1) {
                    //Gx=f(x+1,y+1)-f(x,y),
                    //Gy=f(x,y+1)-f(x+1,y)
                    sumX = array[i + 1][j + 1] - array[i][j];
                    sumY = array[i + 1][j] - array[i][j + 1];
                    sum = (int) Math.sqrt(sumX * sumX + sumY * sumY);
                    newArray[i][j] = sum > 0xff ? 0xff : sum;
                } else if (j == column - 1) {
                    //最後一列
                    newArray[i][j] = newArray[i][j - 1];
                } else if (i == row - 1) {
                    //最後一行
                    newArray[i][j] = newArray[i - 1][j];
                }
            }
        }
        return ImageUtils.rangeByte(newArray);
    }
}

三、結果

1、原圖。

2、生成的結果截圖。

3、圖片邊緣檢測的圖片。

4、將圖片邊緣檢測的圖片二值化,其中閾值分別爲:32、64、128。                                                           

 

四、詳細代碼

詳細代碼可以查看文章圖像邊緣檢測 Reberts邊緣檢測的詳細代碼,因爲一樣的,就不重複寫出了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章