底下有詳細代碼
一、介紹
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邊緣檢測的詳細代碼,因爲一樣的,就不重複寫出了。