JAVA图像处理系列(三)——边缘提取

什么是边缘提取

边缘提取,指数字图像处理中,对于图片轮廓的一个处理。对于边界处,灰度值变化比较剧烈的地方,就定义为边缘。也就是拐点,拐点是指函数发生凹凸性变化的点。二阶导数为零的地方。并不是一阶导数,因为一阶导数为零,表示是极值点。

边缘提取方法

边缘检测的基本思想首先是利用边缘增强算子,突出图像中的局部边缘,然后定义象素的“边缘强度”,通过设置阈值的方法提取边缘点集。

本文介绍两种简单的边缘增强算子:
(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 分别为两次矩阵计算的值。

两种方式的计算效果如下:
第一张为原图,第二张为定义种算法的处理结果,第三张为第二种算法的处理结果。

girl3.jpg
edge-girl-1.jpg
edge-girl-2.jpg

算法代码

第一种算法的代码如下:

    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"));
 }

你可能感兴趣的:(JAVA图像处理系列(三)——边缘提取)