【DCMTK】dcm转图片jpeg、bmp、png等

该博客介绍了如何使用DCMTK库将DICOM医学影像文件转换为PPM、BMP、JPEG、PNG和TIFF等图片格式。详细阐述了代码实现过程,包括文件读取、图像导出以及不同格式的转换方法。同时,提到了转换过程中需要注意的文件输入类型和依赖库的安装。
摘要由CSDN通过智能技术生成

利用DCMTK实现dcm文件转图片 jpeg bmp dicom tiff pnm png

项目地址:
CodeChina kissDicomViewer
详细介绍:
CSDN 一个简单的 DICOM 浏览器


实现功能

  DICOM浏览器自然少不了当前打开文件转成图片的功能,可以导出当前选择层和全部层。根据当前打开的不同文件和选项输出单张图片或者序列图片。 本来想增加导出mp4的功能,可惜DCMTK没有现成的,需要引入ffmpeg。想了想还是等常规功能做完了以插件形式引入吧。

需要注意文件输入:单张单层、单张多层(z表示时间)、多张单层(z表示时间)、多张多层(z表示高度)、多张多层(两个z轴分别表示:高度和时间)

导出办法

  利用DCMTK的现成接口即可实现图片的导出:

  • DicomImage::writeRawPPMDICOM文件 ==> PPM图片
  • DicomImage::writeBMPDICOM文件 ==> BMP图片
  • DicomImage::writePluginFormat + DiJPEGPluginDICOM文件 ==> JPEG图片
  • DicomImage::writePluginFormat + DiPNGPluginDICOM文件 ==> PNG图片
  • DicomImage::writePluginFormat + DiTIFFPluginDICOM文件 ==> TIFF图片

TIFF文件需要提前安装libtiff,并且DCMTK编译时加上tiff选项。
PNG文件需要提前安装libpngic,并且DCMTK编译时加上PNG选项。

