【问题标题】:Sobel edge detection creates noiseSobel 边缘检测会产生噪声
【发布时间】:2018-07-17 04:15:35
【问题描述】:

我尝试在 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;
   }
}

这是我所说的噪音的一个例子:

莉娜的形象:

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

【问题讨论】:

    标签: java computer-vision bufferedimage sobel


    【解决方案1】:

    您必须进行以下更改:

    在卷积中取绝对值

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

    【讨论】:

    • 我发现更改所有三个频道的成本很高。是否可以将图像转换为 2d 0-255 灰度图像并且只更改 x 和 y 的值?
    • 如果您使用 getRaster 等,这将是一项更加复杂的工作,但它会更快 - 为了立即获得结果,除非您打算创建一个数组 a[][],否则我什么也看不到。如果您尝试,请提出另一个问题
    • 你也可以使用这个 result.setRGB(x,y, value);这将创建蓝色图像
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 2011-02-25
    • 2021-06-02
    • 2020-04-06
    • 1970-01-01
    • 2011-02-15
    • 2016-11-07
    相关资源
    最近更新 更多