QT DICOM医疗影像转换

时间紧任务重,直接上代码吧:

1、引言:借助开源库DCMKT进行转换

2、库文件引用:

#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"         //DcmFileFormat
#include "dcmtk/dcmimgle/dcmimage.h"    //DicomImage
#include "dcmtk/dcmimgle/diregbas.h"   //DiRegisterBase
#include "dcmtk/dcmimage/diregist.h"   //DiRegisterBase
#include "dcmtk/dcmdata/libi2d/i2d.h"   //I2DImgSource
#include "dcmtk/dcmdata/libi2d/i2dbmps.h"   //I2DBmpSource
#include "dcmtk/dcmdata/libi2d/i2djpgs.h"   //I2DJpegSource
#include "dcmtk/dcmdata/dcpxitem.h"   //DcmPixelItem
#include "dcmtk/dcmdata/dcpath.h"   //DcmPixelItem
#include "dcmtk/dcmdata/dcrledrg.h"   //DcmRLEDecoderRegistration
#include "dcmtk/dcmjpeg/djdecode.h"   //DJDecoderRegistration
#include "dcmtk/dcmjpeg/dipijpeg.h"   //DiJPEGPlugin

3、DCOM影像的显示:

QString strFilePath = QFileDialog::getOpenFileName(this, "打开对话框", QDir::currentPath(),"DICOM图像文件(*.dcm)");
    if (!strFilePath.isEmpty()){
        ui->lineEdit_dcm->setText(strFilePath);
        DicomImage *dcmImage = new DicomImage(ui->lineEdit_dcm->text().toLocal8Bit().toStdString().c_str());
        if (dcmImage != NULL)
        {
            if (dcmImage->getStatus() == EIS_Normal)
            {
                EP_Interpretation PhotometricInterpretation = dcmImage->getPhotometricInterpretation();
                if ((PhotometricInterpretation == EPI_Monochrome1) || (PhotometricInterpretation == EPI_Monochrome2))
                {
                    dcmImage->setMinMaxWindow();
                    ulong size = dcmImage->getWidth() * dcmImage->getHeight();
                    uchar *data = new uchar[size];
                    dcmImage->setMinMaxWindow();
                    dcmImage->getOutputData(data, size, 8);
                    QImage image = QImage(data, dcmImage->getWidth(), dcmImage->getHeight(), QImage::Format_Indexed8);
                    QImage image2 = image.copy();
                    image2 = image2.scaled(ui->label_dcm->width(), ui->label_dcm->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                    ui->label_dcm->setPixmap(QPixmap::fromImage(image2));

                    delete[] data;
                    data = nullptr;
                }
                else if (PhotometricInterpretation == EPI_RGB){
                    DcmFileFormat dicomfile;//将dcm格式文件读取出来解析相关类
                    OFCondition oc = dicomfile.loadFile(ui->lineEdit_dcm->text().toLocal8Bit().data());
                    if(oc.bad()){
                        QMessageBox::information(this, "提示",  "转换失败!");
                        delete dcmImage;
                        dcmImage = nullptr;
                        return;
                    }

                    DcmDataset* pDataset = dicomfile.getDataset();//得到dcm文件的数据

                    int nWidth, nHeight, nBandCount, nWindowWidth, nWindowCenter,nRescaleSlope,nRescaleIntercept,nBitsAllocated,nHighBit,
                        nNumberOfFrames;
                    OFString strInstanceNumber, strWidth, strHeight,
                        strWindowWidth, strWindowCenter, strSamplesPerPixel,
                        strRescaleSlope,strRescaleIntercept,strBitsAllocated,strHighBit,strNumberOfFrames;

                    //读取dcm格式文件里相关元素值
                    pDataset->findAndGetOFString(DCM_InstanceNumber, strInstanceNumber);
                    pDataset->findAndGetOFString(DCM_Columns ,strWidth);
                    pDataset->findAndGetOFString(DCM_Rows ,strHeight);
                    pDataset->findAndGetOFString(DCM_WindowWidth ,strWindowWidth);
                    pDataset->findAndGetOFString(DCM_WindowCenter ,strWindowCenter);
                    pDataset->findAndGetOFString(DCM_SamplesPerPixel ,strSamplesPerPixel);
                    pDataset->findAndGetOFString(DCM_RescaleSlope ,strRescaleSlope);
                    pDataset->findAndGetOFString(DCM_RescaleIntercept,strRescaleIntercept);
                    pDataset->findAndGetOFString(DCM_BitsAllocated,strBitsAllocated);
                    pDataset->findAndGetOFString(DCM_HighBit,strHighBit);
                    pDataset->findAndGetOFString(DCM_NumberOfFrames,strNumberOfFrames);

                    nWidth = atoi(strWidth.c_str());
                    nHeight = atoi(strHeight.c_str());
                    if(strSamplesPerPixel.empty())
                    {
                        strSamplesPerPixel = "1";//若没有说明哪种类型图像,默认为灰度图像
                    }

                    if(strRescaleSlope.empty())
                    {
                        strRescaleSlope = "1";//像素转换的比例系数,没有则默认存储为1
                    }

                    if(strRescaleIntercept.empty())
                    {
                        strRescaleIntercept = "0";//像素转换的比例参数,没有则默认存储为0
                    }

                    nBandCount = atoi(strSamplesPerPixel.c_str());
                    nWindowWidth = atoi(strWindowWidth.c_str());
                    nWindowCenter = atoi(strWindowCenter.c_str());
                    nRescaleSlope = atoi(strRescaleSlope.c_str());
                    nRescaleIntercept = atoi(strRescaleIntercept.c_str());
                    nBitsAllocated = atoi(strBitsAllocated.c_str());
                    nHighBit = atoi(strHighBit.c_str());
                    nNumberOfFrames = atoi(strNumberOfFrames.c_str());

                    E_TransferSyntax opt_oxfer = pDataset->getOriginalXfer();
                    //图像存储的压缩格式
                    if(EXS_RLELossless == opt_oxfer)
                    {
                        E_TransferSyntax opt_oxfer = EXS_RLELossless;
                        OFBool opt_uidcreation = OFFalse;
                        OFBool opt_reversebyteorder = OFFalse;
                        DcmRLEDecoderRegistration::registerCodecs(opt_uidcreation, opt_reversebyteorder);
                        DcmXfer original_xfer(opt_oxfer);
                        if (!original_xfer.isEncapsulated()){
                            QMessageBox::information(this, "提示",  "转换失败!");
                            delete dcmImage;
                            dcmImage = nullptr;
                            return;
                        }

                        oc = pDataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
                        if (oc != EC_Normal){
                            QMessageBox::information(this, "提示",  "转换失败!");
                            delete dcmImage;
                            dcmImage = nullptr;
                            return;
                        }
                    }

                    else if(opt_oxfer >= EXS_JPEGProcess1 && opt_oxfer <= EXS_JPEGLSLossy)
                    {
                        E_DecompressionColorSpaceConversion opt_decompCSconversion = EDC_guessLossyOnly;
                        E_UIDCreation    opt_uidcreation = EUC_default;
                        DJDecoderRegistration::registerCodecs(opt_decompCSconversion, opt_uidcreation);
                        DcmXfer original_xfer(opt_oxfer);
                        if (!original_xfer.isEncapsulated()){
                            QMessageBox::information(this, "提示",  "转换失败!");
                            delete dcmImage;
                            dcmImage = nullptr;
                            return;
                        }

                        oc = pDataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
                        if(oc != EC_Normal){
                            QMessageBox::information(this, "提示",  "转换失败!");
                            delete dcmImage;
                            dcmImage = nullptr;
                            return;
                        }
                    }

                    DcmElement* element = NULL;
                    OFCondition result = pDataset->findAndGetElement(DCM_PixelData, element);//获取文件中存储的像素元素
                    long nCount = nWidth * nHeight;//unsigned char
                    if(nBandCount == 3)
                        nCount *= 3;//若是RGB彩色图像则有R,G,B三种色彩值进行存储

                    /*获取的像素值需要进行转化
                     * 实际像素值 = RescaleSlope * 获取像素值 + RescaleIntercept,
                     * 若BitsAllocated超过8会超出颜色值的表示范围0~255需要对其进行转化.
                     */
                    unsigned char *pRgbData = new unsigned char[nCount];
                    if(8 == nBitsAllocated)
                    {
                        Uint8* pixData = NULL;
                        result = element->getUint8Array(pixData);
                        if(result.good() && pixData != NULL)
                        {
                            if(pRgbData != NULL)
                            {
                                for(long i = 0; i < nCount; i++)
                                {
                                    while(nBitsAllocated - nHighBit > 0)
                                    {
                                        pixData[i] &= ~(1 << nHighBit);
                                        nHighBit++;
                                    }

                                    pRgbData[i] = nRescaleSlope*pixData[i] + nRescaleIntercept;
                                }
                            }

                            QImage image = QImage((uchar*)pRgbData, nWidth, nHeight, nBandCount==1 ? QImage::Format_Indexed8 : QImage::Format_RGB888);
                            QImage image2 = image.copy();
                            image2 = image2.scaled(ui->label_dcm->width(), ui->label_dcm->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                            ui->label_dcm->setPixmap(QPixmap::fromImage(image2));
                        }
                    }
                    else if(16 == nBitsAllocated)//若颜色值存储为16位,则有可能超出颜色的表示范围(0~255)此时需要对其进行转化
                    {
                        Uint16* pixData = NULL;
                        result = element->getUint16Array(pixData);
                        if(result.good() && pixData != NULL)
                        {
                            if(pRgbData != NULL)
                            {
                                //short *pshort = (short *)pixData;
                                for(long i = 0; i < nCount; i++)
                                {
                                    while(nBitsAllocated - nHighBit > 0)
                                    {
                                        pixData[i] &= ~(1 << nHighBit);
                                        nHighBit++;
                                    }

                                    int data= nRescaleSlope*pixData[i] + nRescaleIntercept;
                                    //float fdata = float (nRescaleSlope*pixData[i] + nRescaleIntercept);
                                    if(data < nWindowCenter - nWindowWidth/2)
                                    {
                                        pRgbData[i] = 0;
                                    }
                                    else if(data > nWindowCenter + nWindowWidth/2)
                                    {
                                        pRgbData[i] = 0xFF;
                                    }
                                    else
                                    {
                                        double dValue = (data + nWindowWidth/2.0f - nWindowCenter)*255.0f/nWindowWidth;

                                        int nGray = 0;
                                        if(dValue < 0)
                                        {
                                            nGray = 0;
                                        }
                                        else if(dValue > 255)
                                        {
                                            nGray = 255;
                                        }
                                        else
                                        {
                                            nGray = (int)dValue;
                                        }

                                        pRgbData[i] = nGray;
                                    }
                                }

                                QImage image = QImage((uchar*)pRgbData, nWidth, nHeight, nBandCount==1 ? QImage::Format_Indexed8 : QImage::Format_RGB888);
                                QImage image2 = image.copy();
                                image2 = image2.scaled(ui->label_dcm->width(), ui->label_dcm->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                                ui->label_dcm->setPixmap(QPixmap::fromImage(image2));
                            }
                        }
                    }

                    if(NULL != pRgbData)
                    {
                        delete []pRgbData;
                        pRgbData = NULL;
                    }

                    if(EXS_RLELossless == opt_oxfer)
                    {
                        DcmRLEDecoderRegistration::cleanup();
                    }

                    else if(opt_oxfer >= EXS_JPEGProcess1 && opt_oxfer <= EXS_JPEGLSLossy)
                    {
                        DJDecoderRegistration::cleanup(); // deregister JPEG codecs
                    }
                }
            }
            else {
                QMessageBox::information(this, "提示",  QString("Error: cannot load DICOM image (") + QString(DicomImage::getString(dcmImage->getStatus())) + QString(")"));
            }

            delete dcmImage;
            dcmImage = nullptr;
        }
    }

4、DCOM影像的转换:

QString strFilePath = QFileDialog::getSaveFileName(this, "保存对话框", QDir::currentPath(),"DICOM图像文件(*.dcm)");
    if (!strFilePath.isEmpty()){
        QString strDcmFilePath = strFilePath;//ui->lineEdit_raw->text().replace(".raw",".dcm");
        if (!strDcmFilePath.endsWith(".dcm", Qt::CaseInsensitive))
            strDcmFilePath += ".dcm";

        QFile file(ui->lineEdit_raw->text()/*"template.raw"*/);
        if (file.open(QIODevice::ReadOnly)){
            int width = 0;
            int height = 0;
            file.read((char*)&width, sizeof(int));
            file.read((char*)&height, sizeof(int));
            QByteArray pixelData = file.readAll();
            file.close();

            Uint16 samplesPerPixel = 3;
            Uint16 rows = height;
            Uint16 cols = width;
            Uint16 bitsAlloc = 8;
            Uint16 bitsStored = 8;
            Uint16 highBit = 7;
            OFString photoMetrInt = "RGB";

            DcmFileFormat fileFormat;
            OFCondition oc = fileFormat.loadFile("template.dcm");//DCOM影像有些标签需要填写,这里为了省事,直接从其他影像文件获取吧
            if (oc.bad()){
                QMessageBox::information(this, "提示",  "转换失败!");
                return;
            }

            DcmDataset *dataSet = fileFormat.getDataset();
            dataSet->putAndInsertUint16(DCM_SamplesPerPixel, samplesPerPixel);//3
            dataSet->putAndInsertString(DCM_NumberOfFrames, "1");   //1
            dataSet->putAndInsertUint16(DCM_Rows, rows);    //3200
            dataSet->putAndInsertUint16(DCM_Columns, cols); // 4000
            dataSet->putAndInsertUint16(DCM_BitsAllocated, bitsAlloc);  //8
            dataSet->putAndInsertUint16(DCM_BitsStored, bitsStored);    //8
            dataSet->putAndInsertUint16(DCM_HighBit, highBit);  //7
            dataSet->putAndInsertOFStringArray(DCM_PhotometricInterpretation, "RGB");//RGB

            dataSet->putAndInsertUint8Array(DCM_PixelData, OFreinterpret_cast(Uint8*, pixelData.data()), pixelData.size());

            DcmFileFormat dicomfile(dataSet);
            oc = dicomfile.saveFile(strDcmFilePath.toLocal8Bit().toStdString().c_str());
            if (oc.bad()){
                QMessageBox::information(this, "提示",  "转换失败!");
                return;
            }
            else{
                QMessageBox::information(this, "提示",  "转换成功!");
            }
        }
    }

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值