Java 输出为BuffereImage.TYPE_BYTE_BINARY的Sobel边缘检测

Java 输出为BuffereImage.TYPE_BYTE_BINARY的Sobel边缘检测,java,image-processing,edge-detection,sobel,Java,Image Processing,Edge Detection,Sobel,我正在做一个学校作业,我们应该在图像上做sobel边缘检测。我们应该对sobel核och进行卷积,然后计算每个像素的梯度幅度。然后,我们应该使用阈值方法根据阈值为像素指定值255(白色)或0(黑色)。来自边缘检测的输出图像必须为缓冲图像类型。类型为\u BYTE\u BINARY。我使用灰度图像作为输入,但最终结果看起来非常奇怪。。它绝对不会检测到边缘 我搜索了一下,找到了工作代码(,请看标记的正确答案),但是,这里的输出图像是BufferedImage.type_INT_RGB类型,这是不允许

我正在做一个学校作业,我们应该在图像上做sobel边缘检测。我们应该对sobel核och进行卷积,然后计算每个像素的梯度幅度。然后,我们应该使用阈值方法根据阈值为像素指定值255(白色)或0(黑色)。来自边缘检测的输出图像必须为缓冲图像类型。类型为\u BYTE\u BINARY。我使用灰度图像作为输入,但最终结果看起来非常奇怪。。它绝对不会检测到边缘

我搜索了一下,找到了工作代码(,请看标记的正确答案),但是,这里的输出图像是BufferedImage.type_INT_RGB类型,这是不允许的。。。在这个问题中,还使用BuffereImage.TYPE.INT.RGB作为边缘检测的输入

非常感谢您对解决此问题的帮助

执行程序时的结果。边缘检测结果位于最右侧。

边缘检测结果应该是什么样子。

我的代码:

/**
 * turns an image to a grayscale version of the image
 */
public void alterImageGrayScale() throws IOException {
    imageGrayScale = new BufferedImage(imageOriginal.getWidth(), imageOriginal.getHeight(), BufferedImage.TYPE_BYTE_GRAY);

    for(int i = 0; i < imageOriginal.getWidth(); i++) {
        for(int j = 0; j < imageOriginal.getHeight(); j++) {
            Color c = new Color(imageOriginal.getRGB(i, j));
            int red = c.getRed();
            int green = c.getGreen();
            int blue = c.getBlue();
            int gray = (int) (0.2126*red + 0.7152*green + 0.0722*blue);
            imageGrayScale.setRGB(i, j, new Color(gray, gray, gray).getRGB());
        }
    }
}

/**
 * edge detection
 * @throws IOException
 */
public void alterEdgeDetection() throws IOException {
    imageBlackAndWhite = new BufferedImage(imageGrayScale.getWidth(), imageGrayScale.getHeight(), BufferedImage.TYPE_INT_RGB);
    int x = imageGrayScale.getWidth();
    int y = imageGrayScale.getHeight();
    int threshold = 250;

    for (int i = 1; i < x - 1; i++) {
        for (int j = 1; j < y - 1; j++) {

            int val00 = imageGrayScale.getRGB(i - 1, j - 1);
            int val01 = imageGrayScale.getRGB(i - 1, j);
            int val02 = imageGrayScale.getRGB(i - 1, j + 1);
            int val10 = imageGrayScale.getRGB(i, j - 1);
            int val11 = imageGrayScale.getRGB(i, j);
            int val12 = imageGrayScale.getRGB(i, j + 1);
            int val20 = imageGrayScale.getRGB(i + 1, j - 1);
            int val21 = imageGrayScale.getRGB(i + 1, j);
            int val22 = imageGrayScale.getRGB(i + 1, j + 1);

            int gradientX = ((-1 * val00) + (0 * val01) + (1 * val02)) + ((-2 * val10) + (0 * val11) + (2 * val12))
                    + ((-1 * val20) + (0 * val21) + (1 * val22));
            int gradientY = ((-1 * val00) + (-2 * val01) + (-1 * val02)) + ((0 * val10) + (0 * val11) + (0 * val12))
                    + ((1 * val20) + (2 * val21) + (1 * val22));
            int gradientValue = (int) Math.sqrt(Math.pow(gradientX, 2) + Math.pow(gradientY, 2));

            //???? feel like something should be done here, but dont know what

            if(threshold > gradientValue) {
                imageBlackAndWhite.setRGB(i, j, new Color(0, 0, 0).getRGB());
            } else {
                imageBlackAndWhite.setRGB(i, j, new Color(255, 255, 255).getRGB());
            }

        }
    }
}
/**
*将图像转换为图像的灰度版本
*/
public void alterImageGrayScale()引发IOException{
imageGrayScale=new BuffereImage(imageOriginal.getWidth(),imageOriginal.getHeight(),BuffereImage.TYPE_BYTE_GRAY);
对于(int i=0;i梯度值){
setRGB(i,j,新颜色(0,0,0.getRGB());
}否则{
setRGB(i,j,新颜色(255,255,255).getRGB());
}
}
}
}