变量说明
abort_终止当前转换
leaflet_导出单张/多张
jpeg_quality_jpeg 压缩质量
frame_导出单张时第几层
file_type_导出类型
dest_dir_导出目录
image_files_输入文件(单个或序列)
void ExportImageThread::run() {
    DcmRLEDecoderRegistration::registerCodecs(); // 寄存器RLE解压编解码器
    DJDecoderRegistration::registerCodecs(EDC_photometricInterpretation); // 注册JPEG解压缩编解码器
    foreach (QString file, image_files_) {
        if (abort_) {
            break;
        }
        DcmFileFormat dfile;
        OFCondition cond = dfile.loadFile(file.toLocal8Bit().data());
        if (cond.bad()) {
            emit resultReady(tr("Failed: %1, %2.").arg(file, cond.text()));
            continue;
        }
        QString fileName = file;
        fileName.replace("/", QDir::separator()).replace("\\", QDir::separator());
        fileName = fileName.mid(fileName.lastIndexOf(QDir::separator()) + 1);
        QString filepath = dest_dir_ + QDir::separator() + fileName;
        QDir().mkpath(dest_dir_);
        if (file_type_ == EFT_Dicom) {
            OFCondition l_error = dfile.saveFile(filepath.toLocal8Bit().data());
            if (EC_Normal == l_error) {
                emit resultReady(tr("Exported: %1.").arg(file));
            } else {
                emit resultReady(tr("Failed: %1, %2.").arg(file, l_error.text()));
            }
            continue;
        }
        DcmDataset *dataset = dfile.getDataset();
        E_TransferSyntax xfer = dataset->getOriginalXfer();
        Sint32 frameCount;
        if (dataset->findAndGetSint32(DCM_NumberOfFrames, frameCount).bad()) {
            frameCount = 1;
        }
        ulong compabilityMode = CIF_DecompressCompletePixelData;
        if (frameCount > 1) {
            compabilityMode |= CIF_UsePartialAccessToPixelData;
        }
        DicomImage *di = new DicomImage(&dfile, xfer, compabilityMode);
        if (di->getStatus() != EIS_Normal) {
            emit resultReady(tr("Failed: %1, %2.").arg(file,
                             QString::fromLocal8Bit(DicomImage::getString(di->getStatus()))));
            delete di;
            continue;
        }
        di->setWindow(0);
        /* 将所选帧写入文件 */
        FILE *ofile = nullptr;
        QString suffix = GetSuffix(di);
        int result = 0;
        qint32 generate = this->frame_;
        qint32 generate_end = this->leaflet_ ? this->frame_ + 1 : frameCount;
        if(generate < frameCount) {
            for (; generate < generate_end; generate++) {
                /* 输出到文件 */
                if (fileName.right(4) == QString(".dcm")) {
                    fileName = fileName.mid(0, file.lastIndexOf('.'));
                }
                QString filepath = dest_dir_ +
                                   QDir::separator() +
                                   QString("%1%2%3.%4").arg(
                                       fileName,
                                       frameCount > 1 ? QString::number(generate) : QString(),
                                       this->leaflet_ ? "(" + QString::number(generate) + ")" : "",
                                       suffix);
                ofile = fopen(filepath.toLocal8Bit().data(), "wb");
                if (ofile == nullptr) {
                    emit resultReady(tr("Failed: %1, open dest file failed.").arg(file));
                    continue;
                }
                switch (file_type_) {// 最后创建输出图像文件
                    case EFT_RawPNM:
                        result = di->writeRawPPM(ofile, 8, static_cast<quint32>(generate));
                        break;
                    case EFT_8bitPNM:
                        result = di->writePPM(ofile, 8, static_cast<quint32>(generate));
                        break;
                    case EFT_16bitPNM:
                        result = di->writePPM(ofile, 16, static_cast<quint32>(generate));
                        break;
                    case EFT_BMP:
                        result = di->writeBMP(ofile, 0, static_cast<quint32>(generate));
                        break;
                    case EFT_8bitBMP:
                        result = di->writeBMP(ofile, 8, static_cast<quint32>(generate));
                        break;
                    case EFT_24bitBMP:
                        result = di->writeBMP(ofile, 24, static_cast<quint32>(generate));
                        break;
                    case EFT_32bitBMP:
                        result = di->writeBMP(ofile, 32, static_cast<quint32>(generate));
                        break;
                    case EFT_JPEG: {/* 初始化JPEG插件 */
                            DiJPEGPlugin plugin;
                            plugin.setQuality(static_cast<quint32>(jpeg_quality_));
                            plugin.setSampling(ESS_422);
                            result = di->writePluginFormat(&plugin, ofile, static_cast<quint32>(generate));
                        }
                        break;
#ifdef WITH_LIBPNG
                    case EFT_PNG: { /* 初始化PNG插件 */
                            DiPNGPlugin pngPlugin;
                            pngPlugin.setInterlaceType(E_pngInterlaceAdam7);
                            pngPlugin.setMetainfoType(E_pngFileMetainfo);
                            result = di->writePluginFormat(&pngPlugin, ofile, static_cast<quint32>(generate));
                        }
                        break;
#endif
                    case EFT_PastelPNM:
                        result = di->writePPM(ofile, MI_PastelColor, static_cast<quint32>(generate));
                        break;
#ifdef WITH_LIBTIFF
                    case EFT_TIFF: {
                            /* initialize TIFF plugin */
                            DiTIFFPlugin tiffPlugin;
                            tiffPlugin.setCompressionType(E_tiffPackBitsCompression);
                            tiffPlugin.setLZWPredictor(E_tiffLZWPredictorDefault);
                            tiffPlugin.setRowsPerStrip(OFstatic_cast(unsigned long, 0));
                            result = di->writePluginFormat(&tiffPlugin, ofile, static_cast<quint32>(frame));
                        }
#endif
                    default:
                        break;
                }
                if (result) {
                    emit resultReady(tr("Exported: %1.").arg(file));
                } else {
                    emit resultReady(tr("Failed: %1, conversion failed.").arg(file));
                }
                fclose(ofile);
            }
        }
        delete di;
    }
    DcmRLEDecoderRegistration::cleanup(); // 注销RLE解压缩编解码器
    DJDecoderRegistration::cleanup(); // 注销JPEG解压缩编解码器
}

界面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZSLGL5E-1612440275829)(vx_images/3509617208475.png)]

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Beyond欣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值