我使用以下Java代码来读取Dicom图像,尝试将其转换为JPEG文件。当读数发生在行
时tempImage = ImageIO.read(dicomFile);
,返回的图像的图像类型为10或其他,如0或11.这里的问题是读取偶尔发生。有时返回的图像类型是10,有时则不是。 当返回的图像类型为10时,转换后的JPEG文件的写入成功并返回true,我得到了我的JPEG文件。但是,如果返回的图像类型不是10,则写入失败并返回false,并且不会生成任何文件。这是我用来写的声明:
writerReturn = ImageIO.write(image, "jpeg", new File(tempLocation + studyId + File.separator + seriesUID + File.separator + objectId + thumbnail+ ".jpeg"));
我花了很长时间试图弄清楚为什么这种零星行为正在发生但无法达成任何目标。你能帮忙吗?
答案 0 :(得分:1)
我猜测问题是您的输入图像是16位,而我确信您的代码只接受8位输入。除非你转换16位输入,否则你不能使用所谓的通常的JPEG 8bits有损格式写出来。
在我的方框中,我看到的是:
$ gdcminfo 1.2.840.113619.2.67.2200970061.29232060605151433.387
MediaStorage is 1.2.840.10008.5.1.4.1.1.1.1 [Digital X-Ray Image Storage - For Presentation]
TransferSyntax is 1.2.840.10008.1.2.4.90 [JPEG 2000 Image Compression (Lossless Only)]
NumberOfDimensions: 2
Dimensions: (1887,1859,1)
SamplesPerPixel :1
BitsAllocated :16
BitsStored :14
HighBit :13
PixelRepresentation:0
ScalarType found :UINT16
PhotometricInterpretation: MONOCHROME2
PlanarConfiguration: 0
TransferSyntax: 1.2.840.10008.1.2.4.90
Group 0x6000
Rows 1859
Columns 1887
NumberOfFrames 0
Description
Type G
Origin[2] 1,1
FrameOrigin 0
BitsAllocated 1
BitPosition 0
Origin: (0,0,0)
Spacing: (0.187429,0.187429,1)
DirectionCosines: (1,0,0,0,1,0)
Rescale Intercept/Slope: (0,1)
Orientation Label: AXIAL
因此,如果你想说服自己,你可以提取封装的JPEG 2000字节流:
$ gdcmraw 1.2.840.113619.2.67.2200970061.29232060605151433.387 bug.j2k
$ file bug.j2k
bug.j2k: JPEG 2000 codestream
我可以使用IrfanView和kdu_show打开生成的bug.j2k
,但是你可以看到图像很暗(只读取低位)。
答案 1 :(得分:0)
根据评论中的额外信息,我们发现应用程序在Glassfish服务器中运行,并且安装了两个ImageIO插件,两者都能够读取DICOM图像。问题与阅读无关,但有时将解码图像写入JPEG失败。
上述插件的服务提供商是org.dcm4cheri.imageio.plugins.DcmImageReaderSpi
和
org.dcm4che2.imageioimpl.plugins.dcm.DicomImageReaderSpi
,但只有后者(DicomImageReaderSpi
)似乎有效。这是因为它为每个样本生成一个8位BufferedImage
,这是JPEGImageWriter
能够写入的内容(DcmImageReaderSpi
每个样本图像创建一个16位,无法写入作为JFIF JPEG,因此JPEGImageWriter
)不支持。
由于ImageIO插件的(默认情况下)未指定(读取:不可预测)顺序,结果是有时您获得8 bps版本,有时是16位版本的图像,最终结果是有时转换无效。
现在,好消息是我们可以 设置ImageIO插件的显式顺序,或者我们可以在运行时取消注册插件,获得稳定可预测的结果。这些选项中哪些更好,取决于您的服务器上是否有其他代码依赖于不需要的插件。如果您不需要,请取消注册。
以下代码显示了上述两个选项:
// Get the global registry
IIORegistry registry = IIORegistry.getDefaultInstance();
// Lookup the known providers
ImageReaderSpi goodProvider = lookupProviderByName(registry, "org.dcm4che2.imageioimpl.plugins.dcm.DicomImageReaderSpi");
ImageReaderSpi badProvider = lookupProviderByName(registry, "org.dcm4cheri.imageio.plugins.DcmImageReaderSpi");
if (goodProvider != null && badProvider != null) {
// If both are found, EITHER
// order the good provider BEFORE the bad one
registry.setOrdering(ImageReaderSpi.class, goodProvider, badProvider);
// OR
// un-register the bad provider
registry.deregisterServiceProvider(badProvider);
}
// New and improved (shorter) version. :-)
private static <T> T lookupProviderByName(final ServiceRegistry registry, final String providerClassName) {
try {
return (T) registry.getServiceProviderByClass(Class.forName(providerClassName));
}
catch (ClassNotFoundException ignore) {
return null;
}
}
您还应确保仅运行此代码,对于基于容器的应用程序,在应用程序上下文启动时非常愉快。
使用上述解决方案,ImageIO.read(...)
将始终使用好的插件,ImageIO.write(...)
将按预期工作。