#include "esImageData.h"
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmimgle/dcmimage.h"
#include "dcmtk/dcmjpeg/djdecode.h" /* for dcmjpeg decoders */
#include "dcmtk/dcmjpeg/djencode.h" /* for dcmjpeg encoders */
#include "dcmtk/dcmdata/dcrledrg.h" /* for DcmRLEDecoderRegistration */
#include "dcmtk/dcmdata/dcrleerg.h" /* for DcmRLEEncoderRegistration */
#include "dcmtk/dcmjpeg/dipijpeg.h" /* for dcmimage JPEG plugin */
#include "dcmtk/config/osconfig.h"
#include "dcmtk/ofstd/ofstdinc.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/dcmdata/cmdlnarg.h"
#include "dcmtk/dcmimage/diregist.h"
#include "dcmtk/ofstd/ofstd.h"
#include "dcmtk/dcmimgle/digsdfn.h"
#include <QDebug>
#pragma execution_character_set("utf-8")
esImageData::esImageData(QObject *parent)
: QObject(parent)
{
setAutoDelete(false);
m_readFlag = false;
m_dcmFile = new DcmFileFormat;
opt_oxfer = EXS_LittleEndianExplicit;
m_RescaleIntercept = 0;
m_RescaleSlope = 1;
}
esImageData::~esImageData()
{
if (m_dcmFile != NULL)
{
m_dcmFile->clear();
delete m_dcmFile;
m_dcmFile = NULL;
}
}
bool esImageData::GetReadFlag()
{
return m_readFlag;
}
DcmFileFormat *esImageData::GetDcmFileFormat()
{
return m_dcmFile;
}
void esImageData::spacing(double spacing[3])
{
spacing[0] = m_spaceX;
spacing[1] = m_spaceY;
spacing[2] = m_spaceZ;
}
void esImageData::ImagePositionPatient(double ImagePositionPatient[3])
{
for (size_t i = 0; i < 3; i++)
{
ImagePositionPatient[i] = m_ImagePositionPatient[i];
}
}
bool esImageData::DicomImageToPixmap(DicomImage& dcmImage, QPixmap& pixmap)
{
bool res = true;
void* pDIB = nullptr;
int size = 0;
if (dcmImage.isMonochrome())
{
// 灰度图像
size = dcmImage.createWindowsDIB(pDIB, 0, 0, 8, 1, 1);
if (!pDIB)
return false;
res = UcharArrayToPixmap((uchar*)pDIB, dcmImage.getWidth(), dcmImage.getHeight(), size, pixmap);
}
else
{
// RGB图像
size = dcmImage.createWindowsDIB(pDIB, 0, 0, 24, 1, 1);
if (!pDIB)
return false;
res = UcharArrayToPixmap((uchar*)pDIB, dcmImage.getWidth(), dcmImage.getHeight(), size, pixmap, 24);
}
delete pDIB;
return res;
}
bool esImageData::UcharArrayToPixmap(uchar* data, int w, int h, int bitSize, QPixmap& pixmap, int biBitCount)
{
//位图文件由四部分依序组成:BITMAPFILEHEADER,BITMAPINFOHEADER,调色板,Image Data。
BITMAPFILEHEADER lpfh;// 文件头 固定的14个字节, 描述文件的有关信息
BITMAPINFOHEADER lpih;// 固定的40个字节,描述图像的有关信息
RGBQUAD palette[256];// 调色板RGBQUAD的大小就是256
memset(palette, 0, sizeof(palette));
for (int i = 0; i < 256; ++i) {
palette[i].rgbBlue = i;
palette[i].rgbGreen = i;
palette[i].rgbRed = i;
}
memset(&lpfh, 0, sizeof(BITMAPFILEHEADER));
lpfh.bfType = 0x4d42;//'B''M' must be 0x4D42.
//the sum bits of BITMAPFILEHEADER,BITMAPINFOHEADER and RGBQUAD;the index byte of the image data.
lpfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(palette);
memset(&lpih, 0, sizeof(BITMAPINFOHEADER));
lpih.biSize = sizeof(BITMAPINFOHEADER); //the size of this struct. it is 40 bytes.
lpih.biWidth = w;
lpih.biHeight = h;
lpih.biCompression = BI_RGB;
lpih.biPlanes = 1; //must be 1.
void* pDIB = data;
int size = bitSize;
lpih.biBitCount = biBitCount;
//the size of the whole bitmap file.
lpfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(palette) + size;
QByteArray bmp;
bmp.append((char*)&lpfh, sizeof(BITMAPFILEHEADER));
bmp.append((char*)&lpih, sizeof(BITMAPINFOHEADER));
bmp.append((char*)palette, sizeof(palette));
bmp.append((char*)pDIB, size);
return pixmap.loadFromData(bmp);
}
bool esImageData::ReadDicomFile(const QString& filename)
{
m_readFlag = false;
m_filename = filename;
QByteArray fileNameba = filename.toLocal8Bit();
OFCondition oc = m_dcmFile->loadFile(OFFilename(fileNameba.data()));
if (oc.bad())
{
qDebug() <<"read "<< fileNameba.data() << " Fail:" << oc.text();
return false;
}
DcmDataset* dataset = 0;
OFCondition result;
const char* value = nullptr;
if (!(dataset = m_dcmFile->getDataset()))
return false;
result = dataset->findAndGetFloat64(DCM_PixelSpacing, m_spaceX, 1);
if (result.bad())
m_spaceX = 1;
result = dataset->findAndGetFloat64(DCM_PixelSpacing, m_spaceY, 0);
if (result.bad())
m_spaceY = 1;
result = dataset->findAndGetFloat64(DCM_SpacingBetweenSlices, m_spaceZ);
if (result.bad())
{
result = dataset->findAndGetFloat64(DCM_SliceThickness, m_spaceZ);
if (result.bad())
m_spaceZ = 1;
}
result = dataset->findAndGetFloat64(DCM_WindowWidth, m_winWidth);
result = dataset->findAndGetFloat64(DCM_WindowCenter, m_winCenter);
//信息获取
//Patient related information
OFString pid, pname, psex, pbirth;
dataset->findAndGetOFString(DCM_PatientID, pid);
//m_PatientId = QString(pid.c_str());
m_PatientId = QString(pid.c_str());
dataset->findAndGetOFString(DCM_PatientName, pname);
//m_PatientName = QString(pname.c_str());
m_PatientName = QString(pname.c_str());
dataset->findAndGetOFString(DCM_PatientBirthDate, pbirth);
m_PatientBirth = QString(pbirth.c_str());
dataset->findAndGetOFString(DCM_PatientSex, psex);
//m_PatientGender = QString(psex.c_str());
m_PatientGender = QString(psex.c_str());
//study related information
OFString snumber, sid, sdate, stime, sdescription, sbodypart;
dataset->findAndGetOFString(DCM_AccessionNumber, snumber);
m_AccessionNumber = QString(snumber.c_str());
dataset->findAndGetOFString(DCM_StudyInstanceUID, sid);//unique
m_StudyInstanceId = QString(sid.c_str());
dataset->findAndGetOFString(DCM_StudyDate, sdate);
dataset->findAndGetOFString(DCM_StudyTime, stime);
m_StudyDate = QString(sdate.c_str());
m_StudyDateTime = QString(sdate.c_str()) + " " + QString(stime.c_str()).left(6);
dataset->findAndGetOFString(DCM_StudyDescription, sdescription);
//m_StudyDescription = QString(sdescription.c_str());
m_StudyDescription = QString(sdescription.c_str());
dataset->findAndGetOFString(DCM_BodyPartExamined, sbodypart);
//m_StudyBodyPart = QString(sbodypart.c_str());
m_StudyBodyPart = QString(sbodypart.c_str());
//Series related information
OFString id, number, time, date, description, modality, imageorient;
dataset->findAndGetOFString(DCM_SeriesInstanceUID, id);
m_SeriesInstanceId = QString(id.c_str());
dataset->findAndGetOFString(DCM_SeriesNumber, number);
m_SeriesNumber = QString(number.c_str());
dataset->findAndGetOFString(DCM_InstanceNumber, number);
m_InstanceNumber = QString(number.c_str());
result = dataset->findAndGetFloat64(DCM_ImagePositionPatient, m_ImagePositionPatient[0], 0);
if (result.bad())
{ }
result = dataset->findAndGetFloat64(DCM_ImagePositionPatient, m_ImagePositionPatient[1], 1);
if (result.bad())
{ }
result = dataset->findAndGetFloat64(DCM_ImagePositionPatient, m_ImagePositionPatient[2], 2);
dataset->findAndGetOFString(DCM_Modality, modality);
m_SeriesModality = QString(modality.c_str());
dataset->findAndGetOFString(DCM_SeriesDescription, description);
//m_SeriesDescription = QString(description.c_str());
m_SeriesDescription = QString(description.c_str());
dataset->findAndGetOFString(DCM_ImageOrientationPatient, imageorient);
m_SeriesImageOrientation = QString(imageorient.c_str());
//图像信息
OFString RescaleIntercept, RescaleSlope;
result=dataset->findAndGetOFString(DCM_RescaleIntercept, RescaleIntercept);
if (result.good())
{
m_RescaleIntercept = QString(RescaleIntercept.c_str()).toDouble();
}
result=dataset->findAndGetOFString(DCM_RescaleSlope, RescaleSlope);
if (result.good())
{
m_RescaleSlope = QString(RescaleSlope.c_str()).toDouble();
}
dataset->findAndGetUint16(DCM_PixelRepresentation, m_PixelRepresentation);
dataset->findAndGetUint16(DCM_SamplesPerPixel, m_SamplesPerPixel);
dataset->findAndGetUint16(DCM_BitsAllocated, m_BitsAllocated);
Uint16 nRows = 0;
dataset->findAndGetUint16(DCM_Rows, nRows);
this->m_Height = (int)nRows;
Uint16 nCols = 0;
dataset->findAndGetUint16(DCM_Columns, nCols);
this->m_Width = (int)nCols;
//this->m_Depth = fileCount;
//this->m_SizeofImage = m_Height * m_Width;
this->m_AlignWidth = (m_Width + 3) / 4 * 4; //4字节对齐
unsigned short bytes_per_pixel = m_BitsAllocated * m_SamplesPerPixel / 8;
m_ImageArraySize = m_Width * m_Height * bytes_per_pixel;
OFString window_width, window_center;
dataset->findAndGetOFString(DCM_WindowWidth, window_width);
dataset->findAndGetOFString(DCM_WindowCenter, window_center);
const char* c = window_center.data();
this->m_WindowCenter = atoi(c);
const char* w = window_width.data();
this->m_WindowWidth = atoi(w);
//--------------------------------------------------------
m_readFlag = true;
return true;
}
bool esImageData::LoadPixelData(Uint8*&pixelData, int &pixelType)
{
return LoadPixelData(m_dcmFile->getDataset(), pixelData, pixelType);
}
QString esImageData::GetTagInfo(Uint16 g, Uint16 e)
{
QString str;
DcmDataset* dataset = m_dcmFile->getDataset();
if (dataset)
{
OFString ofstr;
dataset->findAndGetOFString(DcmTagKey(g,e), ofstr);
str = QString(ofstr.c_str());
}
dataset = NULL;
return str;
}
bool esImageData::DecompressFile(DcmDataset* dataset)
{
bool resFlag=true;
/********解压缩**********/
const char* transferSyntax = nullptr;
m_dcmFile->getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, transferSyntax);
OFCondition error = EC_Normal;
if (strcmp(transferSyntax,UID_JPEGProcess14SV1TransferSyntax)==0 || strcmp(transferSyntax , UID_JPEGProcess2_4TransferSyntax) == 0 ||
strcmp(transferSyntax , UID_JPEGProcess14TransferSyntax) == 0 || strcmp(transferSyntax , UID_JPEGProcess1TransferSyntax) == 0)
{
error=dataset->chooseRepresentation(opt_oxfer, nullptr);
}
else if (strcmp(transferSyntax ,UID_RLELosslessTransferSyntax)==0)
{
error=dataset->chooseRepresentation(opt_oxfer, nullptr);
}
if (error.bad())
{
if (error == EJ_UnsupportedColorConversion)
qDebug() << ("Try --conv-never to disable color space conversion\n");
else if (error == EC_CannotChangeRepresentation)
qDebug()<<QString("Input transfer syntax %1 not supported").arg(transferSyntax);
resFlag = false;
}
return resFlag;
}
bool esImageData::LoadPixelData(DcmDataset* dataset, Uint8*&pixelData,int& pixelType)
{
bool resFlag = false;
bool decompressFlag = true;
DcmXfer xfer (dataset->getOriginalXfer());
const char* xfer_id = xfer.getXferID();
if ((strcmp(xfer_id, UID_BigEndianExplicitTransferSyntax))
&& (strcmp(xfer_id, UID_LittleEndianImplicitTransferSyntax)) &&
(strcmp(xfer_id, UID_LittleEndianExplicitTransferSyntax)))
{
decompressFlag = DecompressFile(dataset);
}
if (!decompressFlag)
return resFlag;
DcmElement* element = NULL;
if (dataset->findAndGetElement(DCM_PixelData, element).good())
{
//element->detachValueField();
Uint8*tmpPixelData = NULL;
OFCondition result = element->getUint8Array(tmpPixelData);
if (result.good() && tmpPixelData)
{
memcpy(pixelData, tmpPixelData, m_ImageArraySize);
pixelType = 0;
resFlag = true;
}
}
else if (dataset->findAndGetElement(DCM_FloatPixelData, element).good())
{
Float32*tmpPixelData = NULL;
//element->detachValueField();
OFCondition result = element->getFloat32Array(tmpPixelData);
if (result.good() && tmpPixelData)
{
memcpy(pixelData, (Uint8*)tmpPixelData, m_ImageArraySize);
pixelType = 0;
resFlag = true;
}
}
else if (dataset->findAndGetElement(DCM_DoubleFloatPixelData, element).good())
{
//element->detachValueField();
Float64*tmpPixelData = NULL;
OFCondition result = element->getFloat64Array(tmpPixelData);
if (result.good() && tmpPixelData)
{
memcpy(pixelData, (Uint8*)tmpPixelData, m_ImageArraySize);
pixelType = 0;
resFlag = true;
}
dataset->remove(DCM_PixelData);
}
//if (element)
//{
// delete element;
// element = NULL;
//}
//DicomImage * m_pDcmImage = new DicomImage(m_dcmFile, dataset->getOriginalXfer(), CIF_TakeOverExternalDataset);
//if (m_pDcmImage->getStatus() == EIS_Normal)
//{
// const DiPixel *pixel = m_pDcmImage->getInterData();
// memcpy(pixelData, pixel->getData(), m_ImageArraySize);
// resFlag = true;
//}
//delete m_pDcmImage;
return resFlag;
}
bool esImageData::RescaledImageDataIsDecimal()
{
return RescaledImageDataIsDecimal(m_RescaleSlope, m_RescaleIntercept);
}
bool esImageData::RescaledImageDataIsSigned()
{
return RescaledImageDataIsSigned(m_PixelRepresentation,m_RescaleSlope, m_RescaleIntercept);
}
bool esImageData::RescaledImageDataIsDecimal(double RescaleSlope,double RescaleOffset)
{
int s = int(RescaleSlope);
int o = int(RescaleOffset);
float sf = float(s);
float of = float(o);
double d1 = fabs(sf - RescaleSlope);
double d2 = fabs(of - RescaleOffset);
if (d1 > 0.0 || d2 > 0.0)
{
return true;
}
else
{
return false;
}
}
bool esImageData::RescaledImageDataIsSigned(int PixelRepresentation,double RescaleSlope, double RescaleOffset)
{
bool rescaleSigned = (RescaleSlope < 0.0);
bool pixelRepSigned = (PixelRepresentation == 1);
bool offsetSigned = (RescaleOffset < 0.0);
return (rescaleSigned || pixelRepSigned || offsetSigned);
}
//-------------------------------------
//线程池加速
#include "vtkSetGet.h"
int esImageData::GetScalarType()
{
DcmDataset*dataset = m_dcmFile->getDataset();
int destScalarType = -1;
DcmElement* element = NULL;
if (dataset->findAndGetElement(DCM_FloatPixelData, element).good())
{
destScalarType = VTK_FLOAT;
}
else if (dataset->findAndGetElement(DCM_DoubleFloatPixelData, element).good())
{
destScalarType = VTK_DOUBLE;
}
else if (dataset->findAndGetElement(DCM_PixelData, element).good())
{
double rescaleIntercept = this->RescaleIntercept();
double rescaleSlope = this->RescaleSlope();
bool isFloat = this->RescaledImageDataIsDecimal();
bool signedFlag = this->RescaledImageDataIsSigned();
int bitAllocated = this->BitsAllocated();
if (bitAllocated == 8)
{
destScalarType = VTK_UNSIGNED_CHAR;
}
else if (bitAllocated == 16)
{
if (signedFlag)
destScalarType = VTK_SHORT;
else
destScalarType = VTK_UNSIGNED_SHORT;
}
else if (bitAllocated == 32)
{
destScalarType = VTK_INT;
if (isFloat)
destScalarType = VTK_FLOAT;
}
else
destScalarType = -1;
}
//if (element)
//{
// delete element;
// element = NULL;
//}
return destScalarType;
}
void esImageData::run()
{
loadPixelResult = false;
int destScalarType = GetScalarType();
if (destScalarType == -1)
return;
loadPixelResult=LoadPixelData(tmpPixelData, pixelType);
if (loadPixelResult)
{
int frameSize = m_Width * m_Height;
switch (destScalarType) {
vtkTemplateMacro(
{
VTK_TT*curFramePtr = (VTK_TT*) tmpPixelData;
std::for_each(curFramePtr, curFramePtr + frameSize - 1,
[&](VTK_TT &val) {val = val * m_RescaleSlope + m_RescaleIntercept; });
});
}
}
}
最新发布