我得到了一个字节数组,存储了一个已经解构的DICOM文件中的16位像素数据。我现在需要做的是以某种方式将像素数据转换/导出为TIFF文件格式。我使用imageio-tiff-3.3.2.jar插件来处理tiff转换/头数据。但是现在我需要将该图像数据数组打包到原始图像维度的BufferedImage中,以便将其导出到TIFF。但是BufferedImage似乎不支持16位图像。有没有办法解决这个问题,比如外部库?是否有其他方法可以将图像数据打包到原始DICOM维度的TIFF图像中?请记住,这个过程必须是完全无损的。在过去的几天里,我环顾四周,尝试了一些东西,但到目前为止,没有任何东西对我有效。
如果你有任何问题,或者有什么我可以做的来澄清任何困惑,请告诉我。
给定包含无符号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
图像,显示速度可能较慢(但在我的测试中,它似乎执行得合理)。它要快得多,而且使用的额外内存很少,因为它在创建时不复制/转换输入数据。
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;
}
}
如果您的图像在转换后看起来很奇怪,请尝试翻转endianness,如代码中所注释的那样。
最后,一些代码来练习上面的内容:
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):
问题内容: 我有一个从主监视器截取的图像,因此我想将其添加到Java FX : 我正在尝试将设置为,但是类型不兼容,也无法强制转换。我该如何纠正? 问题答案: 您可以使用
我有一个来自主监视器的图像截图,我想将其添加到Java FX ImageView中,如下所示: 我试图将BufferedImage捕获设置为javafx。场景形象Image Image但是类型不兼容,我也无法转换它。我该如何纠正?
问题内容: 如果我的窗口处于32位色深模式,那么下面的代码将从窗口中获取漂亮的PIL图像: 但是,以16位模式运行时,出现错误: 我应该如何形成以16位模式工作的电话?另外,如何使该函数在任何位深度模式下都能工作,而不必说必须将其作为参数传递呢? 更新:从这个问题中,我了解到我必须对第二个模式参数使用“ BGR; 16”而不是“ BGRX”。它可以拍出正确的照片,无论是否指定步幅。问题是像素值在某
当我以tiff格式打开一个16位图像时,它会以黑色图像的形式打开。16位tiff图像仅在程序ImageJ中打开;但是,它不会在预览中打开。我想知道我现在的选择是什么,以一种不降低分辨率的更简单的方式查看格式,而不是打开ImageJ查看它。我是否应该将其转换为8位格式,但当格式从16位减少到8位时,是否会丢失数据?另外,我正在考虑将tiff图像转换为jpeg,但这会导致分辨率降低吗?
我试图从bufferedimage中获取像素数据,该bufferedimage将只包含灰度半透明图像(argb)。我从图像中得到一个WritableRaster,并使用光栅的setPixels方法设置它的像素。使用此方法,我得到ArrayIndexOutOfBounds异常。在做了一些研究后,我发现BufferedImages在每个频带每个像素存储一个整数,而不是每个像素存储一个整数。也就是说,对
我是第一次使用openCV。我正在使用openCV3和XCode对其进行编码。我想创建一个16位的灰度图像,但我想我有的数据是这样定义的,4000是像素值为白色和0为黑色。我在int类型的数组中有这些像素的信息。如何创建Mat并将数组中的值分配给Mat?