Java中使用dcm4che操作dicom之dcm2Jpg

  1.  项目resources/lib下引入相关jar包(dcm4che-5.31.0相关jar)。

  2. 引入配置文件

相关代码如下:


import org.apache.commons.cli.*;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.image.ICCProfile;
import org.dcm4che3.imageio.plugins.dcm.DicomImageReadParam;
import org.dcm4che3.io.DicomInputStream;
import org.dcm4che3.tool.common.CLIUtils;
import org.dcm4che3.util.SafeClose;

import javax.imageio.*;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.StreamSupport;


public class Dcm2JpgUtils {

    private static ResourceBundle rb = ResourceBundle.getBundle("jpg-messages", Locale.getDefault());

    public interface ReadImage {
        BufferedImage apply(File src) throws IOException;
    }

    private static ReadImage readImage;
    private String suffix;
    private int frame = 1;
    private int windowIndex;
    private int voiLUTIndex;
    private boolean preferWindow = true;
    private float windowCenter;
    private float windowWidth;
    private boolean autoWindowing = true;
    private boolean ignorePresentationLUTShape;
    private Attributes prState;
    private final ImageReader imageReader =
            ImageIO.getImageReadersByFormatName("DICOM").next();
    private static ImageWriter imageWriter;
    private static ImageWriteParam imageWriteParam;
    private int overlayActivationMask = 0xffff;
    private int overlayGrayscaleValue = 0xffff;
    private int overlayRGBValue = 0xffffff;
    private static ICCProfile.Option iccProfile = ICCProfile.Option.none;

