第三章 基於QT和DCMTK的Dicom 圖像瀏覽器---單個Dicom圖像讀取類

由於mitk.net被人惡意搶注, 中科院分子影像重點實驗室的www.mitk.net 改到 www.mitk.net.cn 。

目錄:

開始  《DCMTK(MD版)編譯和安裝+VS2015》

第一章 《DCMTK(MD版)、QT、VS2015編寫Dicom序列瀏覽應用程序-新建項目,配置環境》

第二章 《第二章 基於QT和DCMTK的Dicom 圖像瀏覽器---界面設計》

第三章 《 基於QT和DCMTK的Dicom 圖像瀏覽器---單個Dicom圖像讀取類》

第四章 《基於QT和DCMTK的Dicom 圖像瀏覽器---檢查文件夾下Dicom序列個數》

第五章 《基於QT和DCMTK的Dicom 圖像瀏覽器---Dicom圖像序列類

第六章  《基於QT和DCMTK的Dicom 圖像瀏覽器---Dicom視圖類

第七章  《基於QT和DCMTK的Dicom 圖像瀏覽器---收尾》

一、Dicom圖像簡單分類

灰度(一般爲16位灰度):有壓縮 (一般大小爲512k), 無壓縮(一般大小在100k~300k)

       彩色(RGB):有壓縮 (JPEG), 無壓縮(BPM、PNG)

 

二、讀取Dicom頭信息

使用DCMTK的兩個類 DcmFileFormat 和  DcmDataset

OFCondition  作爲返回來判斷執行信息和記錄執行日誌。

dcmff = new DcmFileFormat;
OFCondition oc = dcmff->loadFile(OFFilename(file.toLocal8Bit()));
if (oc.bad())
{
	qDebug() << "Fail:" << oc.text();
	return;
}

DcmDataset *dataset = 0;
if (!(dataset = dcmff->getDataset()))
		return;

/********讀取參數**********/
OFCondition  result;
const char *value = NULL;

// 病人信息
result = dataset->findAndGetString(DCM_PatientID, value); // 病歷號
QString	patientID = QString::fromLocal8Bit(value);

//病人名字
result = dataset->findAndGetString(DCM_PatientName, value);
patientName = QString::fromLocal8Bit(value);

result = dataset->findAndGetString(DCM_PatientBirthDate, value);
patientBirth = QDate::fromString(QString::fromLocal8Bit(value), "yyyyMMdd");

result = dataset->findAndGetString(DCM_PatientSex, value);// 性別
patientSex = QString::fromLocal8Bit(value);
	
result = dataset->findAndGetString(DCM_PatientAge, value);// 年齡
patientAge = QString::fromLocal8Bit(value);

// study information
result = dataset->findAndGetString(DCM_StudyInstanceUID, value);
studyUid = QString::fromLatin1(value);

result = dataset->findAndGetString(DCM_StudyDate, value);
studyTime.setDate(QDate::fromString(QString::fromLocal8Bit(value), "yyyyMMdd"));

result = dataset->findAndGetString(DCM_StudyTime, value);
studyTime.setTime(formatDicomTime(QString::fromLatin1(value)));
	
result = dataset->findAndGetString(DCM_StudyDescription, value);
studyDes = QString::fromLocal8Bit(value);

result = dataset->findAndGetString(DCM_ProtocolName, value);
if (result.bad())
	// 沒有讀取到;
else
	procId = QString::fromLocal8Bit(value);// 讀取成功

result = dataset->findAndGetString(DCM_BodyPartExamined, value);
bodyPart = QString::fromLocal8Bit(value);

result = dataset->findAndGetString(DCM_PatientPosition, value);
bodyPos = QString::fromLocal8Bit(value);
	

//series information
result = dataset->findAndGetString(DCM_Manufacturer, value);
manufacturer = QString::fromLocal8Bit(value);

result = dataset->findAndGetString(DCM_Modality, value);
modality = QString::fromLocal8Bit(value);

