36 #include <QDomDocument>
38 #include <vtkImageAccumulate.h>
39 #include <vtkImageReslice.h>
40 #include <vtkImageData.h>
41 #include <vtkMatrix4x4.h>
43 #include <vtkPlanes.h>
44 #include <vtkImageResample.h>
45 #include <vtkImageChangeInformation.h>
46 #include <vtkImageClip.h>
47 #include <vtkImageIterator.h>
48 #include <vtkPiecewiseFunction.h>
49 #include <vtkColorTransferFunction.h>
81 double Image::ShadingStruct::loadAttribute(QDomNode dataNode, QString name,
double defVal)
83 QString text = dataNode.toElement().attribute(name);
85 double val = text.toDouble(&ok);
93 QDomElement elem = dataNode.toElement();
94 elem.setAttribute(
"on", on);
95 elem.setAttribute(
"ambient", ambient);
96 elem.setAttribute(
"diffuse", diffuse);
97 elem.setAttribute(
"specular", specular);
98 elem.setAttribute(
"specularPower", specularPower);
103 if (dataNode.isNull())
106 on = dataNode.toElement().attribute(
"on").toInt();
108 ambient = loadAttribute(dataNode,
"ambient", ambient);
109 diffuse = loadAttribute(dataNode,
"diffuse", diffuse);
110 specular = loadAttribute(dataNode,
"specular", specular);
111 specularPower = loadAttribute(dataNode,
"specularPower", specularPower);
130 mInitialWindowWidth = -1;
131 mInitialWindowLevel = -1;
138 mImageLookupTable2D.reset();
139 mImageTransferFunctions3D.reset();
149 baseImageDataCopy = vtkImageDataPtr::New();
160 retval->mImageLookupTable2D = mImageLookupTable2D;
161 retval->mImageTransferFunctions3D = mImageTransferFunctions3D;
162 retval->mInitialWindowWidth = mInitialWindowWidth;
163 retval->mInitialWindowLevel = mInitialWindowLevel;
176 ImageTF3DPtr transferFunctions = parentImage->getUnmodifiedTransferFunctions3D()->createCopy();
177 ImageLUT2DPtr LUT2D = parentImage->getUnmodifiedLookupTable2D()->createCopy();
183 mInitialWindowWidth = parentImage->getInitialWindowWidth();
184 mInitialWindowLevel = parentImage->getInitialWindowLevel();
233 this->blockSignals(
true);
235 this->resetTransferFunction(imageTransferFunctions3D);
236 this->resetTransferFunction(imageLookupTable2D);
238 this->blockSignals(
false);
242 void Image::resetTransferFunction(
ImageLUT2DPtr imageLookupTable2D)
244 if (mImageLookupTable2D)
249 mImageLookupTable2D = imageLookupTable2D;
251 if (mImageLookupTable2D)
259 void Image::resetTransferFunction(
ImageTF3DPtr imageTransferFunctions3D)
261 if (mImageTransferFunctions3D)
266 mImageTransferFunctions3D = imageTransferFunctions3D;
268 if (mImageTransferFunctions3D)
283 this->moveToThread(thread);
284 this->getUnmodifiedTransferFunctions3D()->moveToThread(thread);
285 this->getUnmodifiedLookupTable2D()->moveToThread(thread);
295 if (resetTransferFunctions)
302 double windowWidth = this->getUnmodifiedLookupTable2D()->getWindow();
303 double windowLevel = this->getUnmodifiedLookupTable2D()->getLevel();
320 if(mThresholdPreview)
321 return mTresholdPreviewTransferfunctions3D;
322 return getUnmodifiedTransferFunctions3D();
327 if(!this->mImageTransferFunctions3D)
329 return mImageTransferFunctions3D;
334 this->resetTransferFunction(transferFuntion);
339 if(mThresholdPreview)
340 return mTresholdPreviewLookupTable2D;
341 return getUnmodifiedLookupTable2D();
346 if(!mImageLookupTable2D)
348 return mImageLookupTable2D;
353 this->resetTransferFunction(imageLookupTable2D);
389 template<
typename scalartype>
static int getRGBMax(
vtkImageDataPtr image)
392 vtkImageIterator<scalartype> iter(image, image->GetExtent());
393 while (!iter.IsAtEnd())
395 typename vtkImageIterator<scalartype>::SpanIterator siter = iter.BeginSpan();
396 while (siter != iter.EndSpan())
430 case VTK_UNSIGNED_CHAR:
433 case VTK_UNSIGNED_SHORT:
473 if (vtkScalarType==VTK_CHAR)
475 else if (vtkScalarType==VTK_UNSIGNED_CHAR)
476 return VTK_UNSIGNED_CHAR_MIN;
477 else if (vtkScalarType==VTK_SIGNED_CHAR)
478 return VTK_SIGNED_CHAR_MIN;
479 else if (vtkScalarType==VTK_UNSIGNED_SHORT)
480 return VTK_UNSIGNED_SHORT_MIN;
481 else if (vtkScalarType==VTK_SHORT)
482 return VTK_SHORT_MIN;
483 else if (vtkScalarType==VTK_UNSIGNED_INT)
484 return VTK_UNSIGNED_INT_MIN;
485 else if (vtkScalarType==VTK_INT)
488 reportError(QString(
"Unknown VTK ScalarType: %1").arg(vtkScalarType));
496 if (vtkScalarType==VTK_CHAR)
498 else if (vtkScalarType==VTK_UNSIGNED_CHAR)
499 return VTK_UNSIGNED_CHAR_MAX;
500 else if (vtkScalarType==VTK_SIGNED_CHAR)
501 return VTK_SIGNED_CHAR_MAX;
502 else if (vtkScalarType==VTK_UNSIGNED_SHORT)
503 return VTK_UNSIGNED_SHORT_MAX;
504 else if (vtkScalarType==VTK_SHORT)
505 return VTK_SHORT_MAX;
506 else if (vtkScalarType==VTK_UNSIGNED_INT)
507 return VTK_UNSIGNED_INT_MAX;
508 else if (vtkScalarType==VTK_INT)
511 reportError(QString(
"Unknown VTK ScalarType: %1").arg(vtkScalarType));
523 QDomNode imageNode = dataNode;
524 QDomDocument doc = dataNode.ownerDocument();
526 QDomElement tf3DNode = doc.createElement(
"transferfunctions");
527 this->getUnmodifiedTransferFunctions3D()->addXml(tf3DNode);
528 imageNode.appendChild(tf3DNode);
530 QDomElement lut2DNode = doc.createElement(
"lookuptable2D");
531 this->getUnmodifiedLookupTable2D()->addXml(lut2DNode);
532 imageNode.appendChild(lut2DNode);
534 QDomElement shadingNode = doc.createElement(
"shading");
536 imageNode.appendChild(shadingNode);
542 QDomElement cropNode = doc.createElement(
"crop");
545 imageNode.appendChild(cropNode);
547 QDomElement clipNode = doc.createElement(
"clip");
550 QDomElement planeNode = doc.createElement(
"plane");
555 clipNode.appendChild(planeNode);
557 imageNode.appendChild(clipNode);
559 QDomElement modalityNode = doc.createElement(
"modality");
560 modalityNode.appendChild(doc.createTextNode(
mModality));
561 imageNode.appendChild(modalityNode);
563 QDomElement imageTypeNode = doc.createElement(
"imageType");
564 imageTypeNode.appendChild(doc.createTextNode(
mImageType));
565 imageNode.appendChild(imageTypeNode);
567 QDomElement interpolationNode = doc.createElement(
"vtk_interpolation");
569 imageNode.appendChild(interpolationNode);
571 QDomElement initialWindowNode = doc.createElement(
"initialWindow");
572 initialWindowNode.setAttribute(
"width", mInitialWindowWidth);
573 initialWindowNode.setAttribute(
"level", mInitialWindowLevel);
574 imageNode.appendChild(initialWindowNode);
577 double Image::loadAttribute(QDomNode dataNode, QString name,
double defVal)
579 QString text = dataNode.toElement().attribute(name);
581 double val = text.toDouble(&ok);
601 if (dataNode.isNull())
605 QDomNode transferfunctionsNode = dataNode.namedItem(
"transferfunctions");
606 if (!transferfunctionsNode.isNull())
607 this->getUnmodifiedTransferFunctions3D()->parseXml(transferfunctionsNode);
610 std::cout <<
"Warning: Image::parseXml() found no transferfunctions";
611 std::cout << std::endl;
614 mInitialWindowWidth = this->loadAttribute(dataNode.namedItem(
"initialWindow"),
"width", mInitialWindowWidth);
615 mInitialWindowLevel = this->loadAttribute(dataNode.namedItem(
"initialWindow"),
"level", mInitialWindowLevel);
617 this->getUnmodifiedLookupTable2D()->parseXml(dataNode.namedItem(
"lookuptable2D"));
620 mShading.
on = dataNode.namedItem(
"shading").toElement().text().toInt();
622 if (!dataNode.namedItem(
"shadingAmbient").isNull())
623 mShading.
ambient = dataNode.namedItem(
"shadingAmbient").toElement().text().toDouble();
624 if (!dataNode.namedItem(
"shadingDiffuse").isNull())
625 mShading.
diffuse = dataNode.namedItem(
"shadingDiffuse").toElement().text().toDouble();
626 if (!dataNode.namedItem(
"shadingSpecular").isNull())
627 mShading.
specular = dataNode.namedItem(
"shadingSpecular").toElement().text().toDouble();
628 if (!dataNode.namedItem(
"shadingSpecularPower").isNull())
636 QDomElement cropNode = dataNode.namedItem(
"crop").toElement();
637 if (!cropNode.isNull())
643 QDomElement clipNode = dataNode.namedItem(
"clip").toElement();
644 QDomElement clipPlaneNode = clipNode.firstChildElement(
"plane");
645 for (; !clipPlaneNode.isNull(); clipPlaneNode = clipPlaneNode.nextSiblingElement(
"plane"))
647 Vector3D normal = Vector3D::fromString(clipPlaneNode.attribute(
"normal"));
648 Vector3D origin = Vector3D::fromString(clipPlaneNode.attribute(
"origin"));
650 plane->SetNormal(normal.begin());
651 plane->SetOrigin(origin.begin());
655 mModality = dataNode.namedItem(
"modality").toElement().text();
656 mImageType = dataNode.namedItem(
"imageType").toElement().text();
658 QDomElement interpoationNode = dataNode.namedItem(
"vtk_interpolation").toElement();
659 if (!interpoationNode.isNull())
668 mInitialWindowWidth = width;
669 mInitialWindowLevel = level;
680 if (mThresholdPreview)
795 info->SetOutputExtentStart(0, 0, 0);
796 info->SetOutputOrigin(0, 0, 0);
798 info->UpdateInformation();
836 int size = axisSize - 1;
838 dummyImageData->SetExtent(0, size, 0, size, 0, size);
839 dummyImageData->SetSpacing(1, 1, 1);
844 dummyImageData->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
845 unsigned char* dataPtr =
static_cast<unsigned char*
> (dummyImageData->GetScalarPointer());
848 int minVoxelValue = 0;
849 int numVoxels = axisSize*axisSize*axisSize;
850 for (
int i = 0; i < numVoxels; ++i)
852 int voxelValue = minVoxelValue + i;
854 dataPtr[i] = maxVoxelValue;
855 else if (voxelValue < maxVoxelValue)
856 dataPtr[i] = voxelValue;
858 dataPtr[i] = maxVoxelValue;
861 return dummyImageData;
875 if (mThresholdPreview)
882 if (mThresholdPreview)
883 return VTK_NEAREST_INTERPOLATION;
892 double factor = computeResampleFactor(maxVoxels);
894 if (fabs(1.0-factor)>0.01)
897 resampler->SetInterpolationModeToLinear();
898 resampler->SetAxisMagnificationFactor(0, factor);
899 resampler->SetAxisMagnificationFactor(1, factor);
900 resampler->SetAxisMagnificationFactor(2, factor);
901 resampler->SetInputData(retval);
904 resampler->GetOutput()->GetScalarRange();
905 retval = resampler->GetOutput();
918 double Image::computeResampleFactor(
long maxVoxels)
924 double factor = (double)maxVoxels/(
double)voxels;
925 factor = pow(factor, 1.0/3.0);
937 QString filename = basePath +
"/Images/" + this->
getUid() +
".mhd";
938 this->
setFilename(QDir(basePath).relativeFilePath(filename));
946 mThresholdPreview =
true;
948 this->createThresholdPreviewTransferFunctions3D(threshold);
949 this->createThresholdPreviewLookupTable2D(threshold);
954 void Image::createThresholdPreviewTransferFunctions3D(
const Eigen::Vector2d &threshold)
958 ColorMap colors = this->createPreviewColorMap(threshold);
959 IntIntMap opacity = this->createPreviewOpacityMap(threshold);
961 mTresholdPreviewTransferfunctions3D = tfGenerator.generate3DTFPreset();
962 mTresholdPreviewTransferfunctions3D->resetColor(colors);
963 mTresholdPreviewTransferfunctions3D->resetAlpha(opacity);
966 void Image::createThresholdPreviewLookupTable2D(
const Eigen::Vector2d &threshold)
968 ImageDefaultTFGenerator tfGenerator(
ImagePtr(
this, null_deleter()));
970 ColorMap colors = this->createPreviewColorMap(threshold);
972 mTresholdPreviewLookupTable2D = tfGenerator.generate2DTFPreset();
973 mTresholdPreviewLookupTable2D->resetColor(colors);
974 mTresholdPreviewLookupTable2D->setLLR(threshold[0]);
977 ColorMap Image::createPreviewColorMap(
const Eigen::Vector2d &threshold)
979 double lower = threshold[0];
981 colors[lower] = Qt::green;
982 colors[this->
getMax()] = Qt::green;
986 IntIntMap Image::createPreviewOpacityMap(
const Eigen::Vector2d &threshold)
988 double lower = threshold[0];
989 double upper = threshold[1];
991 opacity[lower - 1] = 0;
994 opacity[upper + 1] = 0;
1000 mThresholdPreview =
false;
1001 mTresholdPreviewTransferfunctions3D.reset();
1002 mTresholdPreviewLookupTable2D.reset();
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
QString qstring_cast(const T &val)
void transferFunctionsChanged()
static vtkImageDataPtr createDummyImageData(int axisSize, int maxVoxelValue)
Create a moc object of vtkImageData.
Image(const QString &uid, const vtkImageDataPtr &data, const QString &name="")
virtual bool getCropping() const
void reportError(QString msg)
virtual void setModality(const QString &val)
virtual Transform3D get_rMd() const
bool mUseCropping
image should be cropped using mCroppingBox
virtual vtkImageDataPtr getGrayScaleVtkImageData()
as getBaseVtkImageData(), but constrained to 1 component if multicolor.
int getInterpolationType() const
virtual Eigen::Array3d getSpacing() const
QString mImageType
type of the image, defined as DICOM tag (0008,0008) (mainly value 3, but might be a merge of value 4)...
void parseXml(QDomNode dataNode)
virtual void setTransferFunctions3D(ImageTF3DPtr transferFuntion)
PlainObject normal() const
virtual double getShadingDiffuse()
Get shading diffuse parmeter.
virtual vtkImageAccumulatePtr getHistogram()
void mergevtkSettingsIntosscTransform()
static ImagePtr create(const QString &uid, const QString &name)
void addXml(QDomNode dataNode)
#define CX_ASSERT(statement)
virtual void setShadingDiffuse(double diffuse)
Set shading diffuse parmeter.
virtual QString getModality() const
virtual void setVtkImageData(const vtkImageDataPtr &data, bool resetTransferFunctions=true)
vtkSmartPointer< class vtkImageAccumulate > vtkImageAccumulatePtr
void propertiesChanged()
emitted when one of the metadata properties (uid, name etc) changes
virtual void setLookupTable2D(ImageLUT2DPtr imageLookupTable2D)
boost::shared_ptr< class Image > ImagePtr
virtual void setInitialWindowLevel(double width, double level)
vtkSmartPointer< vtkImageChangeInformation > vtkImageChangeInformationPtr
static DoubleBoundingBox3D fromString(const QString &text)
construct a bb from a string containing 6 whitespace-separated numbers
virtual void setCropping(bool on)
virtual Image::ShadingStruct getShading()
virtual void setShadingOn(bool on)
DoubleBoundingBox3D mCroppingBox_d
box defining the cropping size.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
virtual void setShadingAmbient(double ambient)
Set shading ambient parmeter.
virtual vtkImageDataPtr getBaseVtkImageData()
static ImagePtr create(ImagePtr base)
virtual void addXml(QDomNode &dataNode)
adds xml information about the data and its variabels
virtual double getShadingSpecular()
Get shading specular parmeter.
virtual void setShadingSpecular(double specular)
Set shading specular parmeter.
virtual void setImageType(const QString &val)
ImagePtr mUnsigned
version of this containing unsigned data.
virtual ImagePtr getUnsigned(ImagePtr self)
virtual void intitializeFromParentImage(ImagePtr parentImage)
virtual QString getUid() const
virtual ImageTF3DPtr getTransferFunctions3D()
void addXml(QDomNode &dataNode)
adds xml information about the image and its variabels
virtual RegistrationHistoryPtr get_rMd_History()
std::map< int, QColor > ColorMap
boost::shared_ptr< class ImageLUT2D > ImageLUT2DPtr
ImageLUT2DPtr generate2DTFPreset()
void startThresholdPreview(const Eigen::Vector2d &threshold)
QString mModality
modality of the image, defined as DICOM tag (0008,0060), Section 3, C.7.3.1.1.1
void reportWarning(QString msg)
virtual int getMaxAlphaValue()
Max alpha value (probably 255)
vtkImageDataPtr convertImageDataTo8Bit(vtkImageDataPtr image, double windowWidth, double windowLevel)
Have never been used or tested. Create a test for it.
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
virtual void setShadingSpecularPower(double specularPower)
Set shading specular power parmeter.
void moveThisAndChildrenToThread(QThread *thread)
Move this and all children to thread. Use the thread is generated in a worker thread and the result i...
virtual int getRange()
For convenience: getMax() - getMin()
virtual void save(const QString &basePath)
void setAcquisitionTime(QDateTime time)
void transferFunctionsChanged()
emitted when image transfer functions in 2D or 3D are changed.
Transform3D createTransformTranslate(const Vector3D &translation)
Settings * settings()
Shortcut for accessing the settings instance.
Representation of an integer bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
vtkSmartPointer< class vtkImageResample > vtkImageResamplePtr
vtkImageAccumulatePtr mHistogramPtr
Histogram.
vtkImageDataPtr resample(long maxVoxels)
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Vector3D multiply_elems(const Vector3D &a, const Vector3D &b)
perform element-wise multiplication of a and b.
virtual void setShading(Image::ShadingStruct shading)
vtkImageDataPtr convertImageDataToGrayScale(vtkImageDataPtr image)
RegistrationHistoryPtr m_rMd_History
Superclass for all data objects.
std::map< int, int > IntIntMap
void setDeepModified(vtkImageDataPtr image)
void readInto(DataPtr data, QString path)
virtual DoubleBoundingBox3D getCroppingBox() const
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
virtual void setCroppingBox(const DoubleBoundingBox3D &bb_d)
ImageTF3DPtr generate3DTFPreset()
void vtkImageDataChanged()
emitted when the vktimagedata are invalidated and must be retrieved anew.
virtual vtkImageDataPtr get8bitGrayScaleVtkImageData()
Have never been used or tested. Create a test for it.
REGISTRATION_STATUS mRegistrationStatus
virtual double getShadingAmbient()
Get shading ambient parmeter.
virtual bool load(QString path)
void stopThresholdPreview()
void setInterpolationType(int val)
virtual QString getImageType() const
virtual double getShadingSpecularPower()
Get shading specular power parmeter.
vtkImageDataPtr mBaseImageData
image data in data space
int mInterpolationType
mirror the interpolationType in vtkVolumeProperty
vtkSmartPointer< class vtkPlane > vtkPlanePtr
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr
virtual void setFilename(QString val)
virtual void transformChangedSlot()
virtual ImageLUT2DPtr getLookupTable2D()
virtual bool getShadingOn() const
void resetTransferFunctions(bool _2D=true, bool _3D=true)
Resets the transfer functions and creates new default values.
virtual DoubleBoundingBox3D boundingBox() const
bounding box in image space
std::vector< vtkPlanePtr > mPersistentClipPlanes
vtkImageDataPtr mBaseGrayScaleImageData
image data in data space