根据注释中的响应,将通过边缘检测计算的灰度图像转换为
类型为字节二进制的图像就足够了

下面是一个MCVE,它加载问题中链接到的灰度图像(包含边缘检测结果),并将其转换为二值图像

对于转换为二值图像,有一个阈值可以使用屏幕底部的滑块进行修改:它确定哪个灰度值将分别转换为黑色或白色像素

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;

public class ImageToBinary
{
    public static void main(String[] args) throws Exception
    {
        BufferedImage input = 
            ImageIO.read(new URL("https://i.stack.imgur.com/jvOan.png"));        

        BufferedImage output = convertToBinary(input, 10);

        SwingUtilities.invokeLater(() -> createAndShowGui(input, output));
    }

    private static void createAndShowGui(
        BufferedImage input, BufferedImage output)
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel p = new JPanel(new GridLayout(1,2));
        JLabel outputLabel = new JLabel(new ImageIcon(output));
        p.add(new JLabel(new ImageIcon(input)));    
        p.add(outputLabel);
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(p, BorderLayout.NORTH);   

        JSlider slider = new JSlider(0, 256, 10);
        slider.addChangeListener(e -> 
        {
            int threshold = slider.getValue();
            BufferedImage newOutput = convertToBinary(input, threshold);
            outputLabel.setIcon(new ImageIcon(newOutput));
        });

        f.getContentPane().add(slider, BorderLayout.SOUTH);
        f.pack();

        f.setLocationRelativeTo(null);
        f.setVisible(true);

    }

    private static BufferedImage convertToBinary(
        BufferedImage input, int threshold)
    {
        int w = input.getWidth();
        int h = input.getHeight();
        BufferedImage output = new BufferedImage(
            w, h, BufferedImage.TYPE_BYTE_BINARY);

        int blackRgb = Color.BLACK.getRGB();
        int whiteRgb = Color.WHITE.getRGB();

        for (int y = 0; y < h; y++)
        {
            for (int x = 0; x < w; x++)
            {

                int rgb = input.getRGB(x, y);
                int r = (rgb >> 16) & 0xFF;
                int g = (rgb >> 8) & 0xFF;
                int b = (rgb) & 0xFF;
                int gray = (int) (0.2126 * r + 0.7152 * g + 0.0722 * b);
                if (gray >= threshold)
                {
                    output.setRGB(x, y, whiteRgb);
                }
                else
                {
                    output.setRGB(x, y, blackRgb);
                }
            }
        }
        return output;
    }        

}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.GridLayout;
导入java.awt.image.buffereImage;
导入java.net.URL;
导入javax.imageio.imageio;
导入javax.swing.ImageIcon;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.JSlider;
导入javax.swing.SwingUtilities;
公共类ImageToBinary
{
公共静态void main(字符串[]args)引发异常
{
BuffereImage输入=
ImageIO.read(新URL(“https://i.stack.imgur.com/jvOan.png"));        
BuffereImage输出=convertToBinary(输入,10);
调用器(()->createAndShowGui(输入,输出));
}
私有静态void createAndShowGui(
BuffereImage输入,BuffereImage输出)
{
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p=新JPanel(新网格布局(1,2));
JLabel outputLabel=新JLabel(新图像图标(输出));
p、 添加(新JLabel(新图像图标(输入));
p、 添加(输出标签);
f、 getContentPane().setLayout(新的BorderLayout());
f、 getContentPane().add(p,BorderLayout.NORTH);
JSlider滑块=新JSlider(0,256,10);
slider.addChangeListener(e->
{
int threshold=slider.getValue();
BuffereImage newOutput=convertToBinary(输入,阈值);
setIcon(新图像图标(新输出));
});
f、 getContentPane().add(滑块,BorderLayout.SOUTH);
f、 包装();
f、 setLocationRelativeTo(空);
f、 setVisible(真);
}
专用静态缓冲区映像转换器二进制(
缓冲区图像输入,整数阈值)