result = dataset->findAndGetString(DCM_ManufacturerModelName, value);
modelName = QString::fromLocal8Bit(value);

result = dataset->findAndGetString(DCM_AccessionNumber, value);
accessionNumber = QString::fromLatin1(value);
	
result = dataset->findAndGetString(DCM_SeriesInstanceUID, value);
seriesUid = QString::fromLatin1(value);
	
result = dataset->findAndGetString(DCM_SeriesNumber, value);
seriesNumber = QString::fromLatin1(value);
	
result = dataset->findAndGetString(DCM_SeriesDescription, value);
seriesDes = QString::fromLocal8Bit(value);

//instance information
result = dataset->findAndGetString(DCM_SOPInstanceUID, value);
instanceUid = QString::fromLatin1(value);
	
result = dataset->findAndGetString(DCM_SOPClassUID, value);
sopClassUid = QString::fromLatin1(value);
	
result = dataset->findAndGetString(DCM_InstanceNumber, value);
instanceNumber = QString(value);

result = dataset->findAndGetString(DCM_AcquisitionDate, value);
if (value == NULL) 
    result = dataset->findAndGetString(DCM_ContentDate, value);
acquisitionTime.setDate(QDate::fromString(QString::fromLatin1(value), "yyyyMMdd"));
	
result = dataset->findAndGetString(DCM_AcquisitionTime, value);
if (value == NULL) 
    result = dataset->findAndGetString(DCM_ContentTime, value);
acquisitionTime.setTime(formatDicomTime(QString::fromLatin1(value)));

result = dataset->findAndGetString(DCM_InstitutionName, value);
institution = QString::fromLocal8Bit(value);
	
result = dataset->findAndGetString(DCM_PatientPosition, value);
patientPostion = QString::fromLatin1(value);
	
result = dataset->findAndGetString(DCM_RequestingPhysician, value);
reqPhysician = QString::fromLocal8Bit(value);
	
result = dataset->findAndGetString(DCM_PerformingPhysicianName, value);
perPhysician = QString::fromLocal8Bit(value);


/*******圖像相關信息*******/

float pixelSpacingY,pixelSpacingX,sliceThickness; // 單個像素間距
result = dataset->findAndGetFloat64(DCM_PixelSpacing, pixelSpacingY, 0);
result = dataset->findAndGetFloat64(DCM_PixelSpacing, pixelSpacingX, 1);
result = dataset->findAndGetFloat64(DCM_SliceThickness, sliceThickness);


float startX,startY,sliceLocation;  // 實際起始位置
result = dataset->findAndGetFloat64(DCM_ImagePositionPatient, startX, 0);
result = dataset->findAndGetFloat64(DCM_ImagePositionPatient, startY, 1);
result = dataset->findAndGetFloat64(DCM_SliceLocation, sliceLocation);

float intercept;
result = dataset->findAndGetFloat64(DCM_RescaleIntercept, intercept);

// 窗寬和窗位
float winWidth,winCenter;
result = dataset->findAndGetFloat64(DCM_WindowWidth, winWidth);
result = dataset->findAndGetFloat64(DCM_WindowCenter, winCenter);


result = dataset->findAndGetString(DCM_KVP, value);
if (result.bad())
		kvp = 0;
else
		kvp = QString::fromLatin1(value).toDouble();

	
result = dataset->findAndGetString(DCM_Exposure, value);
if (result.bad())
		mAs = 0;
else
		mAs = QString::fromLatin1(value).toDouble();

	
result = dataset->findAndGetString(DCM_ExposureTime, value);
if (result.bad())
		mS = 0;
else
		mS = QString::fromLatin1(value).toDouble();

result = dataset->findAndGetString(DCM_XRayTubeCurrent, value);
if (result.bad())
		mA = 0;
else
		mA = QString::fromLatin1(value).toDouble();

 

二、讀取Dicom圖像數據

