tift2dcm(tiff2Dicom、tiff转dicom)

胶片扫描tiff文件转dicom

	首先感谢您花时间阅读这篇文章,在您为tiff转dicom文件而烦恼的时候,
	不防认真的看看这篇文章能否帮到您,也希望您对文章中有错误的地方请不吝赐教。先谢谢各位笔下留情!
	好了废话不多说,直接上主题!

使用的语言 Java

使用的开源库 Dcm4che

需要用到的jar包:
commons-cli-1.2.jar
dcm4che-core-5.12.0.jar
dcm4che-imageio-5.12.0.jar
dcm4che-tool-common-5.12.0.jar

额外使用到的jar ij.jar

dcm4che里面有个工具类是dcm4che-tool-jpg2dcm,里面有个类是Jpg2Dcm

Jpg2Dcm里面的 代码片.

    public void convert(File infile, File outfile) throws IOException {
        FileType fileType = null;
        try {
            fileType = FileType.valueOf(infile);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(MessageFormat.format(rb.getString("invalid-file-ext"), infile));
        }

        fileLength = infile.length();
        if (fileLength > MAX_FILE_SIZE)
            throw new IllegalArgumentException(MessageFormat.format(rb.getString("file-too-large"), infile));

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile))) {
            if (!parseHeader(fileType, bis))
                throw new IOException(MessageFormat.format(rb.getString("failed-to-parse"), fileType, infile));

            int itemLen = (int) fileLength;
            try (DicomOutputStream dos = new DicomOutputStream(outfile)) {
                dos.writeDataset(metadata.createFileMetaInformation(fileType.getTransferSyntaxUID()), metadata);
                dos.writeHeader(Tag.PixelData, VR.OB, -1);
                dos.writeHeader(Tag.Item, null, 0);
                if (jpegHeader != null && noAPPn) {
                    int offset = jpegHeader.offsetAfterAPP();
                    itemLen -= offset - 3;
                    dos.writeHeader(Tag.Item, null, (itemLen + 1) & ~1);
                    dos.write((byte) -1);
                    dos.write((byte) JPEG.SOI);
                    dos.write((byte) -1);
                    dos.write(buffer, offset, headerLength - offset);
                } else {
                    dos.writeHeader(Tag.Item, null, (itemLen + 1) & ~1);
                    dos.write(buffer, 0, headerLength);
                }
                StreamUtils.copy(bis, dos, buffer);
                if ((itemLen & 1) != 0)
                    dos.write(0);
                dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);
            }
        }
        System.out.println(MessageFormat.format(rb.getString("converted"), infile, outfile));
    }
 private enum FileType {
        jpeg(UID.SecondaryCaptureImageStorage, UID.JPEGBaseline1) {
            @Override
            boolean parseHeader(Jpg2Dcm main) {
                return (main.jpegHeader = new JPEGHeader(main.buffer, JPEG.SOS)).toAttributes(main.metadata) != null;
            }
        },
        mpeg(UID.VideoPhotographicImageStorage, UID.MPEG2) {
            @Override
            boolean parseHeader(Jpg2Dcm main) {
                return new MPEGHeader(main.buffer).toAttributes(main.metadata, main.fileLength) != null;
            }
        };

        private final String cuid;
        private final String tsuid;

        FileType(String cuid, String tsuid) {
            this.cuid = cuid;
            this.tsuid = tsuid;
        }

        public String getSOPClassUID() {
            return cuid;
        }

        public String getTransferSyntaxUID() {
            return tsuid;
        }

        abstract boolean parseHeader(Jpg2Dcm main);

        static FileType valueOf(File file) {
            String contentType = FileTypeMap.getDefaultFileTypeMap().getContentType(file);
            return valueOf(contentType.substring(contentType.lastIndexOf("/")+1));
        }
    }
  

以上就是Jpg2Dcm jpg转dicom的源码。当我用tiff的图像去转dicom的时候这里就获取不到 tiif文件的FileType。于是对源码做了部分修改

 private enum FileType {
        jpeg(UID.SecondaryCaptureImageStorage, UID.JPEGBaseline1) {
            @Override
            boolean parseHeader(Jpg2Dcm main) {
                return (main.jpegHeader = new JPEGHeader(main.buffer, JPEG.SOS)).toAttributes(main.metadata) != null;
            }
        },
        
        tiff(UID.SecondaryCaptureImageStorage, UID.JPEGLossless) {
            @Override
            boolean parseHeader(Jpg2Dcm main) {
                return true;
            }
        },
        
        mpeg(UID.VideoPhotographicImageStorage, UID.MPEG2) {
            @Override
            boolean parseHeader(Jpg2Dcm main) {
                return new MPEGHeader(main.buffer).toAttributes(main.metadata, main.fileLength) != null;
            }
        };

        private final String cuid;
        private final String tsuid;

        FileType(String cuid, String tsuid) {
            this.cuid = cuid;
            this.tsuid = tsuid;
        }

        public String getSOPClassUID() {
            return cuid;
        }

        public String getTransferSyntaxUID() {
            return tsuid;
        }

        abstract boolean parseHeader(Jpg2Dcm main);

        static FileType valueOf(File file) {
            String contentType = FileTypeMap.getDefaultFileTypeMap().getContentType(file);
            return valueOf(contentType.substring(contentType.lastIndexOf("/")+1));
        }
    }

