gpt4 book ai didi

java - 16 位 DICOM 图像的像素数据到 BufferedImage

转载 作者:行者123 更新时间:2023-11-29 04:33:23 25 4
gpt4 key购买 nike

我有一个字节数组,用于存储来自已解构的 DICOM 文件的 16 位像素数据。我现在需要做的是以某种方式将该像素数据转换/导出为 TIFF 文件格式。我正在使用 imageio-tiff-3.3.2.jar 插件来处理 tiff 转换/ header 数据。但是现在我需要将该图像数据数组打包到原始图像尺寸的 BufferedImage 中,以便可以将其导出为 TIFF。但 BufferedImage 似乎不支持 16 位图像。有没有办法解决这个问题,比如外部库?还有另一种方法可以将该图像数据打包成原始 DICOM 尺寸的 TIFF 图像吗?请记住,此过程必须完全无损。在过去的几天里,我环顾四周并尝试了一些方法,但到目前为止,没有任何效果对我有用。

如果您有任何问题,或者我能做些什么来消除任何困惑,请告诉我。

编辑:预期和当前图像 enter image description here

最佳答案

给定原始字节数组的输入数据,其中包含无符号的 16 位图像数据,这里有两种创建 BufferedImage 的方法。

第一个会比较慢,因为它涉及将 byte 数组复制到 short 数组中。它还需要两倍的内存。好处是它创建了一个标准的 TYPE_USHORT_GRAY BufferedImage,显示速度可能更快并且可能更兼容。

private static BufferedImage createCopyUsingByteBuffer(int w, int h, byte[] rawBytes) {
short[] rawShorts = new short[rawBytes.length / 2];

ByteBuffer.wrap(rawBytes)
// .order(ByteOrder.LITTLE_ENDIAN) // Depending on the data's endianness
.asShortBuffer()
.get(rawShorts);

DataBuffer dataBuffer = new DataBufferUShort(rawShorts, rawShorts.length);
int stride = 1;
WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, w, h, w * stride, stride, new int[] {0}, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);

return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
}

创建速度更快的变体(以前的版本需要多花 4-5 倍的时间),但会生成 TYPE_CUSTOM 图像,显示速度可能较慢(虽然看起来确实表现合理,在我的测试中)。它速度更快,并且使用很少的额外内存,因为它在创建时不复制/转换输入数据。

相反,它使用自定义示例模型,将 DataBuffer.TYPE_USHORT 作为传输类型,但使用 DataBufferByte 作为数据缓冲区。

private static BufferedImage createNoCopy(int w, int h, byte[] rawBytes) {
DataBuffer dataBuffer = new DataBufferByte(rawBytes, rawBytes.length);

int stride = 2;
SampleModel sampleModel = new MyComponentSampleModel(w, h, stride);
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);

ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);

return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
}

private static class MyComponentSampleModel extends ComponentSampleModel {
public MyComponentSampleModel(int w, int h, int stride) {
super(DataBuffer.TYPE_USHORT, w, h, stride, w * stride, new int[] {0});
}

@Override
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
throw new ArrayIndexOutOfBoundsException("Coordinate out of bounds!");
}

// Simplified, as we only support TYPE_USHORT
int numDataElems = getNumDataElements();
int pixelOffset = y * scanlineStride + x * pixelStride;

short[] sdata;

if (obj == null) {
sdata = new short[numDataElems];
}
else {
sdata = (short[]) obj;
}

for (int i = 0; i < numDataElems; i++) {
sdata[i] = (short) (data.getElem(0, pixelOffset) << 8 | data.getElem(0, pixelOffset + 1));
// If little endian, swap the element order, like this:
// sdata[i] = (short) (data.getElem(0, pixelOffset + 1) << 8 | data.getElem(0, pixelOffset));
}

return sdata;
}
}

如果您的图像在此转换后看起来很奇怪,请尝试翻转字节顺序,如代码中所注释的那样。

最后,一些代码来练习上面的内容:

public static void main(String[] args) {
int w = 1760;
int h = 2140;

byte[] rawBytes = new byte[w * h * 2]; // This will be your input array, 7532800 bytes

ShortBuffer buffer = ByteBuffer.wrap(rawBytes)
// .order(ByteOrder.LITTLE_ENDIAN) // Try swapping the byte order to see sharp edges
.asShortBuffer();

// Let's make a simple gradient, from black UL to white BR
int max = 65535; // Unsigned short max value
for (int y = 0; y < h; y++) {
double v = max * y / (double) h;

for (int x = 0; x < w; x++) {
buffer.put((short) Math.round((v + max * x / (double) w) / 2.0));
}
}

final BufferedImage image = createNoCopy(w, h, rawBytes);
// final BufferedImage image = createCopyUsingByteBuffer(w, h, rawBytes);

SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

frame.add(new JScrollPane(new JLabel(new ImageIcon(image))));

frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

输出应该是这样的(缩小到 1/10):

enter image description here

关于java - 16 位 DICOM 图像的像素数据到 BufferedImage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42841566/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com