当前位置: 首页 > 知识库问答 >
问题:

如何为3个样本的32位图像数据创建BufferedImage

厉令
2023-03-14

我试图创建一个BufferedImage从一些图像数据,这是一个字节数组。图像是RGB格式,每像素3个样本-R、G和B,每个样本32位(对于每个样本,不是所有3个样本)。

现在我想从这个字节数组创建一个BufferedImage。这就是我所做的:

        ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {32, 32, 32}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_INT);
        Object tempArray = ArrayUtils.toNBits(bitsPerSample, pixels, samplesPerPixel*imageWidth, endian == IOUtils.BIG_ENDIAN);
        WritableRaster raster = cm.createCompatibleWritableRaster(imageWidth, imageHeight);
        raster.setDataElements(0, 0, imageWidth, imageHeight, tempArray); 
        BufferedImage bi = new BufferedImage(cm, raster, false, null);

上面的代码工作在24位每个样本的RGB图像,但不是32位每个样本。生成的图像是垃圾,显示在图像的右侧。它应该像图像的左边。

使用传输类型databuffer.type_byte、databuffer.type_ushort和databuffer.type_int创建的ComponentColorModel实例具有像素样本值,这些值被视为无符号整数值。

上面的引用来自Java文档ComponentColorModel。这意味着32位样本将被视为无符号整数值。那么问题可能出在别的地方。

是否有任何身体遇到类似的问题,并得到了一个变通办法,或者我可能做了一些错误的事情在这里?

更新:从HaraldK的回答和评论中,我们最终同意问题来自Java的ComponentColorModel,它没有正确处理32位示例。HaraldK提出的解决方案也适用于我的情况。以下是我的版本:

import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;

public class Int32ComponentColorModel extends ComponentColorModel {
   //
   public Int32ComponentColorModel(ColorSpace cs, boolean alpha) {
        super(cs, alpha, false, alpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, DataBuffer.TYPE_INT);
   }

   @Override
   public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) {
       int numComponents = getNumComponents();

       if (normComponents == null || normComponents.length < numComponents + normOffset) {
           normComponents = new float[numComponents + normOffset];
       }

       switch (transferType) {
           case DataBuffer.TYPE_INT:
               int[] ipixel = (int[]) pixel;
               for (int c = 0, nc = normOffset; c < numComponents; c++++, nc++) {
                   normComponents[nc] = ipixel[c] / ((float) ((1L << getComponentSize(c)) - 1));
               }
               break;
           default: // I don't think we can ever come this far. Just in case!!!
               throw new UnsupportedOperationException("This method has not been implemented for transferType " + transferType);
       }

       return normComponents;
   }
}

共有1个答案

井宪
2023-03-14

更新:

这似乎是一个已知的bug:componentcolormodel.getnormalizedcomponents()不处理32位TYPE_INT,reported 10(ten!)几年前,反对Java5。

好处是,Java现在部分是开源的。我们现在可以提出一个补丁,如果运气好的话,它将被评估为Java9左右...:-P

private static class TypeIntComponentColorModel extends ComponentColorModel {
    public TypeIntComponentColorModel(final ColorSpace cs, final boolean alpha) {
        super(cs, alpha, false, alpha ? TRANSLUCENT : OPAQUE, DataBuffer.TYPE_INT);
    }

    @Override
    public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) {
        int numComponents = getNumComponents();

        if (normComponents == null) {
            normComponents = new float[numComponents + normOffset];
        }

        switch (transferType) {
            case DataBuffer.TYPE_INT:
                int[] ipixel = (int[]) pixel;
                for (int c = 0, nc = normOffset; c < numComponents; c++, nc++++++) {
                    normComponents[nc] = ((float) (ipixel[c] & 0xffffffffl)) / ((float) ((1l << getComponentSize(c)) - 1));
                }
                break;
            default:
                throw new UnsupportedOperationException("This method has not been implemented for transferType " + transferType);
        }

        return normComponents;
    }
}

考虑下面的代码。如果按原样运行,对我来说,它显示的是一个主要是黑色的图像,右上角的四分之一白色覆盖了一个黑色的圆圈。如果我将datatype更改为type_ushort(取消对transfertype行的注释),它将显示半/半白色和从黑到白的线性渐变,中间有一个橙色圆圈(应该如此)。

