【问题标题】:Convert buffered image to the 2D byte array with the same data将缓冲图像转换为具有相同数据的二维字节数组
【发布时间】:2013-09-01 10:36:49
【问题描述】:

我用 Java 编写了一个用于图像处理的应用程序。我已经处理了作为缓冲图像的图像,现在我想为处理后的图像返回byte[],我应该得到二值化图像的字节数组。

这是我的代码:

public static byte[][] binarizeImage(BufferedImage bfImage){

        int red;
        int newPixel;
        int h ;
        int w ;
        int threshold = otsuTreshold(bfImage);   
          // this function returns the threshold value 199

        BufferedImage binarized = new BufferedImage(bfImage.getWidth(), bfImage.getHeight(), bfImage.getType());

        for(int i=0; i<bfImage.getWidth(); i++) {
        for(int j=0; j<bfImage.getHeight(); j++) {

            // Get pixels
            red = new Color(bfImage.getRGB(i, j)).getRed();
            int alpha = new Color(bfImage.getRGB(i, j)).getAlpha();
            if(red > threshold) {
                newPixel = 255;
            }
            else {
                newPixel = 0;
            }
            newPixel = colorToRGB(alpha, newPixel, newPixel, newPixel);
            binarized.setRGB(i, j, newPixel); 
       }

     }
          Raster raster  = binarized.getData();

    h = raster.getHeight();
    w = raster.getWidth();

    byte[][] binarize_image = new byte[w][h];

    for(int i=0 ; i<w ; i++)
    {
        for(int j=0; j<h ; j++)
        {
            binarize_image[i][j]=raster.getSampleModel();  //error at this line 
        }
   }
   return binarize_image;
}

// Convert R, G, B, Alpha to standard 8 bit
    private static int colorToRGB(int alpha, int red, int green, int blue) {

        int newPixel = 0;
        newPixel += alpha;
        newPixel = newPixel << 8;
        newPixel += red; newPixel = newPixel << 8;
        newPixel += green; newPixel = newPixel << 8;
        newPixel += blue;

        return newPixel;

    }

但它不起作用。我应该怎么做才能将该缓冲图像转换为相同图像数据的字节数组?

【问题讨论】:

  • 转换后您希望binarize_image 包含什么内容?每像素 8 位黑/白 + 8 位 alpha?如果是这样,您希望如何将其存储为每像素 8 位?这并不是我所认为的二进制,但你可能正在创造一种艺术效果?在任何情况下,您都可以不使用临时的binarized 图像,只需在第一个循环中直接将值设置为binarize_image
  • 编写代码的主要目的是只想将灰度图像转换为二值化图像。我正在尝试使用上面的代码。
  • 什么是“二值化”图像?你的意思是二进制,只有黑/白?你的输入图像总是灰色的吗? 8 位?
  • 是二值化图像是指黑白图像

标签: java image image-processing bytearray bufferedimage


【解决方案1】:

我不确定“二值化”一词在这种情况下的含义。您似乎只想过滤图像(即根据某个阈值切断红色通道)并将结果转换为byte[]

假设上面是正确的然后检查下面的代码。它将图像转换为byte[] 用于 32 位图像。请注意以下几点:

  • 您不需要先过滤图像,然后再转换为byte[]。您可以在转换期间执行此操作。
  • “将 RGB 转换为标准 8 位”:如果您的意思是 每个颜色通道 8 位,那么这没问题,但如果您的意思是 每个像素 8 位 那么您在谈论压缩/转换(即您可能会丢失一些信息/质量),在这种情况下您应该提供有关您想要实现的目标的更多信息。
  • 假设我们讨论的是 32 位图像的情况,您得到的 byte[] 的大小将是 4 * width * height 而不是 width * height。如果您需要处理其他情况,则应考虑BufferedImage 支持的可用图像类型(或至少只考虑您感兴趣的图像类型)。

下面的代码将打印每个转换像素的信息,如下所示(注意红色通道是如何过滤的):

[0,0] Converting [ffaaccee] --&gt; [0, cc, ee, ff]

package imageio.byteconversion;

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

public class BufferedImageToBytes {

    private static void log(String s) {
        System.out.println(s);
    }

    private static String toByteString(int color) {
        // Perform a bitwise AND for convenience while printing. 
        // Otherwise Integer.toHexString() interprets values as integers and a negative byte 0xFF will be printed as "ffffffff"
        return Integer.toHexString(color & 0xFF);
    }

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

        // Load the image. This expects the image to be in the same package with this class 
        InputStream stream = BufferedImageToBytes.class.getResourceAsStream("test.png");
        BufferedImage image = ImageIO.read(stream);
        int iw = image.getWidth();
        int ih = image.getHeight();
        log("Image loaded succesfully, width=" + iw + " height=" + ih);
        stream.close();

