【问题标题】:Awkward image after applying the Sobel operator - java应用 Sobel 运算符后的尴尬图像 - java
【发布时间】:2013-12-14 22:26:17
【问题描述】:

经过深入搜索后,我无法理解为什么我的结果图像与来自维基百科的图像相比不是我所期望的 - sobel 运算符使用相同的内核作为 Sobel 运算符。

http://s29.postimg.org/kjex7dx6f/300px_Valve_original_1.png

http://s14.postimg.org/vxhvffm29/Untitled.png

所以,我有一个按钮监听器,可以加载 bmp 图像、应用 Sobel 并显示 ImageIcon 有代码:

javax.swing.JFileChooser choose = new javax.swing.JFileChooser();

choose.setFileFilter(new DoFileFilter(".bmp"));
int returnVal = choose.showOpenDialog(this);

if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
    try {
        java.io.FileInputStream imgis = null;
        // System.out.println("Ai ales fisierul : " +
        // choose.getSelectedFile());
        String path = choose.getSelectedFile().toString();
        Path.setText(path);

        imgis = new java.io.FileInputStream(path);

        java.awt.image.BufferedImage img = javax.imageio.ImageIO.read(imgis);

        DirectImgToSobel ds = new DirectImgToSobel(img);
        javax.swing.ImageIcon image;
        image = new javax.swing.ImageIcon(ds.getBuffImg());
        ImgPrev.setIcon(image);

        javax.swing.JFrame frame = (javax.swing.JFrame) javax.swing.SwingUtilities.getWindowAncestor(jPanel1);

        frame.pack();
        frame.repaint();
    } catch (FileNotFoundException ex) {
        Logger.getLogger(Display.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(Display.class.getName()).log(Level.SEVERE, null, ex);
    }
}

还有索贝尔课:

public class DirectImgToSobel {
    private final java.awt.image.BufferedImage img;
    private java.awt.image.BufferedImage buffimg;
    private int[][]
        sobel_x = { { -1,  0,  1 }, { -2, 0, 2 }, { -1, 0, 1 } },
        sobel_y = { { -1, -2, -1 }, {  0, 0, 0 }, {  1, 2, 1 } };

    public DirectImgToSobel() {
        this.img = null;
    }

    public DirectImgToSobel(java.awt.image.BufferedImage img) {

        this.img = img;
        aplicaFiltru();
    }

    private void aplicaFiltru() {

        this.buffimg = new java.awt.image.BufferedImage(this.img.getWidth(), this.img.getHeight(),
                java.awt.image.BufferedImage.TYPE_BYTE_GRAY);
        for (int x = 1; x < this.img.getWidth() - 1; x++) {
            for (int y = 1; y < this.img.getHeight() - 1; y++) {
                int pixel_x = 
              (sobel_x[0][0] * img.getRGB(x-1,y-1)) + (sobel_x[0][1] * img.getRGB(x,y-1)) + (sobel_x[0][2] * img.getRGB(x+1,y-1)) +
              (sobel_x[1][0] * img.getRGB(x-1,y))   + (sobel_x[1][1] * img.getRGB(x,y))   + (sobel_x[1][2] * img.getRGB(x+1,y)) +
              (sobel_x[2][0] * img.getRGB(x-1,y+1)) + (sobel_x[2][1] * img.getRGB(x,y+1)) + (sobel_x[2][2] * img.getRGB(x+1,y+1));
                int pixel_y = 
              (sobel_y[0][0] * img.getRGB(x-1,y-1)) + (sobel_y[0][1] * img.getRGB(x,y-1)) + (sobel_y[0][2] * img.getRGB(x+1,y-1)) +
              (sobel_y[1][0] * img.getRGB(x-1,y))   + (sobel_y[1][1] * img.getRGB(x,y))   + (sobel_y[1][2] * img.getRGB(x+1,y)) +
              (sobel_y[2][0] * img.getRGB(x-1,y+1)) + (sobel_y[2][1] * img.getRGB(x,y+1)) + (sobel_y[2][2] * img.getRGB(x+1,y+1));
                this.buffimg.setRGB(x, y, (int) Math.sqrt(pixel_x * pixel_x + pixel_y * pixel_y));
            }
        }

        buffimg = thresholdImage(buffimg, 28);

        java.awt.Graphics g = buffimg.getGraphics();
        g.drawImage(buffimg, 0, 0, null);
        g.dispose();
    }

    public java.awt.image.BufferedImage getBuffImg() {

        return this.buffimg;
    }

    public static java.awt.image.BufferedImage thresholdImage(java.awt.image.BufferedImage image, int threshold) {

        java.awt.image.BufferedImage result = new java.awt.image.BufferedImage(image.getWidth(), image.getHeight(),
                java.awt.image.BufferedImage.TYPE_BYTE_GRAY);

        result.getGraphics().drawImage(image, 0, 0, null);
        java.awt.image.WritableRaster raster = result.getRaster();

        int[] pixels = new int[image.getWidth()];

        for (int y = 0; y < image.getHeight(); y++) {
            raster.getPixels(0, y, image.getWidth(), 1, pixels);
            for (int i = 0; i < pixels.length; i++) {
                if (pixels[i] < threshold)
                    pixels[i] = 0;
                else
                    pixels[i] = 255;
            }
            raster.setPixels(0, y, image.getWidth(), 1, pixels);
        }
        return result;
    }
}

