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; }
/** * \author Jules Gorny - ALCoV team, ISIT, UMR 6284 UdA – CNRS **/ void writeXMLfromPatient(QString xmlPath, Patient* pat) { QString tab = " "; QFile file(xmlPath); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out << "<Patient Id=\"" << pat->getId() << "\">\n"; QVector<Property> propertiesPat = pat->getProperties(); for(int p=0; p<propertiesPat.size(); p++) { Property prop = propertiesPat[p]; out << tab << "<Property tag=\"" << prop.getTag() << "\" tagName=\"" << prop.getTagName() << "\" value=\"" << prop.getValue() << "\"/>\n"; } QVector<Image*> imgs = pat->getImgs(); for(int i=0; i<imgs.size(); i++) { Image* img = imgs[i]; out << tab << "<" << img->getType() << ">\n"; QVector<Study*> studies = img->getStudies(); for(int st=0; st<studies.size(); st++) { Study* study = studies[st]; out << tab << tab << "<Study description=\"" << study->getDescription() << "\">\n"; QVector<Property> propertiesStud = study->getProperties(); for(int p=0; p<propertiesStud.size(); p++) { Property prop = propertiesStud[p]; out << tab << tab << tab << "<Property tag=\"" << prop.getTag() << "\" tagName=\"" << prop.getTagName() << "\" value=\"" << prop.getValue() << "\"/>\n"; } QVector<Series*> series = study->getSeries(); for(int se=0; se<series.size(); se++) { Series* serie = series[se]; out << tab << tab << tab << "<Series description=\"" << serie->getDescription() << "\">\n"; QVector<Property> propertiesSeries = serie->getProperties(); for(int p=0; p<propertiesSeries.size(); p++) { Property prop = propertiesSeries[p]; out << tab << tab << tab << tab << "<Property tag=\"" << prop.getTag() << "\" tagName=\"" << prop.getTagName() << "\" value=\"" << prop.getValue() << "\"/>\n"; } QVector<Extract*> extracts = serie->getExtracts(); for(int e=0; e<extracts.size(); e++) { Extract* extract = extracts[e]; extract->fillFilesCommonProperty(); out << tab << tab << tab << tab << "<Extract number=\"" << QString::number(extract->getNumber()) << "\">\n"; QVector<Property> propertiesExtr = extract->getProperties(); for(int p=0; p<propertiesExtr.size(); p++) { Property prop = propertiesExtr[p]; out << tab << tab << tab << tab << tab << "<Property tag=\"" << prop.getTag() << "\" tagName=\"" << prop.getTagName() << "\" value=\"" << prop.getValue() << "\"/>\n"; } QVector<File*> files = extract->getFiles(); for(int f=0; f<files.size(); f++) { File* file = files[f]; out << tab << tab << tab << tab << tab << "<File location=\"" << file->getPath() << "\">\n"; QVector<Property> properties = file->getProperties(); for(int p=0; p<properties.size(); p++) { Property prop = properties[p]; out << tab << tab << tab << tab << tab << tab << "<Property tag=\"" << prop.getTag() << "\" tagName=\"" << prop.getTagName() << "\" value=\"" << prop.getValue() << "\"/>\n"; } out << tab << tab << tab << tab << tab << "</File>\n"; } out << tab << tab << tab << tab << "</Extract>\n"; } out << tab << tab << tab << "</Series>\n"; } out << tab << tab << "</Study>\n"; } out << tab << "</" << img->getType() << ">\n"; } out << "</Patient>"; // optional, as QFile destructor will already do it: file.close(); }