使用ColorConvertop转换为标准类型似乎没有什么不同。

public class Int32Image {
    public static void main(String[] args) {
        // Define dimensions and layout of the image
        int w = 300;
        int h = 200;
        int transferType = DataBuffer.TYPE_INT;
//        int transferType = DataBuffer.TYPE_USHORT;

        ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, Transparency.OPAQUE, transferType);
        WritableRaster raster = colorModel.createCompatibleWritableRaster(w, h);
        BufferedImage image = new BufferedImage(colorModel, raster, false, null);

        // Start with linear gradient
        if (raster.getTransferType() == DataBuffer.TYPE_INT) {
            DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer();
            int[] data = buffer.getData();

            for (int y = 0; y < h; y++) {
                int value = (int) (y * 0xffffffffL / h);

                for (int x = 0; x < w; x++) {
                    int offset = y * w * 3 + x * 3;
                    data[offset] = value;
                    data[offset + 1] = value;
                    data[offset + 2] = value;
                }
            }
        }
        else if (raster.getTransferType() == DataBuffer.TYPE_USHORT) {
            DataBufferUShort buffer = (DataBufferUShort) raster.getDataBuffer();
            short[] data = buffer.getData();

            for (int y = 0; y < h; y++) {
                short value = (short) (y * 0xffffL / h);

                for (int x = 0; x < w; x++) {
                    int offset = y * w * 3 + x * 3;
                    data[offset] = value;
                    data[offset + 1] = value;
                    data[offset + 2] = value;
                }
            }
        }

        // Paint something (in  color)
        Graphics2D g = image.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, w / 2, h);
        g.setColor(Color.ORANGE);
        g.fillOval(100, 50, w - 200, h - 100);
        g.dispose();

        System.out.println("image = " + image);

//        image = new ColorConvertOp(null).filter(image, new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB));

        JFrame frame = new JFrame();
        frame.add(new JLabel(new ImageIcon(image)));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

对我来说,这似乎表明colormodel使用transferTypetype_int有问题。但我很乐意错了。;-)

 类似资料:
  • 我的任务是: 创建一个TBitmap对象 如何在Delphi XE中做到这一点?

  • 如果想预先生成一组空的canvas数据,则可调用context.createImageData(sw, sh),这个函数可以创建一组图像数据并绑定在canvas对象上。这组数据可以像先前那样处理,只是在获取canves数据时,这组图像数据不一定会反映canvas的当前状态。

  • 我在最新的Vue CLI 3上有一个简单的Vue项目(我在这两方面都是新手)。在src中,我有100%质量的jpg/png图像。默认情况下,cli while build将使用my images创建dist目录,并添加哈希(image.jpg到image.7a97ca45.jpg),但不进行任何压缩。 所以我添加了imagemin网页包插件、imagemin mozjpeg和imagemin pn

  • 问题内容: 是否有任何的组合和我可以为了建立ELF 32位二进制设定值? 问题答案: 和。 更多示例:体系结构: 作业系统: 有关完整列表(有效的“个体”值),请参考文件: 请注意,以上列表是一个不断增长的列表,不再删除不再受支持的平台(因为该列表用于go / build文件名匹配)。 对于当前列表,所有受支持的平台(GOOS / GOARCH组合),请使用以下命令: + (source)的有效组

  • 我是第一次使用openCV。我正在使用openCV3和XCode对其进行编码。我想创建一个16位的灰度图像,但我想我有的数据是这样定义的,4000是像素值为白色和0为黑色。我在int类型的数组中有这些像素的信息。如何创建Mat并将数组中的值分配给Mat?

  • 我正在编写一个图像处理应用程序,使用javafx作为gui,我想在屏幕上显示处理过的图片。我的程序将图像处理为三维双数组,如double[3][1080][1920],因此我必须减少图像的颜色空间,并将双数组转换为byte或(如果可能)shorts,因为javafx的ImageView不支持浮点值或每个RGB组件的64位。我发现,Imageview只能从文件或inputstream加载数据,因此我