1) 判斷是否有壓縮:

    bool isYaSuo = false; // 無壓縮
    std::string losslessTransUID = "1.2.840.10008.1.2.4.70";
	std::string lossTransUID = "1.2.840.10008.1.2.4.51";
	std::string losslessP14 = "1.2.840.10008.1.2.4.57";
	std::string lossyP1 = "1.2.840.10008.1.2.4.50";
	std::string lossyRLE = "1.2.840.10008.1.2.5";

	E_TransferSyntax xfer = dataset->getOriginalXfer();
	
    const char*	transferSyntax = NULL;
	dcmff->getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, transferSyntax);
	
	if (transferSyntax == NULL)
		isYaSuo = false; // 無壓縮
	else {
		if (transferSyntax == losslessTransUID || transferSyntax == lossTransUID ||
			transferSyntax == losslessP14 || transferSyntax == lossyP1)
		{
			//對壓縮的圖像像素進行解壓
			DJDecoderRegistration::registerCodecs();
			dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
			DJDecoderRegistration::cleanup();
			
            isYaSuo = true; // 有壓縮
		}
		else if (transferSyntax == lossyRLE)
		{
			DcmRLEDecoderRegistration::registerCodecs();
			dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
			DcmRLEDecoderRegistration::cleanup();
			
            isYaSuo = true;// 有壓縮
		}
		else
		{
			isYaSuo = false; //無壓縮
		}

	}
	

2) 使用DicomImage 類讀取圖像像素數據 :

有壓縮的情況

         DicomImage(DcmObject *object, const E_TransferSyntax xfer,  const unsigned long flags = 0,);

         參數 object  指向DcmDataset的指針。xfer 爲壓縮解壓。flags設置爲CIF_TakeOverExternalDataset,不能析構object指針,因爲在析構DicomImage指針時,會自動析構oject,      因此只需delete dcmImage  

無壓縮的情況

         DicomImage(DcmObject *object, const E_TransferSyntax xfer,  const unsigned long flags = 0,);

         參數 object  指向DcmFileFormat的指針。xfer 爲dataset->getOriginalXfer()。flags設置爲CIF_TakeOverExternalDataset,不能析構object指針,因爲在析構DicomImage指針時,會自動析構oject,      因此只需delete dcmImage

	if (isYaSuo)
	{
		dcmImage = new DicomImage((DcmObject*)dataset, dataset->getOriginalXfer(), CIF_TakeOverExternalDataset);
		if (dcmImage->getStatus() == EIS_Normal) {

			   // 讀取正確
			}
		}
	}
	else
	{
		dcmImage = new DicomImage(dcmff, dataset->getOriginalXfer(), CIF_TakeOverExternalDataset);
		if (dcmImage->getStatus() == EIS_Normal) {
			讀取正確
		}
	}

讀取灰度圖像灰度值,如果是灰度圖像。

使用DiPixel類

DicomImage *image = dcmImage;

// 判斷是否時正確DICOM圖像
if(!(image->getStatus() == EIS_Normal))
    return ;


if(image->isMonochrome())
{

  
	const DiPixel* pixel = image->getInterData();

      //讀取圖像在像素點(x,y) 位置的值 value
    
    qint64 value;

	if (pixel && (x < image->getWidth()) && (x >= 0)
			&& (y <image->getHeight()) && (y >= 0)) {
			
            EP_Representation r = pixel->getRepresentation(); // 讀取數據類型。
			switch (r) {
				case EPR_Sint8:
                    value = *((qint8*)(pixel->getData()) + (y * image->getWidth() + x));
                    break;
				case EPR_Uint8:
					value = *((quint8*)(pixel->getData()) + (y * image->getWidth() + x));
                    break;				
				case EPR_Sint16:
                    value = *((qint16*)(pixel->getData()) + (y * image->getWidth() + x));
                    break;
				case EPR_Uint16:
                    value = *((quint16*)(pixel->getData()) + (y * image->getWidth() + x));
                    break;
				case EPR_Sint32:
                    value = *((qint32*)(pixel->getData()) + (y * image->getWidth() + x));
                    break;
				case EPR_Uint32:
                    value = *((quint32*)(pixel->getData()) + (y * image->getWidth() + x));
                    break;
			}
		}
}

