34 #include "ctkDICOMDatabase.h" 37 #include "vtkImageData.h" 39 #include <vtkImageAppend.h> 40 #include <vtkImageCast.h> 44 #include "ctkDICOMItem.h" 72 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
73 QString seriesNumber = reader->item()->GetElementAsString(DCM_SeriesNumber);
78 QString uid = QString(
"%1_%2_%3").arg(seriesDescription).arg(seriesNumber).arg(currentTimestamp);
79 uid = this->convertToValidName(uid);
83 QString DicomConverter::convertToValidName(QString text)
const 86 illegal <<
"\\s" <<
"\\." <<
":" <<
";" <<
"\\<" <<
"\\>" <<
"\\*" 87 <<
"\\^" <<
"," <<
"\\%";
88 QRegExp regexp(QString(
"(%1)").arg(illegal.join(
"|")));
89 text = text.replace(regexp,
"_");
96 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
97 QString name = convertToValidName(seriesDescription);
101 ImagePtr DicomConverter::createCxImageFromDicomFile(QString filename,
bool ignoreLocalizerImages)
110 if(ignoreLocalizerImages && reader->isLocalizerImage())
112 reportWarning(QString(
"Localizer image removed from series: %1").arg(filename));
116 if (reader->getNumberOfFrames()==0)
118 reportWarning(QString(
"Found no images in %1, skipping.").arg(filename));
122 QString uid = this->generateUid(reader);
123 QString name = this->generateName(reader);
129 reportWarning(QString(
"Failed to create image for %1.").arg(filename));
132 image->setVtkImageData(imageData);
134 QString modality = reader->item()->GetElementAsString(DCM_Modality);
135 image->setModality(modality);
138 image->setInitialWindowLevel(windowLevel.
width, windowLevel.
center);
140 Transform3D M = reader->getImageTransformPatient();
141 image->get_rMd_History()->setRegistration(M);
143 reportDebug(QString(
"Image created from %1").arg(filename));
147 std::vector<ImagePtr> DicomConverter::createImages(QStringList files)
149 std::vector<ImagePtr> retval;
150 for (
int i=0; i<files.size(); ++i)
152 bool ignoreSpesialImages =
true;
153 ImagePtr image = this->createCxImageFromDicomFile(files[i], ignoreSpesialImages);
155 retval.push_back(image);
160 std::map<double, ImagePtr> DicomConverter::sortImagesAlongDirection(std::vector<ImagePtr> images,
Vector3D e_sort)
162 std::map<double, ImagePtr> sorted;
163 for (
int i=0; i<images.size(); ++i)
166 double dist =
dot(pos, e_sort);
168 sorted[dist] = images[i];
173 bool DicomConverter::slicesFormRegularGrid(std::map<double, ImagePtr> sorted,
Vector3D e_sort)
const 175 std::vector<Vector3D> positions;
176 std::vector<double> distances;
177 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
182 positions.push_back(pos);
184 if (positions.size()>=2)
186 Vector3D p0 = positions[positions.size()-2];
187 Vector3D p1 = positions[positions.size()-1];
188 double dist =
dot(p1-p0, e_sort);
189 distances.push_back(dist);
192 double sliceGantryTiltTolerance = 0.001;
193 if (!
similar(tilt.length(), 0.0, sliceGantryTiltTolerance))
195 reportError(QString(
"Dicom convert: found gantry tilt: %1, cannot create image.").arg(tilt.length()));
200 if (distances.size()>=2)
202 double d0 = distances[distances.size()-2];
203 double d1 = distances[distances.size()-1];
204 double sliceSpacingTolerance = 0.01;
205 if (!
similar(d0, d1, sliceSpacingTolerance))
207 reportError(QString(
"Dicom convert: found uneven slice spacing: %1 != %2, cannot create image.").arg(d0).arg(d1));
216 double DicomConverter::getMeanSliceDistance(std::map<double, ImagePtr> sorted)
const 218 if (sorted.size()==0)
223 if (first->GetDimensions()[2]>1)
224 return first->GetSpacing()[2];
230 double p1 = sorted.rbegin()->first;
231 double p0 = sorted.begin()->first;
232 return (p1-p0)/sorted.size();
235 ImagePtr DicomConverter::mergeSlices(std::map<double, ImagePtr> sorted)
const 238 appender->SetAppendAxis(2);
240 ImagePtr retval = sorted.begin()->second;
244 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
249 if (i == sorted.size() / 2)
250 retval->setInitialWindowLevel(current->getInitialWindowWidth(), current->getInitialWindowLevel());
255 imageCast->SetInputData(current->getBaseVtkImageData());
256 imageCast->SetOutputScalarTypeToShort();
259 appender->AddInputData(imageCast->GetOutput());
264 Eigen::Array3d spacing(wholeImage->GetSpacing());
265 spacing[2] = this->getMeanSliceDistance(sorted);
266 wholeImage->SetSpacing(spacing.data());
268 retval->setVtkImageData(wholeImage);
275 QStringList files = mDatabase->filesForSeries(series);
277 std::vector<ImagePtr> images = this->createImages(files);
282 if (images.size()==1)
284 return images.front();
289 std::map<double, ImagePtr> sorted = this->sortImagesAlongDirection(images, e_sort);
291 if (!this->slicesFormRegularGrid(sorted, e_sort))
294 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.