【问题讨论】:

    标签: java swing


    【解决方案1】:

    改变图像类型

    TYPE_BYTE_GRAYTYPE_INT_RGB

    使用正确的颜色通道进行卷积

    sobel_x[0][0] * new Color(img.getRGB(x-1,y-1)).getBlue()

    将卷积后的颜色打包成位压缩的RGB,并设置颜色

    int packedRGB=(int)Math.sqrt(pixel_x*pixel_x+pixel_y*pixel_y); packedRGB=(packedRGB << 16 | packedRGB << 8 | RGB); this.buffimg.setRGB(x, y, packedRGB);

    卷积只接受 1 个颜色通道,可以是 r,g,b 或灰色 [(r+g+b)/3],并返回一个颜色通道,这就是为什么你必须将其打包回位压缩 RGB , 因为BufferedImage.setColor() 只采用位压缩 RGB。

    我的代码

    `

    static BufferedImage inputImg,outputImg;
    static int[][] pixelMatrix=new int[3][3];
    
    public static void main(String[] args) {
        try {
    
            inputImg=ImageIO.read(new File("your input image"));
            outputImg=new BufferedImage(inputImg.getWidth(),inputImg.getHeight(),TYPE_INT_RGB);
    
            for(int i=1;i<inputImg.getWidth()-1;i++){
                for(int j=1;j<inputImg.getHeight()-1;j++){
                    pixelMatrix[0][0]=new Color(inputImg.getRGB(i-1,j-1)).getRed();
                    pixelMatrix[0][1]=new Color(inputImg.getRGB(i-1,j)).getRed();
                    pixelMatrix[0][2]=new Color(inputImg.getRGB(i-1,j+1)).getRed();
                    pixelMatrix[1][0]=new Color(inputImg.getRGB(i,j-1)).getRed();
                    pixelMatrix[1][2]=new Color(inputImg.getRGB(i,j+1)).getRed();
                    pixelMatrix[2][0]=new Color(inputImg.getRGB(i+1,j-1)).getRed();
                    pixelMatrix[2][1]=new Color(inputImg.getRGB(i+1,j)).getRed();
                    pixelMatrix[2][2]=new Color(inputImg.getRGB(i+1,j+1)).getRed();
    
                    int edge=(int) convolution(pixelMatrix);
                    outputImg.setRGB(i,j,(edge<<16 | edge<<8 | edge));
                }
            }
    
            File outputfile = new File("your output image");
            ImageIO.write(outputImg,"jpg", outputfile);
    
        } catch (IOException ex) {System.err.println("Image width:height="+inputImg.getWidth()+":"+inputImg.getHeight());}
    }
    public static double convolution(int[][] pixelMatrix){
    
        int gy=(pixelMatrix[0][0]*-1)+(pixelMatrix[0][1]*-2)+(pixelMatrix[0][2]*-1)+(pixelMatrix[2][0])+(pixelMatrix[2][1]*2)+(pixelMatrix[2][2]*1);
        int gx=(pixelMatrix[0][0])+(pixelMatrix[0][2]*-1)+(pixelMatrix[1][0]*2)+(pixelMatrix[1][2]*-2)+(pixelMatrix[2][0])+(pixelMatrix[2][2]*-1);
        return Math.sqrt(Math.pow(gy,2)+Math.pow(gx,2));
    
    }
    

    `

    【讨论】:

      【解决方案2】:

      要获得与维基百科相同的结果,您必须这样做:

      1. 使用图像点的亮度而不是打包到返回 getRGB 的单个 int 的颜色。
      2. 标准化结果(将低值映射到黑色,将高值映射到白色)。

      编辑:我无意中发现了关于 Java 中 Sobel 过滤器的好文章:http://asserttrue.blogspot.ru/2010/08/smart-sobel-image-filter.html

      EDIT2:检查这个How to convert get.rgb(x,y) integer pixel to Color(r,g,b,a) in Java? 问题描述了如何从图像中提取颜色。

      但我的建议是做float brightness = (new Color(img.getRGB(x, y))).RGBtoHSB()[2]; 并将Sobel 应用于brightness

      关于你的阈值函数:你应该得到灰度图像,而不是黑白。

      喜欢:

      if (pixels[i] < threshold) pixels[i] = 0;
      else pixels[i] = (int)((pixels[i] - threshold)/(255.0 - threshold)*255.0);
      

      但是,同样,rgba 颜色表示不适合数学。

      通过查找最小和最大像素值并将(最小-最大)范围拉伸到(0-255)来改进规范化

      【讨论】:

      • 我不明白...你说我应该有红色、绿色、蓝色而不是getRGB,为什么?
      • 因为getRGB 返回位压缩整数,不适合算术运算。检查这个问题:stackoverflow.com/questions/2615522
      • 首先,感谢您的回答:)。我只是在下班后才开始工作,很抱歉我最近没有回复。我不知道如何从您的答案中使用单独的颜色。我已经更新了我的代码,但它在黑屏上显示了一堆点。另外,我已经实现了您答案中的代码,但仅在图像的右侧和下方显示了一个带,我无法理解逻辑。你能帮我一个伪代码或展示如何使用独立颜色吗?谢谢。
      • 我猜你没有收到关于答案编辑的通知(我是新来的)。这是我的失败,我应该在编辑后立即在这里写评论。希望能帮助您解决问题。
      • 另外,我修改了答案并进行了微编辑,以确保此处的浮点除法。
      猜你喜欢
      • 2013-01-26
      • 2018-03-19
      • 2015-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-22
      • 1970-01-01
      相关资源
      最近更新 更多