讀取RGB圖像,如果是RGB圖像。

DicomImage *image = dcmImage;

// 判斷是否時正確DICOM圖像
if(!(image->getStatus() == EIS_Normal))
    return ;



if(image->isMonochrome())
{
}
else
{

    unsigned char * pixelDate=(unsigned char *) image->getOutputData(8,0,0);
    
    int w = image->getWidth();
    int h = image->getHeight();
    
    // 在像素的點(x,y) 下的RGB值
    
     B = *(pixelDate + y*w*3 + x*3 +2);
     G = *(pixelDate + y*w*3 + x*3 +1);
     R = *(pixelDate + y*w*3 + x*3);



}

三、C++類設計

對於灰度圖的僞彩色表類。添加C++類 ColorIndexTable

ColorIndexTable.h 文件

#pragma once
#include<Windows.h>

class ColorIndexTable
{
public:
	enum ColorMode
	{
		gray = 0,
		green,
		blue,
		red,
		FireLut
	};
	
	ColorIndexTable(ColorMode color);
	~ColorIndexTable();
	RGBQUAD palette[256];// 調色板RGBQUAD的大小就是256
	size_t getPaletteBits();

};

ColorIndexTable.cpp 文件

#include "ColorIndexTable.h"


const int Table_FireLutB[256] = { 0,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,
140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,217,214,211,208,
205,202,199,196,193,190,187,184,181,178,175,172,169,166,163,160,157,154,151,148,145,142,139,136,133,
130,127,124,121,118,115,112,109,106,103,100,97,94,91,88,85,82,79,76,73,70,67,64,61,58,55,52,49,46,43,40,
37,34,31,28,25,22,19,16,13,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200,200 };
const int Table_FireLutG[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,12,14,16,18,20,
22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,
92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,
192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,238,
240,242,244,246,248,250,252,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255 };
const int Table_FireLutR[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,9,12,15,18,21,
24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,
120,123,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,
192,195,198,201,204,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249,252,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 };


ColorIndexTable::ColorIndexTable(ColorMode color)
{
	memset(palette, 0, sizeof(palette));
	switch (color)
	{
	case gray:
		// 灰度
		for (int i = 0; i < 256; ++i) {
			palette[i].rgbBlue = i;
			palette[i].rgbGreen = i;
			palette[i].rgbRed = i;
		}
		break;
	case green:
		// 綠色
		for (int i = 0; i < 256; ++i) {
			palette[i].rgbBlue = 0;
			palette[i].rgbGreen = i;
			palette[i].rgbRed = 0;
		}
		break;
	case blue:
		// 藍色
		for (int i = 0; i < 256; ++i) {
			palette[i].rgbBlue = i;
			palette[i].rgbGreen = 0;
			palette[i].rgbRed = 0;
		}
		break;
	case red:
		// 紅色
		for (int i = 0; i < 256; ++i) {
			palette[i].rgbBlue = 0;
			palette[i].rgbGreen = 0;
			palette[i].rgbRed = i;
		}
		break;
	case FireLut:
		// 從Table_FireLut表索引
		for (int i = 0; i < 256; ++i) {
			palette[i].rgbBlue = Table_FireLutB[i];
			palette[i].rgbGreen = Table_FireLutG[i];
			palette[i].rgbRed = Table_FireLutR[i];
		}
		break;
	default:
		break;
	}
}

ColorIndexTable::~ColorIndexTable()
{
}

size_t ColorIndexTable::getPaletteBits()
{
	return sizeof(palette);
}

添加單個圖像讀取類

image.h

