底下有详细代码
一、介绍
1、图像检测的原理。
图像检测的原理是检测相邻的几个点像素值之间的变化率,相对于对函数求导。求点P(x,y)的变换率,可以在点P周围选取一些点,求x方向的距离Gx,再求y方向上的距离Gy。最后变换率G等于Gx平方加上Gy平方的和的平方差,即G=Math.sqrt(Gx^2+Gy^2)。
2、Prewitt算子。
Prewitt算子对噪声不敏感。是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。
经典Prewitt算子认为:凡灰度新值大于或等于阈值的像素点都是边缘点。即选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是欠合理的,会造成边缘点的误判,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。
3、Prewitt算子模版。
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))
Gx=[-1 0 1] , Gy=[-1 -1 -1]
[-1 0 1] [ 0 0 0]
[-1 0 1] [ 1 1 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) {
prewittTest();
}
private static void prewittTest() {
String sourcePath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena灰度图.jpg";
String targetPath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena-prewitt.jpg";
prewitt(sourcePath, targetPath);
prewittBinaryTest(128);
prewittBinaryTest(64);
prewittBinaryTest(32);
}
private static void prewitt(String sourcePath, String targetPath) {
try {
//获取原图像对象,并获取原图像的二维数组
BufferedImage image = ImageIO.read(new File(sourcePath));
int[][] imgArrays = ImageUtils.getBytes(image);
//生成新图像的二维数组
int[][] newImgArrays = EdgeDetectionUtils.prewitt(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 prewittBinaryTest(int threshold) {
String sourcePath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena-prewitt.jpg";
String targetPath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena-prewitt-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)
*/
/**
* 边缘检测--Prewitt
* 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))
* Gx=[-1 0 1] , Gy=[-1 -1 -1]
* ---[-1 0 1] [ 0 0 0]
* ---[-1 0 1] [ 1 1 1]
*/
public static int[][] prewitt(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] + array[i][j + 1] + array[i + 1][j + 1] -
(array[i - 1][j - 1] + array[i][j - 1] + array[i + 1][j - 1]);
sumY = array[i + 1][j - 1] + array[i + 1][j] + array[i + 1][j + 1] -
(array[i - 1][j - 1] + 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边缘检测的详细代码,因为一样的,就不重复写出了。