Procházet zdrojové kódy

ENH: ctkTransferFunction*: Add support for histograms. Add ctkVTKHistogram

Julien Finet před 15 roky
rodič
revize
6eb3f8de0c

+ 72 - 0
Libs/Core/ctkHistogram.cpp

@@ -0,0 +1,72 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+/// CTK includes
+#include "ctkHistogram.h"
+
+//-----------------------------------------------------------------------------
+ctkHistogram::ctkHistogram(QObject* parentObject)
+  :ctkTransferFunction(parentObject)
+{
+}
+
+//-----------------------------------------------------------------------------
+ctkHistogram::~ctkHistogram()
+{
+}
+
+//-----------------------------------------------------------------------------
+bool ctkHistogram::isDiscrete()const
+{
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+bool ctkHistogram::isEditable()const
+{
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+int ctkHistogram::insertControlPoint(const ctkControlPoint& cp)
+{
+  Q_UNUSED(cp);
+  return -1;
+}
+
+//-----------------------------------------------------------------------------
+int ctkHistogram::insertControlPoint(qreal pos)
+{
+  Q_UNUSED(pos);
+  return -1;
+}
+
+//-----------------------------------------------------------------------------
+void ctkHistogram::setControlPointPos(int index, qreal pos)
+{
+  Q_UNUSED(index);
+  Q_UNUSED(pos);
+}
+
+//-----------------------------------------------------------------------------
+void ctkHistogram::setControlPointValue(int index, const QVariant& value)
+{
+  Q_UNUSED(index);
+  Q_UNUSED(value);
+}

+ 69 - 0
Libs/Core/ctkHistogram.h

@@ -0,0 +1,69 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+
+#ifndef __ctkHistogram_h
+#define __ctkHistogram_h
+
+/// Qt includes
+#include <QColor>
+#include <QObject>
+#include <QtGlobal>
+#include <QSharedPointer>
+#include <QVariant>
+
+/// CTK includes
+#include "ctkTransferFunction.h"
+#include "CTKCoreExport.h"
+
+//-----------------------------------------------------------------------------
+struct CTK_CORE_EXPORT ctkHistogramBar : public ctkControlPoint
+{
+  QColor Color;
+};
+
+//-----------------------------------------------------------------------------
+class CTK_CORE_EXPORT ctkHistogram: public ctkTransferFunction
+{
+  Q_OBJECT
+public:
+  ctkHistogram(QObject* parent = 0);
+  virtual ~ctkHistogram();
+  
+  virtual bool isDiscrete()const;
+  virtual bool isEditable()const;
+
+  ///
+  virtual int insertControlPoint(const ctkControlPoint& cp);
+  virtual int insertControlPoint(qreal pos);
+
+  /// 
+  /// be careful with it, as changing the value might require
+  /// more changes to ctkControlPoint.
+  virtual void setControlPointPos(int index, qreal pos);
+  /// 
+  /// be careful with it, as changing the value might require
+  /// more changes to ctkControlPoint.
+  virtual void setControlPointValue(int index, const QVariant& value);
+  virtual void build()=0;
+protected:
+  
+};
+
+#endif

+ 337 - 0
Libs/Visualization/VTK/Core/ctkVTKHistogram.cpp

@@ -0,0 +1,337 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+
+/// Qt includes
+#include <QColor>
+#include <QDebug>
+
+/// CTK includes
+#include "ctkVTKHistogram.h"
+
+/// VTK includes
+#include <vtkDataArray.h>
+#include <vtkIntArray.h>
+#include <vtkMath.h>
+#include <vtkSmartPointer.h>
+
+/// STL include
+#include <limits>
+
+//-----------------------------------------------------------------------------
+class ctkVTKHistogramPrivate: public ctkPrivate<ctkVTKHistogram>
+{
+public:
+  ctkVTKHistogramPrivate();
+  vtkSmartPointer<vtkDataArray> DataArray;
+  vtkSmartPointer<vtkIntArray>  Bins;
+  int                           UserNumberOfBins;
+  int                           Component;
+  mutable double                Range[2];
+  int                           MinBin;
+  int                           MaxBin;
+
+  int computeNumberOfBins()const;
+};
+
+//-----------------------------------------------------------------------------
+ctkVTKHistogramPrivate::ctkVTKHistogramPrivate()
+{
+  this->Bins = vtkSmartPointer<vtkIntArray>::New();
+  this->UserNumberOfBins = -1;
+  this->Component = 0;
+  this->Range[0] = this->Range[1] = 0.;
+  this->MinBin = 0;
+  this->MaxBin = 0;
+}
+
+//-----------------------------------------------------------------------------
+int ctkVTKHistogramPrivate::computeNumberOfBins()const
+{
+  if (this->DataArray.GetPointer() == 0)
+    {
+    return -1;
+    }
+  
+  if (this->DataArray->GetDataType() == VTK_CHAR ||
+      this->DataArray->GetDataType() == VTK_SIGNED_CHAR ||
+      this->DataArray->GetDataType() == VTK_UNSIGNED_CHAR)
+    {
+    this->Range[0] = this->DataArray->GetDataTypeMin();
+    this->Range[1] = this->DataArray->GetDataTypeMax();
+    }
+  else
+    {
+    this->DataArray->GetRange(this->Range, this->Component);
+    if (this->DataArray->GetDataType() == VTK_FLOAT ||
+        this->DataArray->GetDataType() == VTK_DOUBLE)
+      {
+      this->Range[1] += 0.01;
+      }
+    else
+      {
+      this->Range[1] += 1;
+      }
+    }
+  if (this->UserNumberOfBins > 0)
+    {
+    return this->UserNumberOfBins;
+    }
+
+  return static_cast<int>(this->Range[1] - this->Range[0]);
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKHistogram::ctkVTKHistogram(QObject* parentObject)
+  :ctkHistogram(parentObject)
+{
+  CTK_INIT_PRIVATE(ctkVTKHistogram);
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKHistogram::ctkVTKHistogram(vtkDataArray* dataArray, 
+                                 QObject* parentObject)
+  :ctkHistogram(parentObject)
+{
+  CTK_INIT_PRIVATE(ctkVTKHistogram);
+  this->setDataArray(dataArray);
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKHistogram::~ctkVTKHistogram()
+{
+}
+
+//-----------------------------------------------------------------------------
+int ctkVTKHistogram::count()const
+{
+  CTK_D(const ctkVTKHistogram);
+  return d->Bins->GetNumberOfTuples();
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKHistogram::range(qreal& minRange, qreal& maxRange)const
+{
+  CTK_D(const ctkVTKHistogram);
+  if (d->DataArray.GetPointer() == 0)
+    {
+    Q_ASSERT(d->DataArray.GetPointer());
+    minRange = 1.; // set incorrect values
+    maxRange = 0.;
+    return;
+    }
+  if (d->Range[0] == d->Range[1])
+    {
+    minRange = d->DataArray->GetDataTypeMin();
+    maxRange = d->DataArray->GetDataTypeMax();
+    return;
+    }
+  minRange = d->Range[0];
+  maxRange = d->Range[1];
+} 
+
+//-----------------------------------------------------------------------------
+QVariant ctkVTKHistogram::minValue()const
+{
+  CTK_D(const ctkVTKHistogram);
+  return d->MinBin;
+}
+
+//-----------------------------------------------------------------------------
+QVariant ctkVTKHistogram::maxValue()const
+{
+  CTK_D(const ctkVTKHistogram);
+  return d->MaxBin;
+}
+
+//-----------------------------------------------------------------------------
+ctkControlPoint* ctkVTKHistogram::controlPoint(int index)const
+{
+  CTK_D(const ctkVTKHistogram);
+  ctkHistogramBar* cp = new ctkHistogramBar();
+  cp->P.X = this->indexToPos(index);
+  cp->P.Value = d->Bins->GetValue(index);
+  return cp;
+}
+
+//-----------------------------------------------------------------------------
+QVariant ctkVTKHistogram::value(qreal pos)const
+{
+  CTK_D(const ctkVTKHistogram);
+  QSharedPointer<ctkControlPoint> point(this->controlPoint(this->posToIndex(pos)));
+  return point->value();
+}
+
+//-----------------------------------------------------------------------------
+qreal ctkVTKHistogram::indexToPos(int index)const
+{
+  qreal posRange[2];
+  this->range(posRange[0], posRange[1]);
+  return posRange[0] + index * ((posRange[1] - posRange[0]) / (this->count() - 1));
+}
+
+//-----------------------------------------------------------------------------
+int ctkVTKHistogram::posToIndex(qreal pos)const
+{
+  qreal posRange[2];
+  this->range(posRange[0], posRange[1]);
+  return (pos - posRange[0]) / ((posRange[1] - posRange[0]) / (this->count() - 1));
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKHistogram::setDataArray(vtkDataArray* newDataArray)
+{
+  CTK_D(ctkVTKHistogram);
+  d->DataArray = newDataArray;
+  this->qvtkReconnect(d->DataArray,vtkCommand::ModifiedEvent,
+                      this, SIGNAL(changed()));
+  emit changed();
+}
+
+//-----------------------------------------------------------------------------
+vtkDataArray* ctkVTKHistogram::dataArray()const
+{
+  CTK_D(const ctkVTKHistogram);
+  return d->DataArray;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKHistogram::setComponent(int component)
+{
+  CTK_D(ctkVTKHistogram);
+  d->Component = component;
+  // need rebuild
+}
+
+int ctkVTKHistogram::component()const
+{
+  CTK_D(const ctkVTKHistogram);
+  return d->Component;
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKHistogram::setNumberOfBins(int number)
+{
+  CTK_D(ctkVTKHistogram);
+  d->UserNumberOfBins = number;
+}
+
+//-----------------------------------------------------------------------------
+template <class T>
+void populateBins(vtkIntArray* bins, const ctkVTKHistogram* histogram)
+{
+  vtkDataArray* scalars = histogram->dataArray();
+  int* binsPtr = bins->WritePointer(0, bins->GetNumberOfTuples());
+
+  // reset bins to 0
+  memset(binsPtr, bins->GetNumberOfTuples()*sizeof(int), 0);
+
+  const vtkIdType componentNumber = scalars->GetNumberOfComponents();
+  const vtkIdType tupleNumber = scalars->GetNumberOfTuples();
+  int component = histogram->component();
+
+  double range[2];
+  histogram->range(range[0], range[1]);
+  T offset = static_cast<T>(range[0]);
+
+  T* ptr = static_cast<T*>(scalars->WriteVoidPointer(0, tupleNumber));
+  T* endPtr = ptr + tupleNumber * componentNumber;
+  ptr += component;
+  for (; ptr < endPtr; ptr += componentNumber)
+    {
+    Q_ASSERT( (static_cast<long long>(*ptr) - offset) == 
+              (static_cast<int>(*ptr) - offset));
+    binsPtr[static_cast<int>(*ptr - offset)]++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+template <class T>
+void populateIrregularBins(vtkIntArray* bins, const ctkVTKHistogram* histogram)
+{
+  vtkDataArray* scalars = histogram->dataArray();
+
+  int* binsPtr = bins->WritePointer(0, bins->GetNumberOfTuples());
+  // reset bins to 0
+  memset(binsPtr, bins->GetNumberOfTuples() * sizeof(int), 0);
+
+  const vtkIdType componentNumber = scalars->GetNumberOfComponents();
+  const vtkIdType tupleNumber = scalars->GetNumberOfTuples();
+  int component = histogram->component();
+
+  double range[2];
+  histogram->range(range[0], range[1]);
+  double offset = range[0];
+
+  double binWidth = 1.;
+  if (range[1] != range[0])
+    {
+    binWidth = static_cast<double>(bins->GetNumberOfTuples()) / (range[1] - range[0]);
+    }
+
+  T* ptr = static_cast<T*>(scalars->WriteVoidPointer(0, tupleNumber));
+  T* endPtr = ptr + tupleNumber * componentNumber;
+  ptr += component;
+  for (; ptr < endPtr; ptr += componentNumber)
+    {
+    if (std::numeric_limits<T>::has_quiet_NaN && 
+        std::numeric_limits<T>::quiet_NaN() == *ptr)
+      {
+      continue;
+      }
+    binsPtr[vtkMath::Floor(((double)*ptr - offset) * binWidth)]++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKHistogram::build()
+{
+  CTK_D(ctkVTKHistogram);
+  
+  const int binCount = d->computeNumberOfBins();
+
+  d->Bins->SetNumberOfComponents(1);
+  d->Bins->SetNumberOfTuples(binCount);
+
+  if (static_cast<double>(binCount) != (d->Range[1] - d->Range[2]))
+    {
+    switch(d->DataArray->GetDataType())
+      {
+      vtkTemplateMacro(populateIrregularBins<VTK_TT>(d->Bins, this));
+      }
+    }
+  else
+    {
+    switch(d->DataArray->GetDataType())
+      {
+      vtkTemplateMacro(populateBins<VTK_TT>(d->Bins, this));
+      }
+    }
+  // update Min/Max values
+  int* binPtr = d->Bins->GetPointer(0);
+  int* endPtr = d->Bins->GetPointer(binCount-1);
+  d->MinBin = *endPtr;
+  d->MaxBin = *endPtr;
+  for (;binPtr < endPtr; ++binPtr)
+    {
+    d->MinBin = qMin(*binPtr, d->MinBin);
+    d->MaxBin = qMax(*binPtr, d->MaxBin);
+    }
+  emit changed();
+}

+ 70 - 0
Libs/Visualization/VTK/Core/ctkVTKHistogram.h

@@ -0,0 +1,70 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+
+#ifndef __ctkVTKHistogram_h
+#define __ctkVTKLookupTable_h
+
+// CTK includes
+#include "ctkHistogram.h"
+#include "ctkPimpl.h"
+#include "CTKVisualizationVTKCoreExport.h"
+#include "ctkVTKObject.h"
+
+class vtkDataArray;
+class ctkVTKHistogramPrivate;
+
+///
+/// Transfer function for a vtkColorTransferFunction. 
+/// The value is an RGB QColor (no alpha supported)
+class CTK_VISUALIZATION_VTK_CORE_EXPORT ctkVTKHistogram: public ctkHistogram
+{
+  Q_OBJECT;
+  QVTK_OBJECT;
+public:
+  ctkVTKHistogram(QObject* parent = 0);
+  ctkVTKHistogram(vtkDataArray* dataArray, QObject* parent = 0);
+  virtual ~ctkVTKHistogram();
+  
+  virtual ctkControlPoint* controlPoint(int index)const;
+  virtual QVariant value(qreal pos)const;
+  virtual int count()const;
+
+  virtual void range(qreal& minRange, qreal& maxRange)const;
+  virtual QVariant minValue()const;
+  virtual QVariant maxValue()const;
+
+  void setDataArray(vtkDataArray* dataArray);
+  vtkDataArray* dataArray()const;
+
+  void setComponent(int component);
+  int component()const;
+
+  void setNumberOfBins(int number);
+
+  virtual void build();
+protected:
+  qreal indexToPos(int index)const;
+  int posToIndex(qreal pos)const;
+
+private:
+  CTK_DECLARE_PRIVATE(ctkVTKHistogram);
+};
+
+#endif

+ 63 - 0
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkTransferFunctionWidgetTest5.cpp

@@ -0,0 +1,63 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QSharedPointer>
+#include <QTimer>
+
+// CTK includes
+#include "ctkTransferFunction.h"
+#include "ctkTransferFunctionWidget.h"
+#include "ctkVTKHistogram.h"
+
+// VTK includes
+#include <vtkIntArray.h>
+#include <vtkSmartPointer.h>
+
+// STD includes
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+int ctkTransferFunctionWidgetTest5(int argc, char * argv [] )
+{
+  QApplication app(argc, argv);
+  
+  vtkSmartPointer<vtkIntArray> intArray = 
+    vtkSmartPointer<vtkIntArray>::New();
+  intArray->SetNumberOfComponents(1);
+  intArray->SetNumberOfTuples(2000);
+  for (int i = 0; i < 2000; ++i)
+    {
+    intArray->SetValue(i, qrand() % 30);
+    }
+  QSharedPointer<ctkVTKHistogram> histogram = 
+    QSharedPointer<ctkVTKHistogram>(new ctkVTKHistogram(intArray));
+  histogram->build();
+  ctkTransferFunctionWidget transferFunctionWidget(histogram.data(), 0);
+  // the widget is not really shown here, only when app.exec() is called
+  transferFunctionWidget.show();
+
+  QTimer autoExit;
+  QObject::connect(&autoExit, SIGNAL(timeout()), &app, SLOT(quit()));
+  autoExit.start(1000);
+
+  return app.exec();
+}