    public void initImageWriter(String formatName, String suffix,
                                String clazz, String compressionType, Number quality) {
        this.suffix = suffix != null ? suffix : formatName.toLowerCase();
        Iterator<ImageWriter> imageWriters =
                ImageIO.getImageWritersByFormatName(formatName);
        if (!imageWriters.hasNext())
            throw new IllegalArgumentException(
                    MessageFormat.format(rb.getString("formatNotSupported"),
                            formatName));
        Iterable<ImageWriter> iterable = () -> imageWriters;
        imageWriter = StreamSupport.stream(iterable.spliterator(), false)
                .filter(matchClassName(clazz))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(
                        MessageFormat.format(rb.getString("noSuchImageWriter"),
                                clazz, formatName)));
        imageWriteParam = imageWriter.getDefaultWriteParam();
        if (compressionType != null || quality != null) {
            imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            if (compressionType != null)
                imageWriteParam.setCompressionType(compressionType);
            if (quality != null)
                imageWriteParam.setCompressionQuality(quality.floatValue());
        }
    }

    private static Predicate<Object> matchClassName(String clazz) {
        Predicate<String> predicate = clazz.endsWith("*")
                ? startsWith(clazz.substring(0, clazz.length() - 1))
                : clazz::equals;
        return w -> predicate.test(w.getClass().getName());
    }

    private static Predicate<String> startsWith(String prefix) {
        return s -> s.startsWith(prefix);
    }

    public final void setFrame(int frame) {
        this.frame = frame;
    }

    public final void setWindowCenter(float windowCenter) {
        this.windowCenter = windowCenter;
    }

    public final void setWindowWidth(float windowWidth) {
        this.windowWidth = windowWidth;
    }

    public final void setWindowIndex(int windowIndex) {
        this.windowIndex = windowIndex;
    }

    public final void setVOILUTIndex(int voiLUTIndex) {
        this.voiLUTIndex = voiLUTIndex;
    }

    public final void setPreferWindow(boolean preferWindow) {
        this.preferWindow = preferWindow;
    }

    public final void setAutoWindowing(boolean autoWindowing) {
        this.autoWindowing = autoWindowing;
    }

    public boolean isIgnorePresentationLUTShape() {
        return ignorePresentationLUTShape;
    }

    public void setIgnorePresentationLUTShape(boolean ignorePresentationLUTShape) {
        this.ignorePresentationLUTShape = ignorePresentationLUTShape;
    }

    public final void setPresentationState(Attributes prState) {
        this.prState = prState;
    }

    public void setOverlayActivationMask(int overlayActivationMask) {
        this.overlayActivationMask = overlayActivationMask;
    }

    public void setOverlayGrayscaleValue(int overlayGrayscaleValue) {
        this.overlayGrayscaleValue = overlayGrayscaleValue;
    }

    public void setOverlayRGBValue(int overlayRGBValue) {
        this.overlayRGBValue = overlayRGBValue;
    }

    public final void setICCProfile(ICCProfile.Option iccProfile) {
        this.iccProfile = Objects.requireNonNull(iccProfile);
    }

    public final void setReadImage(ReadImage readImage) {
        this.readImage = readImage;
    }

    private static CommandLine parseComandLine(String[] args)
            throws ParseException {
        Options opts = new Options();
        CLIUtils.addCommonOptions(opts);
        opts.addOption(Option.builder("F")
                .hasArg()
                .argName("format")
                .desc(rb.getString("format"))
                .build());
        opts.addOption(Option.builder("E")
                .hasArg()
                .argName("class")
                .desc(rb.getString("encoder"))
                .build());
        opts.addOption(Option.builder("C")
                .hasArg()
                .argName("type")
                .desc(rb.getString("compression"))
                .build());
        opts.addOption(Option.builder("q")
                .hasArg()
                .argName("quality")
                .type(PatternOptionBuilder.NUMBER_VALUE)
                .desc(rb.getString("quality"))
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("suffix")
                .desc(rb.getString("suffix"))
                .longOpt("suffix")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("number")
                .type(PatternOptionBuilder.NUMBER_VALUE)
                .desc(rb.getString("frame"))
                .longOpt("frame")
                .build());
        opts.addOption(Option.builder("c")
                .hasArg()
                .argName("center")
                .type(PatternOptionBuilder.NUMBER_VALUE)
                .desc(rb.getString("windowCenter"))
                .longOpt("windowCenter")
                .build());
        opts.addOption(Option.builder("w")
                .hasArg()
                .argName("width")
                .type(PatternOptionBuilder.NUMBER_VALUE)
                .desc(rb.getString("windowWidth"))
                .longOpt("windowWidth")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("number")
                .type(PatternOptionBuilder.NUMBER_VALUE)
                .desc(rb.getString("window"))
                .longOpt("window")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("number")
                .type(PatternOptionBuilder.NUMBER_VALUE)
                .desc(rb.getString("voilut"))
                .longOpt("voilut")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("profile")
                .desc(rb.getString("iccprofile"))
                .longOpt("iccprofile")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("file")
                .type(PatternOptionBuilder.EXISTING_FILE_VALUE)
                .desc(rb.getString("ps"))
                .longOpt("ps")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("mask")
                .desc(rb.getString("overlays"))
                .longOpt("overlays")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("value")
                .desc(rb.getString("ovlygray"))
                .longOpt("ovlygray")
                .build());
        opts.addOption(Option.builder()
                .hasArg()
                .argName("value")
                .desc(rb.getString("ovlyrgb"))
                .longOpt("ovlyrgb")
                .build());
        opts.addOption(null, "uselut", false, rb.getString("uselut"));
        opts.addOption(null, "noauto", false, rb.getString("noauto"));
        opts.addOption(null, "noshape", false, rb.getString("noshape"));
        opts.addOption(null, "lsE", false, rb.getString("lsencoders"));
        opts.addOption(null, "lsF", false, rb.getString("lsformats"));
        OptionGroup useGroup = new OptionGroup();
        useGroup.addOption(Option.builder()
                .longOpt("usedis")
                .desc(rb.getString("usedis"))
                .build());
        useGroup.addOption(Option.builder()
                .longOpt("useiis")
                .desc(rb.getString("useiis"))
                .build());
        opts.addOptionGroup(useGroup);
        CommandLine cl = CLIUtils.parseComandLine(args, opts, rb, Dcm2JpgUtils.class);
        if (cl.hasOption("lsF")) {
            listSupportedFormats();
            System.exit(0);
        }
        if (cl.hasOption("lsE")) {
            listSupportedImageWriters(cl.getOptionValue("F", "JPEG"));
            System.exit(0);
        }
        return cl;
    }

  

    private void mconvert(File src, File dest) {
        if (src.isDirectory()) {
            dest.mkdir();
            for (File file : src.listFiles())
                mconvert(file, new File(dest,
                        file.isFile() ? suffix(file) : file.getName()));
            return;
        }
        if (dest.isDirectory())
            dest = new File(dest, suffix(src));
        try {
            convert(src, dest);
            System.out.println(
                    MessageFormat.format(rb.getString("converted"),
                            src, dest));
        } catch (Exception e) {
            System.out.println(
                    MessageFormat.format(rb.getString("failed"),
                            src, e.getMessage()));
            e.printStackTrace(System.out);
        }
    }

    public static void convert(File src, File dest) throws IOException {
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        writeImage(dest, iccProfile.adjust(readImage.apply(src)));
    }

    public BufferedImage readImageFromImageInputStream(File file) throws IOException {
        try (ImageInputStream iis = new FileImageInputStream(file)) {
            imageReader.setInput(iis);
            return imageReader.read(frame - 1, readParam());
        }
    }

    public BufferedImage readImageFromDicomInputStream(File file) throws IOException {
        try (DicomInputStream dis = new DicomInputStream(file)) {
            imageReader.setInput(dis);
            return imageReader.read(frame - 1, readParam());
        }
    }

    private ImageReadParam readParam() {
        DicomImageReadParam param =
                (DicomImageReadParam) imageReader.getDefaultReadParam();
        param.setWindowCenter(windowCenter);
        param.setWindowWidth(windowWidth);
        param.setAutoWindowing(autoWindowing);
        param.setIgnorePresentationLUTShape(ignorePresentationLUTShape);
        param.setWindowIndex(windowIndex);
        param.setVOILUTIndex(voiLUTIndex);
        param.setPreferWindow(preferWindow);
        param.setPresentationState(prState);
        param.setOverlayActivationMask(overlayActivationMask);
        param.setOverlayGrayscaleValue(overlayGrayscaleValue);
        param.setOverlayRGBValue(overlayRGBValue);
        return param;
    }

    private static void writeImage(File dest, BufferedImage bi) throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile(dest, "rw")) {
            raf.setLength(0);
            imageWriter.setOutput(new FileImageOutputStream(raf));
            imageWriter.write(null, new IIOImage(bi, null, null), imageWriteParam);
        }
    }


    private String suffix(File src) {
        String suf = src.getName().endsWith(".dcm") ? src.getName().substring(0, src.getName().length() - 4) : src.getName();
        return suf + '.' + suffix;
    }

    private static Attributes loadDicomObject(File f) throws IOException {
        if (f == null)
            return null;
        DicomInputStream dis = new DicomInputStream(f);
        try {
            return dis.readDataset();
        } finally {
            SafeClose.close(dis);
        }
    }

    public static void listSupportedImageWriters(String format) {
        System.out.println(MessageFormat.format(rb.getString("writers"), format));
        Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName(format);
        while (it.hasNext()) {
            ImageWriter writer = it.next();
            ImageWriteParam param = writer.getDefaultWriteParam();
            System.out.println(MessageFormat.format(rb.getString("writer"),
                    writer.getClass().getName(),
                    param.canWriteCompressed(),
                    param.canWriteProgressive(),
                    param.canWriteTiles(),
                    param.canOffsetTiles(),
                    param.canWriteCompressed()
                            ? Arrays.toString(param.getCompressionTypes())
                            : null));
        }
    }

    public static void listSupportedFormats() {
        System.out.println(
                MessageFormat.format(rb.getString("formats"),
                        Arrays.toString(ImageIO.getWriterFormatNames())));
    }
}


