0

我正在使用以下 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"));

我花了很长时间试图弄清楚为什么会发生这种零星的行为但无法解决任何问题。能否请你帮忙?

4

2 回答 2

1

我猜问题是您的输入图像是 16 位,而我确信您的代码只接受 8 位输入。除非您转换 16 位输入,否则您无法使用所谓的常用 JPEG 8 位有损格式进行写入。

在我的盒子上,我看到的是:

$ 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

我能够bug.j2k使用 IrfanView 和kdu_show打开生成的文件,但正如您所见,图像非常暗(仅读取低位)。

于 2016-11-15T07:09:37.507 回答
0

从评论中的额外信息中,我们发现该应用程序在 Glassfish 服务器中运行,并且安装了两个 ImageIO 插件,都能够读取 DICOM 图像。该问题与读取无关,但有时将解码后的图像写入 JPEG 会失败。

上述插件的服务提供者是org.dcm4cheri.imageio.plugins.DcmImageReaderSpiand ,但似乎org.dcm4che2.imageioimpl.plugins.dcm.DicomImageReaderSpi只有后者 ( ) 有效。DicomImageReaderSpi这是因为它为每个样本生成一个 8 位BufferedImage,这JPEGImageWriter是能够写入的(DcmImageReaderSpi每个样本图像创建一个 16 位,它不能写为 JFIF JPEG,因此不受 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(...)预期工作。

于 2016-11-16T13:17:29.810 回答