#pragma once
#include <QString>
#include <QPixmap>

#include "dcmtk/dcmimgle/diutils.h"

class DicomImage;
class DcmFileFormat;
class DiPixel;
class Image
{
public:
	explicit Image(const QString &file);
	~Image();

	// 判斷是否讀取成功
	bool isNormal() const;

	// 窗寬窗位
	void getWindow(double &center, double &width) const
	{
		center = winCenter; width = winWidth;
	}
	
	QString getSeriesUID() const
	{
		return seriesUID;
	}
	int getInstanceNumber();

	bool getPixSpacing(double & spacingX, double & spacingY, double & spacingZ) const;
	bool getImageSize(int &width, int &height) const;
	bool getPixmap(QPixmap & pixmap); // 得到該圖像的位圖 pixmap

	QString getPixInfo(int x, int y); // 在(x,y) 處的像素值
	bool isMonochrome(); // 是否是灰度圖
	const DiPixel *getInternalPtr();

	static bool DicomImageToPixmap(DicomImage & dcmImage, QPixmap & pixmap);
	static bool UcharArrayToPixmap(uchar *data, int w, int h,int bitSize, QPixmap & pixmap,int biBitCount=8);

	//set
	static void setColor(int &color)
	{
		Image::color = color;
	}

	void setWindow(const double &center, const double &width)
	{
		winCenter = center; winWidth = width;
	}
	void setWindowDelta(const double &dCenter, const double &dWidth)
	{
		winCenter += dCenter; winWidth += dWidth;
	}
	void setRoiWindow(const QRectF &rect);

private:
	// 圖像所屬序列的唯一標識
	QString seriesUID;
	// 圖像在序列中的編號(位置)
	QString instanceNumber;

	// 像素間距,用於顯示比例
	double spaceX, spaceY, spaceZ;

	// 圖像寬度、高度
	int imageWidth, imageHeight;

	// 窗寬、位
	double winWidth;
	double winCenter;
	
	DcmFileFormat *dcmff;
	DicomImage *dcmImage;

	// 顏色映射(灰度圖像有效)
	static int color; // 選擇僞彩色

	void init(); // 對屬性賦值
};

image.cpp

#include "Image.h"
#include "ColorIndexTable.h"

#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmimgle/dcmimage.h"
#include "dcmtk/dcmdata/dcdeftag.h"
#include "dcmtk/dcmdata/dctk.h"  
#include "dcmtk/dcmdata/dcrledrg.h" 
#include "dcmtk/dcmimage/diregist.h"
#include "dcmtk/dcmjpeg/djdecode.h"

#include <qdebug.h>

Image::Image(const QString &file):dcmff(new DcmFileFormat), dcmImage(0)
{
	OFCondition oc = dcmff->loadFile(OFFilename(file.toLocal8Bit()));
	if (oc.bad())
	{
		qDebug() << "Fail:" << oc.text();
		return; // 此時 dcmImage=0; 不執行init()
	}
	init();
}

Image::~Image()
{
	if (dcmImage)
	{
		delete dcmImage; 
		dcmImage = 0;
		dcmff = 0;
		/*創建dcmImage時設置了CIF_TakeOverExternalDataset因此只需delete dcmImage*/
	}
	else {
		delete dcmff; dcmff = 0;
	}
}

bool Image::isNormal() const
{
	return dcmImage && (dcmImage->getStatus() == EIS_Normal);
}

