13 #include "ctkDICOMDatabase.h" 16 #include "vtkImageData.h" 18 #include <vtkImageAppend.h> 19 #include <vtkImageCast.h> 23 #include "ctkDICOMItem.h" 52 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
53 QString seriesNumber = reader->item()->GetElementAsString(DCM_SeriesNumber);
58 QString uid = QString(
"%1_%2_%3").arg(seriesDescription).arg(seriesNumber).arg(currentTimestamp);
59 uid = this->convertToValidName(uid);
63 QString DicomConverter::convertToValidName(QString text)
const 66 illegal <<
"\\s" <<
"\\." <<
":" <<
";" <<
"\\<" <<
"\\>" <<
"\\*" 67 <<
"\\^" <<
"," <<
"\\%";
68 QRegExp regexp(QString(
"(%1)").arg(illegal.join(
"|")));
69 text = text.replace(regexp,
"_");
76 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
77 QString name = convertToValidName(seriesDescription);
81 ImagePtr DicomConverter::createCxImageFromDicomFile(QString filename,
bool ignoreLocalizerImages)
90 if(ignoreLocalizerImages && reader->isLocalizerImage())
92 reportWarning(QString(
"Localizer image removed from series: %1").arg(filename));
96 if (reader->getNumberOfFrames()==0)
98 reportWarning(QString(
"Found no images in %1, skipping.").arg(filename));
102 QString uid = this->generateUid(reader);
103 QString name = this->generateName(reader);
109 reportWarning(QString(
"Failed to create image for %1.").arg(filename));
112 image->setVtkImageData(imageData);
114 QString modalityString = reader->item()->GetElementAsString(DCM_Modality);
120 image->setInitialWindowLevel(windowLevel.
width, windowLevel.
center);
122 Transform3D M = reader->getImageTransformPatient();
123 image->get_rMd_History()->setRegistration(M);
129 std::vector<ImagePtr> DicomConverter::createImages(QStringList files)
131 std::vector<ImagePtr> retval;
132 for (
int i=0; i<files.size(); ++i)
134 bool ignoreSpesialImages =
true;
135 ImagePtr image = this->createCxImageFromDicomFile(files[i], ignoreSpesialImages);
137 retval.push_back(image);
142 std::map<double, ImagePtr> DicomConverter::sortImagesAlongDirection(std::vector<ImagePtr> images,
Vector3D e_sort)
144 std::map<double, ImagePtr> sorted;
145 for (
unsigned i=0; i<images.size(); ++i)
148 double dist =
dot(pos, e_sort);
150 sorted[dist] = images[i];
155 bool DicomConverter::slicesFormRegularGrid(std::map<double, ImagePtr> sorted,
Vector3D e_sort)
const 157 std::vector<Vector3D> positions;
158 std::vector<double> distances;
159 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
164 positions.push_back(pos);
166 if (positions.size()>=2)
168 Vector3D p0 = positions[positions.size()-2];
169 Vector3D p1 = positions[positions.size()-1];
170 double dist =
dot(p1-p0, e_sort);
171 distances.push_back(dist);
174 double sliceGantryTiltTolerance = 0.001;
175 if (!
similar(tilt.length(), 0.0, sliceGantryTiltTolerance))
177 reportError(QString(
"Dicom convert: found gantry tilt: %1, cannot create image.").arg(tilt.length()));
182 if (distances.size()>=2)
184 double d0 = distances[distances.size()-2];
185 double d1 = distances[distances.size()-1];
186 double sliceSpacingTolerance = 0.01;
187 if (!
similar(d0, d1, sliceSpacingTolerance))
189 reportError(QString(
"Dicom convert: found uneven slice spacing: %1 != %2, cannot create image.").arg(d0).arg(d1));
198 double DicomConverter::getMeanSliceDistance(std::map<double, ImagePtr> sorted)
const 200 if (sorted.size()==0)
205 if (first->GetDimensions()[2]>1)
206 return first->GetSpacing()[2];
212 double zValueLastImage = sorted.rbegin()->first;
213 double zValueFirstImage = sorted.begin()->first;
214 unsigned long numHolesBetweenImages = sorted.size() - 1;
215 return (zValueLastImage-zValueFirstImage)/numHolesBetweenImages;
218 ImagePtr DicomConverter::mergeSlices(std::map<double, ImagePtr> sorted)
const 221 appender->SetAppendAxis(2);
223 ImagePtr retval = sorted.begin()->second;
227 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
232 if (i == sorted.size() / 2)
233 retval->setInitialWindowLevel(current->getInitialWindowWidth(), current->getInitialWindowLevel());
238 imageCast->SetInputData(current->getBaseVtkImageData());
239 imageCast->SetOutputScalarTypeToShort();
242 appender->AddInputData(imageCast->GetOutput());
247 Eigen::Array3d spacing(wholeImage->GetSpacing());
248 spacing[2] = this->getMeanSliceDistance(sorted);
249 wholeImage->SetSpacing(spacing.data());
251 retval->setVtkImageData(wholeImage);
258 QStringList files = mDatabase->filesForSeries(series);
260 std::vector<ImagePtr> images = this->createImages(files);
265 if (images.size()==1)
267 return images.front();
272 std::map<double, ImagePtr> sorted = this->sortImagesAlongDirection(images, e_sort);
274 if (!this->slicesFormRegularGrid(sorted, e_sort))
277 ImagePtr retval = this->mergeSlices(sorted);
static DicomImageReaderPtr createFromFile(QString filename)
void reportError(QString msg)
static ImagePtr create(const QString &uid, const QString &name)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
IMAGE_MODALITY convertToModality(QString modalityString)
boost::shared_ptr< class Image > ImagePtr
void setDicomDatabase(ctkDICOMDatabase *database)
QString timestampSecondsFormat()
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
ImagePtr convertToImage(QString seriesUid)
void reportWarning(QString msg)
virtual ~DicomConverter()
double dot(const Vector3D &a, const Vector3D &b)
compute inner product (or dot product) of a and b.
vtkSmartPointer< class vtkImageCast > vtkImageCastPtr
boost::shared_ptr< class DicomImageReader > DicomImageReaderPtr
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
vtkSmartPointer< vtkImageAppend > vtkImageAppendPtr
Namespace for all CustusX production code.