在FileType的枚举类中加了一个tiff 的枚举。UID.JPEGLossless这里是因为我看分析了这家医院的胶片扫描出来的tiff文件中的传输语法是JPEGLossless,所以这里用的是UID.JPEGLossless,别家医院是不是也是这个就要看拿到的tiff文件是什么了。(鄙人也是第一次做这个东西,有很多还是有不懂的地方)也是经过反复实验才成功的。耐心点看,继续…
当然只改了这FileType这个枚举类确实是能够生成dicom文件,但是生成的dicom文件是打开不了的。
这时候前面说的ij.jar的jar包就用上了。
接着往下说之前先说说这个ij.jar包的来历================================
这里要感谢我的领导老易同志,他找到这个网站https://sourceforge.net/projects/tifftodicom/,里面直接有个tiff转dicom的工具,但是很遗憾,我没能成功的将tiff转成dicom文件。我也尝试去反编译里面应用的jar包来获取源码,打断点发现这里的ij.jar获取的像素数据 和ImageIo或者通过File文件获取的图像的像素数组有所差别。于是我把注意力放在这个ij.jar包的身上。
但是试了很久也没有成功,这时候又得感谢老易同志了,有款软件叫 Sante DICOM Viewer FREE(请大家自行去下载)。这软件居然能把tiff转成dicom输出,好家伙!用了一年多这个软件居然没发现。你说是不是得感谢老易同志。但是有个奇怪的地方,原本是20多兆的tiff文件,经过这个软件以后,dicom文件变成了60多兆。通过二进制查看,像素数据足足多了3倍!经过对比,不看不知道,一看下一跳。ij.jar获取到tiff的像素数据,前10个像素数据 打个比方 FD FA F6 E6 C1 99 7A 4E 38 36。而 用ImageIo或者File类获取到的像素前10个像素数据,90 00 0F 51 A9 00 0F CD 3F 00。这时候Sante DICOM Viewer FREE把tiff转出来的dicom文件(60多兆的dicom)却是FD FD FD FA FA FA F6 F6 F6 E6 E6 E6 C1 C1 C1 99 99 99 7A 7A 7A 4E 4E 4E 38 38 38 36
36 36。简直就是像绝望中发现了生机一样。
之前种种的错误试验就不再说了,很辛苦 很绝望…
于是我就看上了这个ij.jar。
这就是为什么要说用到这个ij.jar的缘故。====================================
ij.jar可以从上面说的那个网站中下载TiffConvert.jar解压出来就用了。如果你能用TiffConvert.jar这里面的方法直接能将Tiff转Dicom就不用往下看了。
到这里也快结束了。再坚持一下,再修改Jpg2Dcm的源码

