【问题标题】:Extract then stack the high and low bytes from an array of image bytes从图像字节数组中提取然后堆叠高字节和低字节
【发布时间】:2017-05-01 11:03:20
【问题描述】:

我对字节级别的图像压缩比较陌生,目前正在研究一个 java 图像预处理器,它将获取 bmp 图像,将其转换为 8 位无符号灰度,然后根据高位堆叠其字节在导出和压缩之前低。经过一些广泛的研究和测试各种字节提取方法后,我仍然没有看到我需要的结果。在继续之前,需要注意的是,所有这些图像最初都是 DICOM 格式,我使用 ij.plugin.DICOM 包将像素数据提取为 bmp 图像。

下面的描述由下面的代码表示。目前,我正在将原始图像作为缓冲图像读取,将其转换为灰度,然后从光栅中获取图像字节。然后我获取这些字节,并使用我在 stackoverflow 上找到的一些其他代码并将它们“转换”为二进制位的字符串表示形式。然后我将该字符串发送到字符数组。下一步可能是无关紧要的,但我想在删除它之前获得您的意见(因为我是新手)。我制作了一个 Bitset 并遍历“二进制”字符数组。如果字符值为“1”,我将 BitSet 中的该位置设置为 true。然后我将 BitSet 发送到另一个字节数组。

然后我创建了两个新的字节数组,一个用于高字节,一个用于低字节。使用 for 循环,我遍历“位”数组并在高字节或低字节中存储每 4 个“位”,具体取决于我们在数组中的位置。

最后,我将 DICOM 标签数据,从中制作一个字节数组,然后将标签数组、高字节数组和低字节数组堆叠在一起。我的预期结果是让图像矩阵被“拆分”,上半部分包含所有高字节,下半部分包含所有低字节。我被告知标签字节会非常小,它们不应该影响最终结果(为了确定,我已经测试了没有它们的图像,并且没有明显的差异)。

下面是代码。如果您有任何问题,请告诉我,我会相应地修改我的帖子。我试图包括所有相关数据。如果您需要更多,请告诉我。

        BufferedImage originalImage = getGrayScale(img.getBufferedImage());//returns an 8-bit unsigned grayscale conversion of the original image
        byte[] imageInByte = ((DataBufferByte) originalImage.getRaster().getDataBuffer()).getData();
        String binary = toBinary(imageInByte); //converts to a String representation of the binary bits
        char[] binCharArray = binary.toCharArray();
        BitSet bits = new BitSet(binCharArray.length);
        for (int i = 0; i < binCharArray.length; i++) {
            if (binCharArray[i] == '1') {
                bits.set(i);
            }
        }
        imageInByte = bits.toByteArray();

        byte[] high = new byte[(int) imageInByte.length/2];
        byte[] low = new byte[(int) imageInByte.length/2];

        int highC = 0;
        int lowC = 0;
        boolean change = false; //start out storing in the high bit
        //change will = true on very first run. While true, load in the high byte array. Else low byte
        for(int i = 0; i < imageInByte.length; i++){
            if(i % 4 == 0){
                change = !change;
            }
            if(change){
                high[highC] = imageInByte[i];
                highC++;
            } else {
                low[lowC] = imageInByte[i];
                lowC++;
            }
        }
        //old code from a previous attempt. 
     // for (int j = 0; j < imageInByte.length; j++) {
     //       byte h = (byte) (imageInByte[j] & 0xFF);
     //       byte l = (byte) ((imageInByte[j] >> 8) & 0xFF);
     //       high[j] = h;
     //       low[j] = l;
     // }

        OutputStream out = null;
        //add this array to the image array. It goes at the beginning.
        byte[] tagBytes = dicomTags.getBytes();
        currProcessingImageTagLength = tagBytes.length;
        imageInByte = new byte[high.length + low.length + tagBytes.length];
        System.arraycopy(tagBytes, 0, imageInByte, 0, tagBytes.length);
        System.arraycopy(high, 0, imageInByte, tagBytes.length, high.length);
        System.arraycopy(low, 0, imageInByte, tagBytes.length + high.length, low.length);

        BufferedImage bImageFromConvert = new BufferedImage(dimWidth, dimHeight, BufferedImage.TYPE_BYTE_GRAY);//dimWidth and dimHeight are the image dimensions, stored much earlier in this function
        byte[] bufferHolder = ((DataBufferByte) bImageFromConvert.getRaster().getDataBuffer()).getData();
        System.arraycopy(imageInByte, 0, bufferHolder, 0, bufferHolder.length);
     //This is where I try and write the final image before sending it off to an image compressor
        ImageIO.write(bImageFromConvert, "bmp", new File(
                directory + fileName + "_Compressed.bmp"));
        return new File(directory + fileName + "_Compressed.bmp");

