当前位置:   article > 正文

DICOM笔记-使用DCMTK读取DICOM文件保存DICOM文件_dcmtk dicom 读取

dcmtk dicom 读取

记录之前写过一个读取DICOM文件,修改对应Tag标签内容后,保存为新的DICOM文件的例子;
其中的对DICOM信息处理的过程为,将DICOM中的一系列连续DICOM图像,处理后生成一张多帧的DICOM文件;
主要步骤为:
1.读取DICOM文件;
2.对DICOM文件中的信息处理,修改;
3.保存为新的DICOM文件;

读取DICOM文件

读取DICOM文件的信息,使用一系列的findAndGetOFXXX方法;
可以根据DICOM标签中的VR标识来选择,DCMTK库中每个findAndGetOFXXX方法都有详细的注释;
在这里插入图片描述
读取DICOM文件的步骤为:

DcmFileFormat* nm_dcm_format = new DcmFileFormat;		
OFCondition cond = nm_dcm_format->loadFile(nm_file.c_str());
// DICOM信息头
DcmMetaInfo* meta_info = nm_dcm_format->getMetaInfo();
// DICOM信息
DcmDataset* dataset = nm_dcm_format->getDataset();
OFString new_instance_id;
if (meta_info->findAndGetOFString(DCM_MediaStorageSOPInstanceUID, new_instance_id).good())
{
	instance_id = new_instance_id.c_str();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

保存DICOM文件

保存DICOM文件就很简单了。对应findAndGetOFXXX方法有putAndInsertXXX方法来设置DICOM标签对应的信息;

// 1.构建DICOM文件的信息;
DcmFileFormat* nm_dcm_format = new DcmFileFormat;
DcmDataset* dataset = nm_dcm_format->getDataset();
dataset->putAndInsertString(DCM_FrameOfReferenceUID, series_instance_id.c_str());
// 2.使用saveFile方法,保存DICOM文件;
nm_dcm_format->saveFile(mult_pet_file.c_str());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:DICOM标签内的数据长度必须是偶数,如果实际内容为奇数,就需要补足为偶数字节个数;

主要代码


std::string getTime()
{
	time_t timep;
	time(&timep);
	struct tm* p = localtime(&timep);
	char tmp[64] = { 0 };
	sprintf(tmp, "%02d%02d%02d.0000 ", p->tm_hour, p->tm_min, p->tm_sec);
	return tmp;
}

class Dicom_info
{
public:
	Dicom_info(DcmFileFormat* nm_dcm_format)
		:number_of_frames(0)
	{
		DcmMetaInfo* meta_info = nm_dcm_format->getMetaInfo();
		DcmDataset* dataset = nm_dcm_format->getDataset();
		// 0002,0003序列ID;
		OFString new_instance_id;
		if (meta_info->findAndGetOFString(DCM_MediaStorageSOPInstanceUID, new_instance_id).good())
		{
			instance_id = new_instance_id.c_str();
		}
		OFString of_series_instance_id;
		if (dataset->findAndGetOFString(DCM_SeriesInstanceUID, of_series_instance_id).good())
		{
			series_instance_id = of_series_instance_id.c_str();
		}
		OFString of_frame_referenceUID;
		if (dataset->findAndGetOFString(DCM_FrameOfReferenceUID, of_frame_referenceUID).good())
		{
			frame_referenceUID = of_frame_referenceUID.c_str();
		}
		const char* pbuf = NULL;
		if (dataset->findAndGetString(DCM_PixelSpacing, pbuf).good())
		{
			pixel_spacings = Tool::DealString::SplitString(pbuf, "\\");
		}

		if (!dataset->findAndGetUint16(DCM_Rows, rows).good())
		{
			rows = 0;
		}
		if (!dataset->findAndGetUint16(DCM_Columns, columns).good())
		{
			columns = 0;
		}

		const Uint16* pix_inbuf = nullptr;
		unsigned long size = 0;
		if (dataset->findAndGetUint16Array(DCM_PixelData, pix_inbuf, &size).good())
		{
			pix_buf = new float[size];
			for (size_t i = 0; i < size; i++)
			{
				pix_buf[i] = pix_inbuf[i];
			}
		}
		OFString numberOfFrames;
		if (dataset->findAndGetOFString(DCM_NumberOfFrames, numberOfFrames).good())
		{
			number_of_frames = atoi(numberOfFrames.c_str());
		}
	}
	~Dicom_info()
	{
		if (pix_buf != NULL)
		{
			delete[]pix_buf;
		}
	}

	int ChangeDcmFileFormat(DcmFileFormat* nm_dcm_format, float* pinbuf, int rows, int columns, int num)
	{
		try
		{
			DcmMetaInfo* meta_info = nm_dcm_format->getMetaInfo();
			DcmDataset* dataset = nm_dcm_format->getDataset();
			instance_id += Superaddition;
			CheckStringLengthIsEvenSize(instance_id);
			meta_info->putAndInsertString(DCM_MediaStorageSOPInstanceUID, instance_id.c_str());
			dataset->putAndInsertString(DCM_SOPInstanceUID, instance_id.c_str());

			series_instance_id += Superaddition;
			CheckStringLengthIsEvenSize(series_instance_id);
			dataset->putAndInsertString(DCM_SeriesInstanceUID, series_instance_id.c_str());

			frame_referenceUID += Superaddition;
			CheckStringLengthIsEvenSize(frame_referenceUID);
			dataset->putAndInsertString(DCM_FrameOfReferenceUID, series_instance_id.c_str());

			std::string cur_time = getTime();
			dataset->putAndInsertString(DCM_InstanceCreationTime, cur_time.c_str());
			dataset->putAndInsertString(DCM_ImageType, "RECON TOMO");
			//dataset->putAndInsertString(DCM_SeriesDescription, "MEMRS RECON RESULTS ");
			std::string org_value = pixel_spacings.at(0);
			std::string neg_value = "-" + org_value;
			CheckStringLengthIsEvenSize(org_value);
			CheckStringLengthIsEvenSize(neg_value);
			dataset->putAndInsertString(DCM_SliceThickness, org_value.c_str());
			dataset->putAndInsertString(DCM_SpacingBetweenSlices, neg_value.c_str());
			dataset->putAndInsertString(DCM_AcquisitionTerminationCondition, "MANU");
			std::string num_str = std::to_string(num);
			CheckStringLengthIsEvenSize(num_str);
			dataset->putAndInsertString(DCM_NumberOfFrames, num_str.c_str());
			dataset->putAndInsertUint16(DCM_NumberOfSlices, num);
			dataset->putAndInsertUint16(DCM_Rows, rows);
			dataset->putAndInsertUint16(DCM_Columns, columns);
			dataset->putAndInsertString(DCM_CorrectedImage, "ATTN");
			std::string image_orientation = "1.000000\\0.000000\\0.000000\\0.000000\\1.000000\\0.000000";
			CheckStringLengthIsEvenSize(image_orientation);
			DcmItem* sq_item;
			if (dataset->findAndGetSequenceItem(DCM_DetectorInformationSequence, sq_item).good())
			{
				sq_item->putAndInsertString(DCM_ImageOrientationPatient, image_orientation.c_str());
			}

			dataset->putAndInsertString(DCM_ImageID, "TOMO_IRAC ");
			DcmElement* element;
			int out_size = rows * columns * num;
			Uint16* pix_buf = new Uint16[out_size];
			int max_pixel = INT_MIN;
			int min_pixel = INT_MAX;
			for (size_t i = 0; i < out_size; i++)
			{
				pix_buf[i] = pinbuf[i] * 1000;
				if (max_pixel < pix_buf[i])
				{
					max_pixel = pix_buf[i];
				}
				if (min_pixel > pix_buf[i])
				{
					min_pixel = pix_buf[i];
				}
			}
			dataset->putAndInsertUint16(DCM_SmallestImagePixelValue, min_pixel);
			dataset->putAndInsertUint16(DCM_LargestImagePixelValue, max_pixel);

			std::pair<double, double> center_width = CalculateWindowCenterAndWidth(max_pixel, min_pixel);
			std::string window_center_str = std::to_string(center_width.first);
			std::string window_width_str = std::to_string(center_width.second);
			CheckStringLengthIsEvenSize(window_center_str);
			CheckStringLengthIsEvenSize(window_width_str);
			//DCM_WindowCenter DCM_WindowWidth
			dataset->putAndInsertString(DCM_WindowCenter, window_center_str.c_str());
			dataset->putAndInsertString(DCM_WindowWidth, window_width_str.c_str());
			Uint16* deal_buf = new Uint16[out_size];
			int size_one_image = num * columns;
			int size_org = rows * columns;
			// 一共多少张横断图
			for (size_t i = 0; i < columns; i++)
			{
				Uint16* one_image = deal_buf + i * size_one_image;
				// 对每张图的行数据进行拼接;
				for (size_t j = 0; j < rows; j++)
				{
					memcpy(one_image + (num - 1 - j) * num, pix_buf + j * size_org + i * rows, columns * sizeof(Uint16));
				}
			}

			if (dataset->findAndGetElement(DCM_PixelData, element).good())
			{
				element->putUint16Array(deal_buf, out_size);
			}
			delete[] deal_buf;
			delete[] pix_buf;
			return 0;
		}
		catch (...)
		{
			return 1;
		}
	}
private:
	void CheckStringLengthIsEvenSize(std::string content)
	{
		if (content.size() / 2 != 0)
		{
			content += " ";
		}
	}
	std::pair<double, double> CalculateWindowCenterAndWidth(int max_pixel, int min_pixel)
	{
		double windowWidth = max_pixel - min_pixel;
		double windowCenter = min_pixel + windowWidth / 2.0;
		return std::make_pair(windowCenter, windowWidth);
	}
public:
	std::string instance_id;
	std::string series_instance_id;
	std::string frame_referenceUID;
	std::vector<std::string> pixel_spacings;
	float* pix_buf;
	Uint16 rows;
	Uint16 columns;
	double window_center;
	double window_width;

	Uint16 number_of_frames;
};

class ReconDicom
{
public:
	static int GenerateMultPET(std::string nm_file, std::string mult_pet_file)
	{
		ODI("GenerateMultPET begin");
		if (nm_file.empty() || mult_pet_file.empty())
		{
			ODI("文件名为空");
			return 1;
		}

		DcmFileFormat* nm_dcm_format = new DcmFileFormat;		
		OFCondition cond = nm_dcm_format->loadFile(nm_file.c_str());
		if (cond.good())
		{
			Dicom_info decode_dicom(nm_dcm_format);

			DcmRawData data_out = { 0 };
			DcmRawData raw_data;

			ret = decode_dicom.ChangeDcmFileFormat(nm_dcm_format, data_out._img_data, data_out._size_x, data_out._size_y, data_out._series_num);
			if (ret == 1)
			{
				return -1;
			}
			cond = nm_dcm_format->saveFile(mult_pet_file.c_str());
			if (cond.bad())
			{
				return -1;
			}
		}
		return 0;
	}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/289760
推荐阅读
相关标签
  

闽ICP备14008679号