Sobel 边缘检测会产生噪声

Sobel edge detection creates noise

我尝试在 java 中实现 Sobel 边缘检测。 它有点管用,但我收到很多看似随机的噪音...

我将图像加载为 BufferedImages 并首先将其转换为灰度图像(通过我在网上找到的算法)。之后我计算 x 和 y 方向的边缘。

这是我的代码:

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


public class Sobel {

    static int [] sobel_x =     {1, 0,  -1, 
                                2,  0,  -2,
                                1,  0,  -1};

    static int [] sobel_y =     {1, 2,  1, 
                                0,  0,  0,
                                -1, -2, -1};




    public static void main(String argc[]) throws IOException {

        BufferedImage imgIn = ImageIO.read(new File("test.jpeg"));
        BufferedImage imgGrey = greyscale(imgIn);
        ImageIO.write(imgGrey, "PNG", new File("greyscale.jpg"));

        BufferedImage edgesX = edgeDetection(imgGrey, sobel_x);
        ImageIO.write(edgesX, "PNG", new File("edgesX.jpg"));

        BufferedImage edgesY = edgeDetection(imgGrey, sobel_y);
        ImageIO.write(edgesY, "PNG", new File("edgesY.jpg"));

        BufferedImage sobel = sobel(edgesX,edgesY);
        ImageIO.write(sobel, "PNG", new File("sobel.jpg"));

    }


    private static BufferedImage sobel (BufferedImage edgesX, BufferedImage edgesY){

        BufferedImage result = new BufferedImage(edgesX.getWidth(), edgesX.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        int height = result.getHeight();
        int width = result.getWidth();
         for(int x = 0; x < width ; x++){
           for(int y = 0; y < height; y++){
               int tmp = Math.abs(edgesX.getRGB(x, y) + Math.abs(edgesY.getRGB(x, y)));
               result.setRGB(x, y, tmp);
           }
        }
        return result; 
    }

    private static BufferedImage edgeDetection(BufferedImage img, int[] kernel){
       int height = img.getHeight();
       int width = img.getWidth();

       BufferedImage result = new BufferedImage(width -1, height -1, BufferedImage.TYPE_BYTE_GRAY);
       for(int x = 1; x < width -1 ; x++){
           for(int y = 1; y < height - 1; y++){
               int [] tmp = {img.getRGB(x-1, y-1),img.getRGB(x, y-1),img.getRGB(x+1, y-1),img.getRGB(x-1, y),img.getRGB(x, y),img.getRGB(x+1, y),img.getRGB(x-1, y+1),img.getRGB(x, y+1),img.getRGB(x+1, y+1)};
               int value = convolution (kernel, tmp);
               result.setRGB(x,y, value);
           }
       }
       return result;
   }


   private static int convolution (int [] kernel, int [] pixel){
       int result = 0; 

       for (int i = 0; i < pixel.length; i++){
           result += kernel[i] * pixel[i];
       }

       return result / 9;
   }


   private static BufferedImage greyscale(BufferedImage img){

     //get image width and height
        int width = img.getWidth();
        int height = img.getHeight();

        //convert to grayscale
        for(int y = 0; y < height; y++){
          for(int x = 0; x < width; x++){
            int p = img.getRGB(x,y);

            int a = (p>>24)&0xff;
            int r = (p>>16)&0xff;
            int g = (p>>8)&0xff;
            int b = p&0xff;

            //calculate average
            int avg = (r+g+b)/3;

            //replace RGB value with avg
            p = (a<<24) | (avg<<16) | (avg<<8) | avg;

            img.setRGB(x, y, p);
          }
        }
       return img;
   }
}

这是我所说的噪音示例:

莉娜的照片:

我不知道为什么我会听到这些噪音。 任何建议表示赞赏。

您必须进行以下更改:

卷积中取绝对值

   private static int convolution (int [] kernel, int [] pixel){
       int result = 0; 

       for (int i = 0; i < pixel.length; i++){
           result += kernel[i] * pixel[i];
       }

       return (int)(Math.abs(result) / 9);
   }

在 edgeDetection 中将值应用于所有三个通道

    private static BufferedImage edgeDetection(BufferedImage img, int[] kernel){
       int height = img.getHeight();
       int width = img.getWidth();

       BufferedImage result = new BufferedImage(width -1, height -1, BufferedImage.TYPE_INT_RGB);
       for(int x = 1; x < width -1 ; x++){
           for(int y = 1; y < height - 1; y++){
               int [] tmp = {img.getRGB(x-1, y-1)&0xff,img.getRGB(x, y-1)&0xff,img.getRGB(x+1, y-1)&0xff,
               img.getRGB(x-1, y)&0xff,img.getRGB(x, y)&0xff,img.getRGB(x+1, y)&0xff,img.getRGB(x-1, y+1)&0xff,
               img.getRGB(x, y+1)&0xff,img.getRGB(x+1, y+1)&0xff};
               int value = convolution (kernel, tmp);
               result.setRGB(x,y, 0xff000000|(value<<16)|(value<<8)|value);
           }
       }
       return result;
   }

最后将图像声明为 INT_RGB 类型

BufferedImage result = new BufferedImage(edgesX.getWidth(), edgesX.getHeight(), BufferedImage.TYPE_INT_RGB);

BufferedImage result = new BufferedImage(width -1, height -1, BufferedImage.TYPE_INT_RGB);