什么是边缘提取
边缘提取,指数字图像处理中,对于图片轮廓的一个处理。对于边界处,灰度值变化比较剧烈的地方,就定义为边缘。也就是拐点,拐点是指函数发生凹凸性变化的点。二阶导数为零的地方。并不是一阶导数,因为一阶导数为零,表示是极值点。
边缘提取方法
边缘检测的基本思想首先是利用边缘增强算子,突出图像中的局部边缘,然后定义象素的“边缘强度”,通过设置阈值的方法提取边缘点集。
本文介绍两种简单的边缘增强算子:
(1)简单梯度算子
采用如下的3*3的矩阵对图像进行计算
0, -1 ,0
-1, 4, -1
0, -1, 0
(2)梯度增强算子
定义两个3*3的矩阵分别对图像进行计算:
矩阵1:
1, 2, 1
0, 0, 0
-1, -2, -1
矩阵2:
1, 0, -1
2, 0, -2
1, 0, -1
最终的值按下面公式进行计算:
v = sqrt(v1 * v1 + v2 * v2)
其中v1, v2 分别为两次矩阵计算的值。
两种方式的计算效果如下:
第一张为原图,第二张为定义种算法的处理结果,第三张为第二种算法的处理结果。
算法代码
第一种算法的代码如下:
public static BufferedImage edgeExtract1(BufferedImage image) {
BufferedImage bimg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
Pixel p1 = new Pixel();
Pixel p2 = new Pixel();
Pixel p3 = new Pixel();
Pixel p4 = new Pixel();
Pixel p5 = new Pixel();
Pixel p6 = new Pixel();
Pixel p7 = new Pixel();
Pixel p8 = new Pixel();
Pixel p9 = new Pixel();
int maxColor = 0;
Pixel p = new Pixel();
for (int y = 1; y < bimg.getHeight() - 1; y++) {
for (int x = 1; x < bimg.getWidth() - 1; x++) {
p1.setRGB(image.getRGB(x - 1, y - 1));
p2.setRGB(image.getRGB(x, y - 1));
p3.setRGB(image.getRGB(x + 1, y - 1));
p4.setRGB(image.getRGB(x - 1, y));
p5.setRGB(image.getRGB(x, y));
p6.setRGB(image.getRGB(x + 1, y));
p7.setRGB(image.getRGB(x - 1, y + 1));
p8.setRGB(image.getRGB(x, y + 1));
p9.setRGB(image.getRGB(x + 1, y + 1));
p.red = p5.red * 4 - p2.red - p4.red - p6.red - p8.red;
p.blue = p5.blue * 4 - p2.blue - p4.blue - p6.blue - p8.blue;
p.green = p5.green * 4 - p2.green - p4.green - p6.green - p8.green;
if (p.red < 0) p.red = -p.red;
if (p.green < 0) p.green = -p.green;
if (p.blue < 0) p.blue = -p.blue;
if (p.red > 255) p.red = 255;
if (p.green > 255) p.green = 255;
if (p.blue > 255) p.blue = 255;
p.red = p.green = p.blue = (p.red + p.green + p.blue) / 3;
if (p.red > maxColor)
maxColor = p.red;
bimg.setRGB(x, y, p.getRGB());
}
}
for (int y = 1; y < bimg.getHeight() - 1; y++) {
for (int x = 1; x < bimg.getWidth() - 1; x++) {
p.setRGB(bimg.getRGB(x, y));
p.red = p.green = p.blue = 255 * p.red / maxColor;
bimg.setRGB(x, y, p.getRGB());
}
}
return bimg;
}
第二种算法代码如下:
public static BufferedImage edgeExtract2(BufferedImage image) {
BufferedImage bimg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
Pixel p1 = new Pixel();
Pixel p2 = new Pixel();
Pixel p3 = new Pixel();
Pixel p4 = new Pixel();
Pixel p5 = new Pixel();
Pixel p6 = new Pixel();
Pixel p7 = new Pixel();
Pixel p8 = new Pixel();
Pixel p9 = new Pixel();
int sum1, sum2, sum;
Pixel p = new Pixel();
for (int y = 1; y < bimg.getHeight() - 1; y++) {
for (int x = 1; x < bimg.getWidth() - 1; x++) {
p1.setRGB(image.getRGB(x - 1, y - 1));
p2.setRGB(image.getRGB(x, y - 1));
p3.setRGB(image.getRGB(x + 1, y - 1));
p4.setRGB(image.getRGB(x - 1, y));
p5.setRGB(image.getRGB(x, y));
p6.setRGB(image.getRGB(x + 1, y));
p7.setRGB(image.getRGB(x - 1, y + 1));
p8.setRGB(image.getRGB(x, y + 1));
p9.setRGB(image.getRGB(x + 1, y + 1));
sum1 = p1.red + 2 * p2.red + p3.red - p7.red - 2 * p8.red - p9.red;
sum2 = p1.red + 2 * p4.red + p7.red - p3.red - 2 * p6.red - p9.red;
sum = (int) Math.sqrt(sum1 * sum1 + sum2 * sum2);
if (sum > 255)
sum = 255;
p.red = sum;
sum1 = p1.green + 2 * p2.green + p3.green - p7.green - 2 * p8.green - p9.green;
sum2 = p1.green + 2 * p4.green + p7.green - p3.green - 2 * p6.green - p9.green;
sum = (int) Math.sqrt(sum1 * sum1 + sum2 * sum2);
if (sum > 255)
sum = 255;
p.green = sum;
sum1 = p1.blue + 2 * p2.blue + p3.blue - p7.blue - 2 * p8.blue - p9.blue;
sum2 = p1.blue + 2 * p4.blue + p7.blue - p3.blue - 2 * p6.blue - p9.blue;
sum = (int) Math.sqrt(sum1 * sum1 + sum2 * sum2);
if (sum > 255)
sum = 255;
p.blue = sum;
p.red = p.green = p.blue = (p.red + p.green + p.blue) / 3;
bimg.setRGB(x, y, p.getRGB());
}
}
return bimg;
}
其中类Pixel代码如下:
import java.awt.image.*;
public class Pixel {
public int red;
public int green;
public int blue;
public int alpha=0xFF;
public double hue;
public double saturation;
public double luminosity;
private int rgb;
public Pixel() {
}
public void setRGB(int rgb) {
red = (rgb & 0x00FF0000) / 0x00010000;
green = (rgb & 0x0000FF00) / 0x00000100;
blue = rgb & 0x000000FF;
alpha = (rgb >> 24)&0x0ff;
this.rgb = rgb;
}
public int getRGB() {
rgb = alpha<<24 | 0x00010000 * red | 0x00000100 * green | blue;
return this.rgb;
}
public static void setRgb(BufferedImage image, int x, int y, int red, int green, int blue) {
int rgb = 0xFF000000 | red * 0x00010000 | green * 0x00000100 | blue;
image.setRGB(x, y, rgb);
}
public static int pixelIntensity(int rgb) {
int red = (rgb&0x00FF0000)/0x00010000;
int green = (rgb&0x0000FF00)/0x00000100;
int blue = rgb&0x000000FF;
return (int) (0.299 * red + 0.587 * green + 0.114 * blue + 0.5);
}
}
测试代码如下:
public static void main(String[] argv) throws IOException {
BufferedImage img = read(new File("girl.jpg"));
BufferedImage img2 = edgeExtract1(img);
ImageIO.write(img2, "jpeg", new File("edge-girl-1.jpg"));
img2 = edgeExtract2(img);
ImageIO.write(img2, "jpeg", new File("edge-girl-2.jpg"));
}