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,
"_");
75 QString seriesDescription = reader->item()->GetElementAsString(DCM_SeriesDescription);
76 QString name = convertToValidName(seriesDescription);
82 QString seriesNumber = reader->item()->GetElementAsString(DCM_SeriesNumber);
86 ImagePtr DicomConverter::createCxImageFromDicomFile(QString filename,
bool ignoreLocalizerImages)
95 if(ignoreLocalizerImages && reader->isLocalizerImage())
97 reportWarning(QString(
"Localizer image removed from series: %1").arg(filename));
101 if (reader->getNumberOfFrames()==0)
103 reportWarning(QString(
"Found no images in %1, skipping.").arg(filename));
107 QString uid = this->generateUid(reader);
108 QString name = this->generateName(reader);
110 image->setDicomSeriesNumber(this->getSeriesNumber(reader));
115 reportWarning(QString(
"Failed to create image for %1.").arg(filename));
118 image->setVtkImageData(imageData);
120 QString modalityString = reader->item()->GetElementAsString(DCM_Modality);
126 image->setInitialWindowLevel(windowLevel.
width, windowLevel.
center);
128 Transform3D M = reader->getImageTransformPatient();
129 image->get_rMd_History()->setRegistration(M);
135 std::vector<ImagePtr> DicomConverter::createImages(QStringList files)
137 std::vector<ImagePtr> retval;
138 for (
int i=0; i<files.size(); ++i)
140 bool ignoreSpesialImages =
true;
141 ImagePtr image = this->createCxImageFromDicomFile(files[i], ignoreSpesialImages);
143 retval.push_back(image);
148 std::map<double, ImagePtr> DicomConverter::sortImagesAlongDirection(std::vector<ImagePtr> images,
Vector3D e_sort)
150 std::map<double, ImagePtr> sorted;
151 for (
unsigned i=0; i<images.size(); ++i)
154 double dist =
dot(pos, e_sort);
156 sorted[dist] = images[i];
161 bool DicomConverter::slicesFormRegularGrid(std::map<double, ImagePtr> sorted,
Vector3D e_sort)
const 163 std::vector<Vector3D> positions;
164 std::vector<double> distances;
165 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
170 positions.push_back(pos);
172 if (positions.size()>=2)
174 Vector3D p0 = positions[positions.size()-2];
175 Vector3D p1 = positions[positions.size()-1];
176 double dist =
dot(p1-p0, e_sort);
177 distances.push_back(dist);
180 double sliceGantryTiltTolerance = 0.001;
181 if (!
similar(tilt.length(), 0.0, sliceGantryTiltTolerance))
183 reportError(QString(
"Dicom convert: found gantry tilt: %1, cannot create image.").arg(tilt.length()));
188 if (distances.size()>=2)
190 double d0 = distances[distances.size()-2];
191 double d1 = distances[distances.size()-1];
192 double sliceSpacingTolerance = 0.01;
193 if (!
similar(d0, d1, sliceSpacingTolerance))
195 reportError(QString(
"Dicom convert: found uneven slice spacing: %1 != %2, cannot create image.").arg(d0).arg(d1));
204 double DicomConverter::getMeanSliceDistance(std::map<double, ImagePtr> sorted)
const 206 if (sorted.size()==0)
211 if (first->GetDimensions()[2]>1)
212 return first->GetSpacing()[2];
218 double zValueLastImage = sorted.rbegin()->first;
219 double zValueFirstImage = sorted.begin()->first;
220 unsigned long numHolesBetweenImages = sorted.size() - 1;
221 return (zValueLastImage-zValueFirstImage)/numHolesBetweenImages;
224 ImagePtr DicomConverter::mergeSlices(std::map<double, ImagePtr> sorted)
const 227 appender->SetAppendAxis(2);
229 ImagePtr retval = sorted.begin()->second;
233 for (std::map<double, ImagePtr>::iterator iter=sorted.begin(); iter!=sorted.end(); ++iter)
238 if (i == sorted.size() / 2)
239 retval->setInitialWindowLevel(current->getInitialWindowWidth(), current->getInitialWindowLevel());
244 imageCast->SetInputData(current->getBaseVtkImageData());
245 imageCast->SetOutputScalarTypeToShort();
248 appender->AddInputData(imageCast->GetOutput());
253 Eigen::Array3d spacing(wholeImage->GetSpacing());
254 spacing[2] = this->getMeanSliceDistance(sorted);
255 wholeImage->SetSpacing(spacing.data());
257 retval->setVtkImageData(wholeImage);
264 QStringList files = mDatabase->filesForSeries(series);
266 std::vector<ImagePtr> images = this->createImages(files);
271 if (images.size()==1)
273 return images.front();
278 std::map<double, ImagePtr> sorted = this->sortImagesAlongDirection(images, e_sort);
280 if (!this->slicesFormRegularGrid(sorted, e_sort))
283 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.
vtkSmartPointer< vtkImageAppend > vtkImageAppendPtr
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)
Namespace for all CustusX production code.