如果您感兴趣,下面是 toBinary 函数:

  private static String toBinary(byte[] bytes) {
    StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
    for (int i = 0; i < Byte.SIZE * bytes.length; i++) {
        sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
    }
    return sb.toString();
}

非常感谢您的帮助!我现在已经花了将近 20 个小时试图解决这个问题。这是一个非常令人头疼的问题,如果您有任何见解,我们将不胜感激。

编辑:这是 getGreyScale 函数:

public static BufferedImage getGrayScale(BufferedImage inputImage) {
    BufferedImage img = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
    Graphics g = img.getGraphics();
    g.drawImage(inputImage, 0, 0, null);
    g.dispose();
    return img;
}

编辑 2:我根据要求添加了一些图片。

当前输出:

current image

请注意,由于我的声誉低于 10,我无法发布具有“预期”高字节和低字节结果的图像。

【问题讨论】:

  • a)" 将图像矩阵“拆分”,上半部分包含所有高字节,下半部分包含所有低字节。”:所以你想要高部分在图像的上部聚集在一起的所有字节?预期的结果是什么? b)也许这一切都与我一无所知的dicom有关,但被认为是简单的处理步骤,它应该是你所期望的和你得到的
  • @gpasch a) 是的。图像应显示为所有高字节在顶部聚集,所有低字节在底部聚集。换句话说,最终的图像应该是原始尺寸,但图像的上半部分是迷你亮图像,下半部分是迷你暗图像。 b) 出于所有意图和目的,在处理 DICOM 时,它应该作为正常的 bmp 运行。

标签: java image byte preprocessor data-extraction


【解决方案1】:

这表示每 4 个字节更改一次;这不是你想要的:

    for(int i = 0; i < imageInByte.length; i++){
        if(i % 4 == 0){
            change = !change;
        }
        if(change){
            high[highC] = imageInByte[i];
            highC++;
        } else {
            low[lowC] = imageInByte[i];
            lowC++;
        }
    }

我会用你之前的尝试替换它

  for (int j = 0; j < imageInByte.length; j+=2) {
        byte h = (byte) (imageInByte[j] & 0xF0);
        byte h2 = (byte) (imageInByte[j+1] & 0xF0);
        byte l = (byte) (imageInByte[j] & 0x0f);
        byte l2 = (byte) (imageInByte[j+1] & 0x0f);
        high[j/2] = h|(h2>>4);
        low[j/2] = (l<<4)|l2;
  }

【讨论】:

  • 嗯,它看起来确实更接近我的需要,但还是有点偏离。让我看一下代码,确保这不是我在做的事情。
  • 有第一部分 toGray 我不知道它是如何工作的以及它是否正确;然后中间的位有很多摆弄 - 你有二进制文件,我不知道为什么你需要所有这些到 String 并返回 - 最后你可以尝试在压缩之前将图像显示为 JFrame 等以确保它是视觉上你所期望的
  • 将功能添加到问题中,以便您查看。我不确定是否需要 String 和 back 部分。我只是不完全清楚Java如何处理二进制位,或者它是否处理二进制位,并且想确定一下。你认为它会抑制我的代码吗?
  • 稍后我会检查代码,看看它是如何工作的——它不会抑制,只是可能会隐藏一些错误
  • 我不知道你为什么说“有点不对劲”——这似乎对我有用(我排除了我不想要也不会弄乱的 dicom 标签)——否则发布示例图像来说明你所期望的 - 一切顺利
猜你喜欢
  • 1970-01-01
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
  • 2015-04-14
相关资源
最近更新 更多