/* Set a Dcm_meta struct to default values. Generates new UIDs. */ static void default_Dcm_meta(Dcm_meta *const meta) { meta->patient_name = default_patient_name; meta->patient_id = default_patient_id; meta->series_descrip = default_series_descrip; dcmGenerateUniqueIdentifier(meta->study_uid, SITE_STUDY_UID_ROOT); dcmGenerateUniqueIdentifier(meta->series_uid, SITE_SERIES_UID_ROOT); dcmGenerateUniqueIdentifier(meta->instance_uid, SITE_INSTANCE_UID_ROOT); meta->instance_num = default_instance_num; }
void DicomUtils::AddDicomElements(DcmDataset*& dataset) { //构建测试数据 /* 添加患者信息 */ dataset->putAndInsertUint16(DCM_AccessionNumber,0); dataset->putAndInsertString(DCM_PatientName,"zssure",true); dataset->putAndInsertString(DCM_PatientID,"2234"); dataset->putAndInsertString(DCM_PatientBirthDate,"20141221"); dataset->putAndInsertString(DCM_PatientSex,"M"); /* 添加Study信息 */ dataset->putAndInsertString(DCM_StudyDate,"20141221"); dataset->putAndInsertString(DCM_StudyTime,"195411"); char uid[100]; dcmGenerateUniqueIdentifier(uid,SITE_STUDY_UID_ROOT); dataset->putAndInsertString(DCM_StudyInstanceUID,uid); dataset->putAndInsertString(DCM_StudyID,"1111"); /* 添加Series信息 */ dataset->putAndInsertString(DCM_SeriesDate,"20141221"); dataset->putAndInsertString(DCM_SeriesTime,"195411"); memset(uid,0,sizeof(char)*100); dcmGenerateUniqueIdentifier(uid,SITE_SERIES_UID_ROOT); dataset->putAndInsertString(DCM_SeriesInstanceUID,uid); /* 添加Image信息 */ dataset->putAndInsertString(DCM_ImageType,"ORIGINAL\\PRIMARY\\AXIAL"); dataset->putAndInsertString(DCM_ContentDate,"20141221"); dataset->putAndInsertString(DCM_ContentTime,"200700"); dataset->putAndInsertString(DCM_InstanceNumber,"1"); dataset->putAndInsertString(DCM_SamplesPerPixel,"1"); dataset->putAndInsertString(DCM_PhotometricInterpretation,"MONOCHROME2"); dataset->putAndInsertString(DCM_PixelSpacing,"0.3\\0.3"); dataset->putAndInsertString(DCM_BitsAllocated,"16"); dataset->putAndInsertString(DCM_BitsStored,"16"); dataset->putAndInsertString(DCM_HighBit,"15"); dataset->putAndInsertString(DCM_WindowCenter,"600"); dataset->putAndInsertString(DCM_WindowWidth,"800"); dataset->putAndInsertString(DCM_RescaleIntercept,"0"); dataset->putAndInsertString(DCM_RescaleSlope,"1"); }
Volume* VolumeBuilderFromCaptures::build() { Q_ASSERT(m_parentStudy); Q_ASSERT(m_vtkImageAppend->GetNumberOfInputs()); // Creem la nova sèrie Series *newSeries = new Series(); // Omplim la informació de la sèrie a partir de la sèrie de referència // Assignem la modalitat segons el valor introduit. El valor per defecte és 'OT' (Other). newSeries->setModality(m_modality); newSeries->setSOPClassUID(QString(UID_SecondaryCaptureImageStorage)); // Generem el SeriesInstanceUID a partir del generador de DCMTK. \TODO Utilitzar el nostre UID_ROOT? char seriesUid[100]; dcmGenerateUniqueIdentifier(seriesUid, SITE_SERIES_UID_ROOT); newSeries->setInstanceUID(QString(seriesUid)); // \TODO Quin criteri volem seguir per donar nous noms? newSeries->setSeriesNumber(QString("0000") + QString::number(m_parentStudy->getSeries().count())); newSeries->setDescription(this->getSeriesDescription()); // Assignem la sèrie a l'estudi al qual partenyia l'inputVolume. newSeries->setParentStudy(m_parentStudy); m_parentStudy->addSeries(newSeries); // Obtenim el nou vtkImageData a partir de la sortida del vtkImageAppend. // Fem un flip horitzontal per tal utilitzar el mateix sistema de coordenades que DICOM. m_vtkImageAppend->Update(); vtkSmartPointer<vtkImageData> newVtkData = vtkSmartPointer<vtkImageData>::New(); newVtkData->ShallowCopy(m_vtkImageAppend->GetOutput()); // Creem el nou volume Volume *newVolume = new Volume(); newSeries->addVolume(newVolume); // Generem les noves imatges a partir del vtkData generat per vtkImageAppend int samplesPerPixel = newVtkData->GetNumberOfScalarComponents(); int bitsAllocated; int bitsStored; int highBit; int pixelRepresentation; int rows; int columns; // \TODO Potser podriem ser mes precisos QString photometricInterpretation; if (samplesPerPixel == 1) { photometricInterpretation = QString("MONOCHROME2"); } else if (samplesPerPixel == 3) { photometricInterpretation = QString("RGB"); } int scalarType = newVtkData->GetScalarType(); switch (scalarType) { //case VTK_CHAR: //break; case VTK_SIGNED_CHAR: bitsAllocated = 8; pixelRepresentation = 1; break; case VTK_UNSIGNED_CHAR: bitsAllocated = 8; pixelRepresentation = 0; break; case VTK_SHORT: bitsAllocated = 16; pixelRepresentation = 1; break; case VTK_UNSIGNED_SHORT: bitsAllocated = 16; pixelRepresentation = 0; break; case VTK_INT: bitsAllocated = 32; pixelRepresentation = 1; break; case VTK_UNSIGNED_INT: bitsAllocated = 32; pixelRepresentation = 0; break; // case VTK_FLOAT: // bitsAllocated = 32; // pixelRepresentation = 1; ? // break; // case VTK_DOUBLE: // bitsAllocated = 64; // pixelRepresentation = 1; ? // break; default: DEBUG_LOG(QString("Pixel Type no suportat: ") + newVtkData->GetScalarTypeAsString()); } bitsStored = bitsAllocated; highBit = bitsStored - 1; int *dimensions = newVtkData->GetDimensions(); double *spacing = newVtkData->GetSpacing(); rows = dimensions[1]; columns = dimensions[0]; Image *currentImage; for (int i = 0; i < dimensions[2]; i++) { currentImage = new Image(); // Generem el SOPInstanceUID a partir del generador de DCMTK. \TODO Utilitzar el nostre UID_ROOT? char instanceUid[100]; dcmGenerateUniqueIdentifier(instanceUid, SITE_INSTANCE_UID_ROOT); currentImage->setSOPInstanceUID(QString(instanceUid)); newSeries->addImage(currentImage); newVolume->addImage(currentImage); currentImage->setParentSeries(newSeries); currentImage->setOrderNumberInVolume(i); currentImage->setVolumeNumberInSeries(0); currentImage->setBitsAllocated(bitsAllocated); currentImage->setBitsStored(bitsStored); currentImage->setHighBit(highBit); currentImage->setColumns(columns); currentImage->setInstanceNumber(QString::number(i + 1)); currentImage->setPhotometricInterpretation(photometricInterpretation); currentImage->setPixelRepresentation(pixelRepresentation); currentImage->setPixelSpacing(spacing[0], spacing[1]); currentImage->setRows(rows); currentImage->setSamplesPerPixel(samplesPerPixel); } // Es fa després d'haver inserit les imatges perquè el nou Volume activi el flag de dades carregades. newVolume->setData(newVtkData); newVolume->setNumberOfPhases(1); newVolume->setNumberOfSlicesPerPhase(newSeries->getImages().count()); // Informació de DEBUG DEBUG_LOG(QString("\nNova sèrie generada:") + QString("\n SeriesInstanceUID: ") + newSeries->getInstanceUID() + QString("\n SeriesNumber: ") + newSeries->getSeriesNumber() + QString("\n SeriesDescription: ") + newSeries->getDescription() + QString("\n SOPClassUID: ") + newSeries->getSOPClassUID() + QString("\n Modality: ") + newSeries->getModality() + QString("\n SamplesPerPixel: ") + QString::number(samplesPerPixel) + QString("\n PhotometricInterpretation: ") + photometricInterpretation + QString("\n BitsAllocated: ") + QString::number(bitsAllocated) + QString("\n BitsStored: ") + QString::number(bitsStored) + QString("\n HighBit: ") + QString::number(highBit) + QString("\n PixelRepresentation: ") + QString::number(pixelRepresentation) + QString("\n PixelSpacing: ") + QString::number(spacing[0]) + QString(",") + QString::number(spacing[1]) + QString("\n Num.Imatges: ") + QString::number(newSeries->getImages().count())); return newVolume; }
/* Helper function to write an image to a directory of DICOM files using C++ */ static int write_dcm_dir_cpp(const char *path, const Image *const im, const Dcm_meta *const meta) { Image slice; // Initialize C intermediates init_im(&slice); // Initialize the metadata to defaults, if it is null Dcm_meta meta_new; set_meta_defaults(meta, &meta_new); // Get the number of leading zeros for the file names const int num_slices = im->nz; const int num_zeros = static_cast<int>(ceil(log10( static_cast<double>(num_slices)))); // Form the printf format string for file names #define BUF_LEN 16 char format[BUF_LEN]; snprintf(format, BUF_LEN, "%%0%dd.%s", num_zeros, ext_dcm); #undef BUF_LEN // Resize the slice buffer slice.nx = im->nx; slice.ny = im->ny; slice.nz = 1; slice.nc = im->nc; im_default_stride(&slice); if (im_resize(&slice)) { im_free(&slice); return SIFT3D_FAILURE; } // Copy the units to the slice memcpy(SIFT3D_IM_GET_UNITS(&slice), SIFT3D_IM_GET_UNITS(im), IM_NDIMS * sizeof(double)); // Get the maximum absolute value of the whole image volume const float max_val = im_max_abs(im); // Write each slice for (int i = 0; i < num_slices; i++) { // Form the slice file name #define BUF_LEN 1024 char buf[BUF_LEN]; snprintf(buf, BUF_LEN, format, i); // Form the full file path std::string fullfile(path + sepStr + buf); // Copy the data to the slice int x, y, z, c; SIFT3D_IM_LOOP_START_C(&slice, x, y, z, c) SIFT3D_IM_GET_VOX(&slice, x, y, z, c) = SIFT3D_IM_GET_VOX(im, x, y, i, c); SIFT3D_IM_LOOP_END_C // Generate a new SOPInstanceUID dcmGenerateUniqueIdentifier(meta_new.instance_uid, SITE_INSTANCE_UID_ROOT); // Set the instance number const unsigned int instance = static_cast<unsigned int>(i + 1); meta_new.instance_num = instance; // Write the slice to a file if (write_dcm(fullfile.c_str(), &slice, &meta_new, max_val)) { im_free(&slice); return SIFT3D_FAILURE; } } // Clean up im_free (&slice); return SIFT3D_SUCCESS; }
int gendicom(const char* file_name, const std::vector<float> &data, unsigned int rows, unsigned int cols) { char uid[100]; DcmFileFormat fileformat; DcmDataset *dataset = fileformat.getDataset(); OFCondition result = EC_Normal; if (result.good()) result = dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage); //if (result.good()) result = dataset->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_SecondaryCaptureImageStorage); //same as SOP if (result.good()) result = dataset->putAndInsertString(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); //if (result.good()) result = dataset->putAndInsertString(DCM_MediaStorageSOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); if (result.good()) result = dataset->putAndInsertString(DCM_SeriesInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); if (result.good()) result = dataset->putAndInsertString(DCM_StudyInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT)); //if (result.good()) result = dataset->putAndInsertString(DCM_TransferSyntaxUID, UID_LittleEndianExplicitTransferSyntax); //if (result.good()) result = dataset->putAndInsertUint16(DCM_FileMetaInformationVersion, 1); if (result.good()) result = dataset->putAndInsertString(DCM_ImageType, "DERIVED"); if (result.good()) result = dataset->putAndInsertString(DCM_Modality, "MR"); if (result.good()) result = dataset->putAndInsertString(DCM_ConversionType, "WSD"); if (result.good()) result = dataset->putAndInsertString(DCM_DerivationDescription, "IRGN Processed MR Reconstruction"); if (result.good()) result = dataset->putAndInsertString(DCM_SecondaryCaptureDeviceManufacturer, "IMT TUGRAZ"); if (result.good()) result = dataset->putAndInsertString(DCM_SecondaryCaptureDeviceManufacturerModelName, "IMT Cuda Workstation"); if (result.good()) result = dataset->putAndInsertString(DCM_PatientName, "Doe^John"); // set instance creation date and time OFString s; if (result.good()) result = DcmDate::getCurrentDate(s); if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, s); if (result.good()) result = DcmTime::getCurrentTime(s); if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, s); //--- Write image-data --- std::vector<Uint16> uint16_data; float val=0; float min_val; float max_val = *std::max_element(data.begin(),data.end()); for(unsigned int i=0; i<data.size(); ++i) { val = (data[i]/max_val)*65535; uint16_data.push_back(Uint16(val)); } max_val = *std::max_element(uint16_data.begin(),uint16_data.end()); min_val = *std::min_element(uint16_data.begin(),uint16_data.end()); std::cout<<"\n max-val: "<<max_val; std::cout<<"\n min-val: "<<min_val; unsigned bits=16; Uint16 bitsAllocated=((bits-1)/8+1)*8; Uint16 bitsStored=bits; Uint16 highBit=bits-1; if (result.good()) result = dataset->putAndInsertUint16(DCM_BitsAllocated, bitsAllocated); if (result.good()) result = dataset->putAndInsertUint16(DCM_BitsStored, bitsStored); if (result.good()) result = dataset->putAndInsertUint16(DCM_HighBit, highBit); if (result.good()) result = dataset->putAndInsertUint16(DCM_Rows, rows); if (result.good()) result = dataset->putAndInsertUint16(DCM_Columns, cols); if (result.good()) result = dataset->putAndInsertUint16(DCM_PixelRepresentation, 0); // 1 signed, 0 unsigned if (result.good()) result = dataset->putAndInsertOFStringArray(DCM_PhotometricInterpretation, "MONOCHROME2"); if (result.good()) result = dataset->putAndInsertUint16(DCM_SamplesPerPixel, 1); if (result.good()) result = dataset->putAndInsertUint16(DCM_SmallestImagePixelValue, min_val); if (result.good()) result = dataset->putAndInsertUint16(DCM_LargestImagePixelValue, max_val); Uint8* pixelData = (Uint8*)&uint16_data[0]; Uint32 pixelLength; pixelLength = uint16_data.size()*2; //number of elements in vector * 2bytes (for Uint16) dataset->putAndInsertUint8Array(DCM_PixelData, pixelData, pixelLength); OFCondition status = fileformat.saveFile(file_name, EXS_LittleEndianExplicit); if (result.bad()) std::cerr << "Error: cannot write DICOM file (" << result.text() << ")" << std::endl; if (status.bad()) std::cerr << "Error: cannot write DICOM file (" << status.text() << ")" << std::endl; return 0; }