void Image::init()
{
	DcmDataset *dataset = 0;
	OFCondition result;
	const char *value = NULL;
	if (!(dataset = dcmff->getDataset()))
		return;

	// 頭信息讀取
	result = dataset->findAndGetString(DCM_SeriesInstanceUID, value);
	if (result.bad())
		return;
	seriesUID = QString::fromLatin1(value);

	result = dataset->findAndGetString(DCM_InstanceNumber, value);
	if (result.bad())
		return;
	instanceNumber = QString(value);

	result = dataset->findAndGetFloat64(DCM_PixelSpacing, spaceY, 0);
	if (result.bad())
		spaceY = 1;

	result = dataset->findAndGetFloat64(DCM_PixelSpacing, spaceX, 1);
	if (result.bad())
		spaceX = 1;

	result = dataset->findAndGetFloat64(DCM_SliceThickness, spaceZ);
	if (result.bad())
		spaceZ = 1;

	result = dataset->findAndGetFloat64(DCM_WindowWidth, winWidth);
	result = dataset->findAndGetFloat64(DCM_WindowCenter, winCenter);

	// 創建DcmImage
	/********解壓縮**********/
	bool isYaSuo = 0;
	std::string losslessTransUID = "1.2.840.10008.1.2.4.70";
	std::string lossTransUID = "1.2.840.10008.1.2.4.51";
	std::string losslessP14 = "1.2.840.10008.1.2.4.57";
	std::string lossyP1 = "1.2.840.10008.1.2.4.50";
	std::string lossyRLE = "1.2.840.10008.1.2.5";

	E_TransferSyntax xfer = dataset->getOriginalXfer();
	const char*	transferSyntax = NULL;
	dcmff->getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, transferSyntax);
	
	if (transferSyntax == NULL)
		isYaSuo = false;// 無壓縮
	else {
		
		if (transferSyntax == losslessTransUID || transferSyntax == lossTransUID ||
			transferSyntax == losslessP14 || transferSyntax == lossyP1)
		{
			//對壓縮的圖像像素進行解壓
			DJDecoderRegistration::registerCodecs();
			dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
			DJDecoderRegistration::cleanup();
			isYaSuo = true;// 有壓縮
		}
		else if (transferSyntax == lossyRLE)
		{
			DcmRLEDecoderRegistration::registerCodecs();
			dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
			DcmRLEDecoderRegistration::cleanup();
			isYaSuo = true;// 有壓縮
		}
		else
		{
			isYaSuo = false;// 無壓縮
		}

	}

	if (isYaSuo)
	{
		dcmImage = new DicomImage((DcmObject*)dataset, dataset->getOriginalXfer(), CIF_TakeOverExternalDataset);
		if (dcmImage->getStatus() == EIS_Normal) {

			imageWidth = dcmImage->getWidth();
			imageHeight = dcmImage->getHeight();
			if (winWidth < 1) {
				// 設置窗寬窗位
				dcmImage->setRoiWindow(0, 0, imageWidth, imageHeight);
				// 重新對winCenter, winWidth賦值
				dcmImage->getWindow(winCenter, winWidth);
			}
		}
	}
	else
	{
		dcmImage = new DicomImage(dcmff, dataset->getOriginalXfer(), CIF_TakeOverExternalDataset);
		if (dcmImage->getStatus() == EIS_Normal) {
			imageWidth = dcmImage->getWidth();
			imageHeight = dcmImage->getHeight();
			if (winWidth < 1) {
				dcmImage->setRoiWindow(0, 0, imageWidth, imageHeight);
				dcmImage->getWindow(winCenter, winWidth);
			}
		}
	}
}

int Image::getInstanceNumber()
{
	return instanceNumber.toInt();
}

bool Image::getPixSpacing(double & spacingX, double & spacingY, double & spacingZ) const
{
	if (isNormal()) {
		spacingX = spaceX;
		spacingY = spaceY;
		spacingZ = spaceZ;
		return true;
	}
	return false;
}

bool Image::getImageSize(int & width, int & height) const
{
	if(!isNormal())
		return false;
	width = imageWidth; height = imageHeight;
	return true;
}

bool Image::getPixmap(QPixmap & pixmap)
{
	if (isNormal()) {
		dcmImage->setWindow(winCenter, winWidth);
		return DicomImageToPixmap(*dcmImage, pixmap);
	}
	return false;
}