public void convert(File infile, File outfile) throws IOException {
        FileType fileType = null;
        try {
            fileType = FileType.valueOf(infile);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(MessageFormat.format(rb.getString("invalid-file-ext"), infile));
        }

        fileLength = infile.length();
        if (fileLength > MAX_FILE_SIZE)
            throw new IllegalArgumentException(MessageFormat.format(rb.getString("file-too-large"), infile));
        FileInfo fileInfo = null;
		try (BufferedInputStream bis = new BufferedInputStream(
		        new FileInputStream(infile))) {
			if (fileType == FileType.tiff) {
				supplementMissingValue(metadata, Tag.SOPClassUID, fileType.getSOPClassUID());
				//用ij的包去获取图像的像素
				Opener opener = new Opener();
		        ImagePlus img = opener.openTiff(infile.getParentFile().getAbsolutePath(), infile.getName());
		        fileInfo = img.getFileInfo();
		        Object obj = fileInfo.pixels;
		        buffer = (byte[]) obj;
				byte[] bufNew = new byte[buffer.length * 3];
				int index = 0;
				for (int i = 0; i < buffer.length; i++) {
					for (int j = 0; j < 3; j++) {
						bufNew[index++] = buffer[i];
					}
				}
				buffer = bufNew;
				fileLength = buffer.length;
        	}else{
        		 if (!parseHeader(fileType, bis))
                     throw new IOException(MessageFormat.format(rb.getString("failed-to-parse"), fileType, infile));
        	}
           
            int itemLen = (int) fileLength;
            try (DicomOutputStream dos = new DicomOutputStream(outfile)) {
            	if(fileType == FileType.tiff){
            		Attributes fileMetaInformation = metadata.createFileMetaInformation("1.2.840.10008.1.2.1");
            		Attributes img = new Attributes();
            		img.setInt(Tag.Rows, VR.US, fileInfo.height);
            		img.setInt(Tag.Columns, VR.US, fileInfo.width);
            		img.setInt(Tag.BitsAllocated, VR.US, 8);
            		img.setInt(Tag.BitsStored, VR.US, 8);
            		img.setInt(Tag.HighBit, VR.US, 7);
            		img.setInt(Tag.SamplesPerPixel, VR.US, 3);
            		img.setString(Tag.PhotometricInterpretation, VR.CS, "RGB");
            		img.setInt(Tag.PlanarConfiguration, VR.US, 0);
            		img.setBytes(Tag.PixelData, VR.OB, buffer);
            		metadata.addAll(img);
            		MsgEmity me = MyDicomUtil.writeAttrIntoFile(fileMetaInformation, metadata, outfile);
            		if(!me.isSuccess()){
            			System.out.println(me.getMsg());
            		}
            		return;
            	}else{
            		dos.writeDataset(metadata.createFileMetaInformation(fileType.getTransferSyntaxUID()), metadata);
            	}
                dos.writeHeader(Tag.PixelData, VR.OB, -1);
                dos.writeHeader(Tag.Item, null, 0);
                if (jpegHeader != null && noAPPn) {
                    int offset = jpegHeader.offsetAfterAPP();
                    itemLen -= offset - 3;
                    dos.writeHeader(Tag.Item, null, (itemLen + 1) & ~1);
                    dos.write((byte) -1);
                    dos.write((byte) JPEG.SOI);
                    dos.write((byte) -1);
                    dos.write(buffer, offset, headerLength - offset);
				} else {
					dos.writeHeader(Tag.Item, null, (itemLen + 1) & ~1);
					dos.write(buffer, 0, headerLength);
				}
                StreamUtils.copy(bis, dos, buffer);
                if ((itemLen & 1) != 0)
                    dos.write(0);
                dos.writeHeader(Tag.SequenceDelimitationItem, null, 0);
            }
        }
        System.out.println(MessageFormat.format(rb.getString("converted"), infile, outfile));
    }

//用ij的包去获取图像的像素
Opener opener = new Opener();
ImagePlus img = opener.openTiff(infile.getParentFile().getAbsolutePath(), infile.getName());
fileInfo = img.getFileInfo();
Object obj = fileInfo.pixels;
buffer = (byte[]) obj;
byte[] bufNew = new byte[buffer.length * 3];
int index = 0;
for (int i = 0; i < buffer.length; i++) {
for (int j = 0; j < 3; j++) {
bufNew[index++] = buffer[i];
}
}
buffer = bufNew;
fileLength = buffer.length;
所以这段代码就是获取像素然后把每个像素复制3边,再赋值内存中的buffer数组即可。至于为什么每个像素会翻了3倍目前确实无法得知。
后面还有一段是
if(fileType == FileType.tiff){
Attributes fileMetaInformation = metadata.createFileMetaInformation(“1.2.840.10008.1.2.1”);
Attributes img = new Attributes();
img.setInt(Tag.Rows, VR.US, fileInfo.height);
img.setInt(Tag.Columns, VR.US, fileInfo.width);
img.setInt(Tag.BitsAllocated, VR.US, 8);
img.setInt(Tag.BitsStored, VR.US, 8);
img.setInt(Tag.HighBit, VR.US, 7);
img.setInt(Tag.SamplesPerPixel, VR.US, 3);
img.setString(Tag.PhotometricInterpretation, VR.CS, “RGB”);
img.setInt(Tag.PlanarConfiguration, VR.US, 0);
img.setBytes(Tag.PixelData, VR.OB, buffer);
metadata.addAll(img);
MsgEmity me = MyDicomUtil.writeAttrIntoFile(fileMetaInformation, metadata, outfile);
if(!me.isSuccess()){
System.out.println(me.getMsg());
}
return;
}
将图片中的信息赋值到 Attributes 中,再输出到文件即可。
MyDicomUtil.writeAttrIntoFile这个只是封装了dem4che里面的方法 将Attributes 输出到文件的,并不是我自己写的方法。
到这里就结束了,最后也可以将tiff转成dicom文件。最后原谅我不能上传转换以后的dicom文件,因为都是医院病人的真实图像!
网上也有很多tiff转dicom的工具,但是这个还是比较简单的。还有的是把20多兆压缩成7兆左右,就是前面提到的JPEGLossless压缩语法,这个算法出来的dicom只有7兆左右,但是本人能力不足资历尚浅,也没有那么多的时间和精力去处理,能搞定这个60多兆的已经是最大的幸运了。项目6月底上线。也算是功德圆满了!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值