13 #include "ctkDICOMDatabase.h" 16 #include "vtkImageData.h" 18 #include <vtkImageAppend.h> 19 #include <vtkImageCast.h> 23 #include "ctkDICOMItem.h" 51 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
52 QString seriesNumber = reader->item()->GetElementAsString(DCM_SeriesNumber);
57 QString uid = QString(
"%1_%2_%3").arg(seriesDescription).arg(seriesNumber).arg(currentTimestamp);
58 uid = this->convertToValidName(uid);
62 QString DicomConverter::convertToValidName(QString text)
const 65 illegal <<
"\\s" <<
"\\." <<
":" <<
";" <<
"\\<" <<
"\\>" <<
"\\*" 66 <<
"\\^" <<
"," <<
"\\%";
67 QRegExp regexp(QString(
"(%1)").arg(illegal.join(
"|")));
68 text = text.replace(regexp,
"_");
75 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
76 QString name = convertToValidName(seriesDescription);
80 ImagePtr DicomConverter::createCxImageFromDicomFile(QString filename,
bool ignoreLocalizerImages)
89 if(ignoreLocalizerImages && reader->isLocalizerImage())
91 reportWarning(QString(
"Localizer image removed from series: %1").arg(filename));
95 if (reader->getNumberOfFrames()==0)
97 reportWarning(QString(
"Found no images in %1, skipping.").arg(filename));
101 QString uid = this->generateUid(reader);
102 QString name = this->generateName(reader);
108 reportWarning(QString(
"Failed to create image for %1.").arg(filename));
111 image->setVtkImageData(imageData);
113 QString modality = reader->item()->GetElementAsString(DCM_Modality);
114 image->setModality(modality);
117 image->setInitialWindowLevel(windowLevel.
width, windowLevel.
center);
119 Transform3D M = reader->getImageTransformPatient();
120 image->get_rMd_History()->setRegistration(M);
122 reportDebug(QString(
"Image created from %1").arg(filename));
126 std::vector<ImagePtr> DicomConverter::createImages(QStringList files)
128 std::vector<ImagePtr> retval;
129 for (
int i=0; i<files.size(); ++i)
131 bool ignoreSpesialImages =
true;
132 ImagePtr image = this->createCxImageFromDicomFile(files[i], ignoreSpesialImages);
134 retval.push_back(image);
139 std::map<double, ImagePtr> DicomConverter::sortImagesAlongDirection(std::vector<ImagePtr> images,
Vector3D e_sort)
141 std::map<double, ImagePtr> sorted;
142 for (
int i=0; i<images.size(); ++i)
145 double dist =
dot(pos, e_sort);
147 sorted[dist] = images[i];
152 bool DicomConverter::slicesFormRegularGrid(std::map<double, ImagePtr> sorted,
Vector3D e_sort)
const 154 std::vector<Vector3D> positions;
155 std::vector<double> distances;
156 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
161 positions.push_back(pos);
163 if (positions.size()>=2)
165 Vector3D p0 = positions[positions.size()-2];
166 Vector3D p1 = positions[positions.size()-1];
167 double dist =
dot(p1-p0, e_sort);
168 distances.push_back(dist);
171 double sliceGantryTiltTolerance = 0.001;
172 if (!
similar(tilt.length(), 0.0, sliceGantryTiltTolerance))
174 reportError(QString(
"Dicom convert: found gantry tilt: %1, cannot create image.").arg(tilt.length()));
179 if (distances.size()>=2)
181 double d0 = distances[distances.size()-2];
182 double d1 = distances[distances.size()-1];
183 double sliceSpacingTolerance = 0.01;
184 if (!
similar(d0, d1, sliceSpacingTolerance))
186 reportError(QString(
"Dicom convert: found uneven slice spacing: %1 != %2, cannot create image.").arg(d0).arg(d1));
195 double DicomConverter::getMeanSliceDistance(std::map<double, ImagePtr> sorted)
const 197 if (sorted.size()==0)
202 if (first->GetDimensions()[2]>1)
203 return first->GetSpacing()[2];
209 double zValueLastImage = sorted.rbegin()->first;
210 double zValueFirstImage = sorted.begin()->first;
211 unsigned long numHolesBetweenImages = sorted.size() - 1;
212 return (zValueLastImage-zValueFirstImage)/numHolesBetweenImages;
215 ImagePtr DicomConverter::mergeSlices(std::map<double, ImagePtr> sorted)
const 218 appender->SetAppendAxis(2);
220 ImagePtr retval = sorted.begin()->second;
224 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
229 if (i == sorted.size() / 2)
230 retval->setInitialWindowLevel(current->getInitialWindowWidth(), current->getInitialWindowLevel());
235 imageCast->SetInputData(current->getBaseVtkImageData());
236 imageCast->SetOutputScalarTypeToShort();
239 appender->AddInputData(imageCast->GetOutput());
244 Eigen::Array3d spacing(wholeImage->GetSpacing());
245 spacing[2] = this->getMeanSliceDistance(sorted);
246 wholeImage->SetSpacing(spacing.data());
248 retval->setVtkImageData(wholeImage);
255 QStringList files = mDatabase->filesForSeries(series);
257 std::vector<ImagePtr> images = this->createImages(files);
262 if (images.size()==1)
264 return images.front();
269 std::map<double, ImagePtr> sorted = this->sortImagesAlongDirection(images, e_sort);
271 if (!this->slicesFormRegularGrid(sorted, e_sort))
274 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.
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)
void reportDebug(QString msg)
vtkSmartPointer< vtkImageAppend > vtkImageAppendPtr
Namespace for all CustusX production code.