时间紧任务重,直接上代码吧:
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, "提示", "转换成功!");
}
}
}