        log("Image color model: " + image.getColorModel());
        log("Image sample model: " + image.getSampleModel());
        log("Image raster: " + image.getRaster());

        int bands = image.getSampleModel().getNumBands();
        log("Color bands: " + bands);
        if (bands != 4) {
            throw new RuntimeException("The image does not have 4 color bands. Are you sure this is a 32-bit image?");
        }

        int threshold = 199; // <-- decide your threshold here

        byte bytes[] = new byte[4 * iw * ih];
        int index = 0;

        // note that image is processed row by row top to bottom
        for(int y = 0; y < ih; y++) {
            for(int x = 0; x < iw; x++) {

                // returns a packed pixel where each byte is a color channel
                // order is the default ARGB color model
                int pixel = image.getRGB(x, y);

                // Get pixels
                int alpha = (pixel >> 24) & 0xFF;
                int red = (pixel >> 16) & 0xFF;
                int green = (pixel >> 8) & 0xFF;
                int blue = pixel & 0xFF;

                // perform filtering here depending on threshold 
                if (red > threshold) {
                   red = 255;
                } else {
                    red = 0;
                }

                log("[" + x + "," + y + "]" + " Converting [" + Integer.toHexString(pixel)  + "] --> ["
                        + toByteString(red) + ", " + toByteString(green) + ", " 
                        + toByteString(blue) + ", " + toByteString(alpha)
                        + "]");

                bytes[index++] = (byte) red;
                bytes[index++] = (byte) green;
                bytes[index++] = (byte) blue;
                bytes[index++] = (byte) alpha;
           }
        }
    }
}

【讨论】:

  • 感谢您的回复。我只是想对灰度图像进行二值化,所以上面的代码就是为此。
  • @rachana 你说的 "binarize" 是什么意思?转换为byte[]?如果是,那么上面的代码将起作用(尽管您可能会节省更多空间)只需删除引发异常的检查即可。要将其转换为灰色图像吗?请说明您使用什么图像作为来源以及您想要的输出是什么
  • 二值化图像意味着我想将灰度图像转换为黑白格式,这就是我试图用该代码做的事情,并且在二值化之后我想将二值化缓冲图像转换为字节数组处理图像的其他操作需要字节数组。
  • 如果您知道任何图像二值化算法,请告诉我。
  • @rachana 检查this link。它有一个可能适合您的情况的 java 演示
【解决方案2】:

您为什么不尝试使用库作为 Catalano 框架。 http://code.google.com/p/catalano-framework/

FastBitmap fb = new FastBitmap("c:\\files\\image.jpg");
fb.toGrayscale();

OtsuThreshold otsu = new OtsuThreshold();
otsu.applyInPlace(fb);

int[][] image = new int[fb.getHeight()][fb.getWidth()];
fb.toArrayGray(image);

【讨论】:

    【解决方案3】:

    怎么样:

    BufferedImage input;
    
    BufferedImage binary = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
    
    Graphics2D g = binary.createGraphics();
    try {
        g.drawImage(input, 0, 0, null);
    }
    finally {
       g.dispose();
    }
    

    它不会使用您的otsuTreshold,它会(可能)抖动图像,但它会使用最少的内存完成使其成为二进制(仅黑色/白色)的工作。

    【讨论】:

      【解决方案4】:
        try {
                        // get the BufferedImage, using the ImageIO class
                        Bitmap image = 
                          BitmapFactory.decodeStream(getAssets()
                                  .open("aa.bmp"));
                        marchThroughImage(image);
                      } catch (IOException e) {
                        System.err.println(e.getMessage());
                      }
              }
          });
      
      
      }
      public void printPixelARGB(int pixel) {
          int alpha = (pixel >> 24) & 0xff;
          int red = (pixel >> 16) & 0xff;
          int green = (pixel >> 8) & 0xff;
          int blue = (pixel) & 0xff;
          System.out.println("argb: " + alpha + ", " + red + ", " + green + ", " + blue);
        }
      private void marchThroughImage(Bitmap image) {
          int w = image.getWidth();
          int h = image.getHeight();
          System.out.println("width, height: " + w + ", " + h);
      
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              System.out.println("x,y: " + j + ", " + i);
              int pixel = image.getPixel(j, i);
              printPixelARGB(pixel);
              System.out.println("");
            }
          }
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-06
        • 1970-01-01
        • 2021-07-21
        • 1970-01-01
        • 2015-08-23
        • 1970-01-01
        • 2013-12-06
        • 2020-06-12
        相关资源
        最近更新 更多