QString Image::getPixInfo(int x, int y)
{
	if (!isNormal())
		return"";

	if (dcmImage->isMonochrome())
	{
		const DiPixel* pixel = dcmImage->getInterData();

		//讀取圖像在像素點(x,y) 位置的值 value
		qint64 value = 0;
		if (pixel && (x < imageWidth) && (x >= 0)
			&& (y <imageHeight) && (y >= 0)) {

			EP_Representation r = pixel->getRepresentation(); // 讀取數據類型。
			switch (r) {
			case EPR_Sint8:
				value = *((qint8*)(pixel->getData()) + (y * imageWidth + x));
				break;
			case EPR_Uint8:
				value = *((quint8*)(pixel->getData()) + (y * imageWidth + x));
				break;
			case EPR_Sint16:
				value = *((qint16*)(pixel->getData()) + (y * imageWidth + x));
				break;
			case EPR_Uint16:
				value = *((quint16*)(pixel->getData()) + (y * imageWidth + x));
				break;
			case EPR_Sint32:
				value = *((qint32*)(pixel->getData()) + (y * imageWidth + x));
				break;
			case EPR_Uint32:
				value = *((quint32*)(pixel->getData()) + (y * imageWidth + x));
				break;
			}
		}
	
		return QStringLiteral("灰度值:%1").arg(value); // 帶中文字符是使用QStringLiteral
	}else
	{
		unsigned char * pixelDate = (unsigned char *)dcmImage->getOutputData(8, 0, 0);

		// 在像素的點(x,y) 下的RGB值
		int B = 0; int G = 0; int R = 0;
		if (pixelDate && (x < imageWidth) && (x >= 0)
			&& (y < imageHeight) && (y >= 0))
		{
			 B = *(pixelDate + y*imageWidth * 3 + x * 3 + 2);
			 G = *(pixelDate + y*imageWidth * 3 + x * 3 + 1);
			 R = *(pixelDate + y*imageWidth * 3 + x * 3);
		}
		return QStringLiteral("R:%1, G:%2, B:%3").arg(R).arg(G).arg(B); // 帶中文字符是使用QStringLiteral
	}
}

bool Image::isMonochrome()
{
	return dcmImage->isMonochrome();
}

const DiPixel * Image::getInternalPtr()
{
	return isNormal() ? dcmImage->getInterData() : nullptr;
}

bool Image::DicomImageToPixmap(DicomImage & dcmImage, QPixmap & pixmap)
{
	bool res = true;

	void *pDIB = NULL;
	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 Image::UcharArrayToPixmap(uchar *data, int w, int h, int bitSize, QPixmap & pixmap, int biBitCount = 8)
{
	//位圖文件由四部分依序組成:BITMAPFILEHEADER,BITMAPINFOHEADER,調色板,Image Data。
	BITMAPFILEHEADER lpfh;// 文件頭  固定的14個字節, 描述文件的有關信息
	BITMAPINFOHEADER lpih;// 固定的40個字節,描述圖像的有關信息

	ColorIndexTable rgbquad((ColorIndexTable::ColorMode)color);
	RGBQUAD *palette = rgbquad.palette;// 調色板RGBQUAD的大小就是256

	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) + rgbquad.getPaletteBits();


	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) + rgbquad.getPaletteBits() + size;

	QByteArray bmp;
	bmp.append((char*)&lpfh, sizeof(BITMAPFILEHEADER));
	bmp.append((char*)&lpih, sizeof(BITMAPINFOHEADER));
	bmp.append((char*)palette, rgbquad.getPaletteBits());
	bmp.append((char*)pDIB, size);
	
	return pixmap.loadFromData(bmp);
}

void Image::setRoiWindow(const QRectF & rect)
{
	if (!isNormal())
		return;

	dcmImage->setRoiWindow(rect.left(), rect.top(), rect.width(), rect.height());
	dcmImage->getWindow(winCenter, winWidth);
}

int Image::color=0;

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章