配置文件resources/ jpg-messages.properties

usage=dcm2jpg [<options>] <dicom-file> <jpeg-file>\n\
or dcm2jpg [Options] <dicom-file>... <outdir>\n\
or dcm2jpg [Options] <indir>... <outdir>
try=Try `dcm2jpg --help' for more information.
description=\nConvert DICOM image(s) to JPEG(s) or other image formats.\
\n-\
\nOptions\:
example=-\nExample: dcm2jpg img.dcm img.jpg\n\
=> Convert DICOM image 'img.dcm' to JPEG image 'img.jpg'
frame=frame to convert, 1 (= first frame) by default
format=output image format, JPEG by default
lsformats=list supported output image formats 
suffix=file extension used with destination directory argument,\
lower case format name by default
quality=compression quality (0.0-1.0) of output image
encoder=ImageWriter class to be used for encoding,\n\
com.sun.imageio.plugins.* (= JDK ImageIO plugins) by default
lsencoders=list available Image Writers for specified output image format
compression=Compression Type of Image Writer to be used
ps=file path of presentation state to apply
windowCenter=Window Center of linear VOI LUT function to apply
windowWidth=Window Width of linear VOI LUT function to apply
window=use <number>. Window Center/Width value, if the image provides \
several Window Center/Width values; use 1. by default.
voilut=use <number>. explicit VOI LUT, if the image provides \
several explicit VOI LUT; use 1. by default.
uselut=use explicit VOI LUT in image, even if the image also specifies \
Window Center/Width; prefer applying Window Center/Width over explicit VOI LUT \
by default
noauto=disable auto-windowing for images w/o VOI attributes
noshape=ignore present (2050,0020) Presentation LUT Shape; prioritize value of \
(0028,0004) Photometric Interpretation to determine if minimum sample value is \
intended to be displayed as white (=MONCHROME1) or as black (=MONCHROME2)
overlays=render overlays specified by bits 1-16 of <mask> in hex; FFFF by default.
ovlygray=grayscale value of rendered overlays in hex; FFFF (= white) by default.
ovlyrgb=color of rendered overlays as RGB color code; #ffffff (= white) by default.
iccprofile=specifies the color characteristics of, and inclusion of an ICC Profile in the rendered image:\n\
- no: include no ICC profile\n\
- yes: include the ICC Profile specified in the DICOM image, otherwise the sRGB ICC profile\n\
- srgb: include sRGB ICC profile and transform original pixels to sRGB color space if an ICC Profile is specified in the DICOM image\n\
- adobergb: include Adobe RGB ICC profile and transform original pixels to Adobe RGB color space\n\
- rommrgb: include ROMM RGB ICC profile and transform original pixels to ROMM RGB color space\n\
By default, include no ICC profile, but transform original pixels to sRGB color space if an ICC Profile is specified in the DICOM image.
writers=Supported Image Writers for format: {0}
writer=\n{0}\:\
\n   canWriteCompressed\: {1}\
\n  canWriteProgressive\: {2}\
\n        canWriteTiles\: {3}\
\n       canOffsetTiles\: {4}\
\n    Compression Types\: {5} 
formats=Supported output image formats: {0}
missing=missing file operand
nodestdir=target {0} is not a directory
formatNotSupported=output image format: {0} not supported
noSuchImageWriter=no Image Writer: {0} for format {1} found
converted={0} -> {1}
failed=Failed to convert {0}: {1}
usedis=use DicomInputStream for reading the DICOM image. Supports deflated transfer syntaxes (default, without option --frame <number>)
useiis=use ImageInputStream for reading the DICOM image (default, with option --frame <number>)

调用

  public static void main(String[] args) {
        try {
            File src = new File("C:\\Users\\hp\\Desktop\\dicm");
            File dest = new File("C:\\Users\\hp\\Desktop\\jpg");
            Dcm2JpgUtils dcm2jpg = new Dcm2JpgUtils();
            dcm2jpg.initImageWriter("jpg", null, "com.sun.imageio.plugins.*", null, 1l);
            dcm2jpg.setReadImage(dcm2jpg::readImageFromDicomInputStream);
            dcm2jpg.mconvert(src, dest);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值