Commit a54e74f0 authored by David Gobbi's avatar David Gobbi
Browse files

ENH: Add a class for generating an image histogram.

The new vtkImageHistogram class is a multi-threaded filter for
computing an image histogram that differs from vtkImageAccumulate
in that the output image is a histogram plot that can be directly
displayed to the user.  It is also possible to get the histogram
as a vtkIdTypeArray via the GetHistogram() method.

The subclass vtkImageHistogramStatistics computes image statistics
from the generated histogram.  In addition to providing mean, median,
and standard deviation, this class can be used to compute optimal
window/level values for image viewing based on histogram percentiles.

Patch Set 3: Add SetActiveComponent method.

Change-Id: I31c12428b54471c1b6a6e874b219dfacb27282d0
parent 6ae89c2d
......@@ -52,6 +52,8 @@ vtkImageGaussianSource.cxx
vtkImageGradient.cxx
vtkImageGradientMagnitude.cxx
vtkImageGridSource.cxx
vtkImageHistogram.cxx
vtkImageHistogramStatistics.cxx
vtkImageHSIToRGB.cxx
vtkImageHSVToRGB.cxx
vtkImageHybridMedian2D.cxx
......
......@@ -3,7 +3,10 @@ IF (VTK_USE_RENDERING AND VTK_USE_DISPLAY)
CREATE_TEST_SOURCELIST(Tests ${KIT}CxxTests.cxx
ImportExport.cxx
ImageWeightedSum.cxx
ImageAutoRange.cxx
ImageAccumulate.cxx
ImageHistogram.cxx
ImageHistogramStatistics.cxx
FastSplatter.cxx
TestUpdateExtentReset.cxx
EXTRA_INCLUDE vtkTestDriver.h
......
/*=========================================================================
Program: Visualization Toolkit
Module: ImageAutoRange.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// Use vtkImageHistogramStatistics to auto compute the window/level
//
// The command line arguments are:
// -I => run in interactive mode
#include "vtkRenderWindowInteractor.h"
#include "vtkInteractorStyleImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
#include "vtkImageData.h"
#include "vtkImageSliceMapper.h"
#include "vtkImageProperty.h"
#include "vtkImageSlice.h"
#include "vtkPNGReader.h"
#include "vtkImageHistogramStatistics.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"
int ImageAutoRange(int argc, char *argv[])
{
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
vtkInteractorStyle *style = vtkInteractorStyleImage::New();
vtkRenderWindow *renWin = vtkRenderWindow::New();
iren->SetRenderWindow(renWin);
iren->SetInteractorStyle(style);
renWin->Delete();
style->Delete();
vtkPNGReader *reader = vtkPNGReader::New();
char* fname = vtkTestUtilities::ExpandDataFileName(
argc, argv, "Data/fullhead15.png");
reader->SetFileName(fname);
delete[] fname;
vtkImageHistogramStatistics *statistics = vtkImageHistogramStatistics::New();
statistics->SetInputConnection(reader->GetOutputPort());
statistics->GenerateHistogramImageOff();
statistics->Update();
// Get a viewing range based on the full data range
double range[2];
range[0] = statistics->GetMinimum();
range[1] = statistics->GetMaximum();
// Use the autorange feature to get a better image range
double autorange[2];
statistics->GetAutoRange(autorange);
for (int i = 0; i < 2; i++)
{
vtkRenderer *renderer = vtkRenderer::New();
vtkCamera *camera = renderer->GetActiveCamera();
renderer->SetBackground(0.0,0.0,0.0);
renderer->SetViewport(0.5*(i&1), 0.0,
0.5 + 0.5*(i&1), 1.0);
renWin->AddRenderer(renderer);
renderer->Delete();
vtkImageSliceMapper *imageMapper = vtkImageSliceMapper::New();
imageMapper->SetInputConnection(reader->GetOutputPort());
double *bounds = imageMapper->GetBounds();
double point[3];
point[0] = 0.5*(bounds[0] + bounds[1]);
point[1] = 0.5*(bounds[2] + bounds[3]);
point[2] = 0.5*(bounds[4] + bounds[5]);
camera->SetFocalPoint(point);
point[imageMapper->GetOrientation()] += 500.0;
camera->SetPosition(point);
camera->SetViewUp(0.0, 1.0, 0.0);
camera->ParallelProjectionOn();
camera->SetParallelScale(128);
vtkImageSlice *image = vtkImageSlice::New();
image->SetMapper(imageMapper);
imageMapper->Delete();
renderer->AddViewProp(image);
if ((i & 1) == 0)
{
image->GetProperty()->SetColorWindow(range[1] - range[0]);
image->GetProperty()->SetColorLevel(0.5*(range[0] + range[1]));
}
else
{
image->GetProperty()->SetColorWindow(autorange[1] - autorange[0]);
image->GetProperty()->SetColorLevel(0.5*(autorange[0] + autorange[1]));
}
image->Delete();
}
renWin->SetSize(512,256);
renWin->Render();
int retVal = vtkRegressionTestImage( renWin );
if ( retVal == vtkRegressionTester::DO_INTERACTOR )
{
iren->Start();
}
iren->Delete();
statistics->Delete();
reader->Delete();
return !retVal;
}
/*=========================================================================
Program: Visualization Toolkit
Module: ImageHistogram.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// Test the vtkImageHistogram class
//
// The command line arguments are:
// -I => run in interactive mode
#include "vtkRenderWindowInteractor.h"
#include "vtkInteractorStyleImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
#include "vtkImageData.h"
#include "vtkImageSliceMapper.h"
#include "vtkImageProperty.h"
#include "vtkImageSlice.h"
#include "vtkPNGReader.h"
#include "vtkImageHistogram.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"
int ImageHistogram(int argc, char *argv[])
{
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
vtkInteractorStyle *style = vtkInteractorStyleImage::New();
vtkRenderWindow *renWin = vtkRenderWindow::New();
iren->SetRenderWindow(renWin);
iren->SetInteractorStyle(style);
renWin->Delete();
style->Delete();
vtkPNGReader *reader = vtkPNGReader::New();
char* fname = vtkTestUtilities::ExpandDataFileName(
argc, argv, "Data/fullhead15.png");
reader->SetFileName(fname);
delete[] fname;
vtkImageHistogram *histogram = vtkImageHistogram::New();
histogram->SetInputConnection(reader->GetOutputPort());
histogram->GenerateHistogramImageOn();
histogram->SetHistogramImageSize(256,256);
histogram->SetHistogramImageScaleToSqrt();
histogram->AutomaticBinningOn();
histogram->Update();
vtkIdType nbins = histogram->GetNumberOfBins();
double range[2];
range[0] = histogram->GetBinOrigin();
range[1] = range[0] + (nbins - 1)*histogram->GetBinSpacing();
for (int i = 0; i < 2; i++)
{
vtkRenderer *renderer = vtkRenderer::New();
vtkCamera *camera = renderer->GetActiveCamera();
renderer->SetBackground(0.0,0.0,0.0);
renderer->SetViewport(0.5*(i&1), 0.0,
0.5 + 0.5*(i&1), 1.0);
renWin->AddRenderer(renderer);
renderer->Delete();
vtkImageSliceMapper *imageMapper = vtkImageSliceMapper::New();
if ((i & 1) == 0)
{
imageMapper->SetInputConnection(reader->GetOutputPort());
}
else
{
imageMapper->SetInputConnection(histogram->GetOutputPort());
}
double *bounds = imageMapper->GetBounds();
double point[3];
point[0] = 0.5*(bounds[0] + bounds[1]);
point[1] = 0.5*(bounds[2] + bounds[3]);
point[2] = 0.5*(bounds[4] + bounds[5]);
camera->SetFocalPoint(point);
point[imageMapper->GetOrientation()] += 500.0;
camera->SetPosition(point);
camera->SetViewUp(0.0, 1.0, 0.0);
camera->ParallelProjectionOn();
camera->SetParallelScale(128);
vtkImageSlice *image = vtkImageSlice::New();
image->SetMapper(imageMapper);
imageMapper->Delete();
renderer->AddViewProp(image);
if ((i & 1) == 0)
{
image->GetProperty()->SetColorWindow(range[1] - range[0]);
image->GetProperty()->SetColorLevel(0.5*(range[0] + range[1]));
}
else
{
image->GetProperty()->SetInterpolationTypeToNearest();
image->GetProperty()->SetColorWindow(255.0);
image->GetProperty()->SetColorLevel(127.5);
}
image->Delete();
}
renWin->SetSize(512,256);
renWin->Render();
int retVal = vtkRegressionTestImage( renWin );
if ( retVal == vtkRegressionTester::DO_INTERACTOR )
{
iren->Start();
}
iren->Delete();
histogram->Delete();
reader->Delete();
return !retVal;
}
/*=========================================================================
Program: Visualization Toolkit
Module: ImageHistogramStatistics.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// Test the vtkImageHistogramStatistics class
//
// The command line arguments are:
// -I => run in interactive mode
#include "vtkPNGReader.h"
#include "vtkImageCast.h"
#include "vtkImageHistogramStatistics.h"
#include "vtkImageAccumulate.h"
#include "vtkTestUtilities.h"
#include <math.h>
int ImageHistogramStatistics(int argc, char *argv[])
{
vtkPNGReader *reader = vtkPNGReader::New();
char* fname = vtkTestUtilities::ExpandDataFileName(
argc, argv, "Data/fullhead15.png");
reader->SetFileName(fname);
delete[] fname;
// Use float data to get the most code coverage
vtkImageCast *imageCast = vtkImageCast::New();
imageCast->SetOutputScalarTypeToFloat();
imageCast->SetInputConnection(reader->GetOutputPort());
double minValTest = 0;
double maxValTest = 3714;
double meanValTest = 635.8066572717137;
double medianTest = 190.9279926756695;
double stdevTest = 660.9126299774935;
double tol = 1e-6;
vtkImageHistogramStatistics *statistics = vtkImageHistogramStatistics::New();
statistics->SetInputConnection(imageCast->GetOutputPort());
statistics->GenerateHistogramImageOff();
statistics->Update();
double minVal = statistics->GetMinimum();
double maxVal = statistics->GetMaximum();
double meanVal = statistics->GetMean();
double median = statistics->GetMedian();
double stdev = statistics->GetStandardDeviation();
// uncomment to test vtkImageAccumulate instead
/*
vtkImageAccumulate *accumulate = vtkImageAccumulate::New();
accumulate->SetInputConnection(reader->GetOutputPort());
accumulate->Update();
double minVal = accumulate->GetMin()[0];
double maxVal = accumulate->GetMax()[0];
double meanVal = accumulate->GetMean()[0];
double median = medianTest;
double stdev = accumulate->GetStandardDeviation()[0];
*/
bool retVal = true;
if (fabs((minVal - minValTest)/maxValTest) > tol)
{
cout.precision(16);
cout << "minVal " << minVal << " should be " << minValTest << endl;
retVal = false;
}
if (fabs((maxVal - maxValTest)/maxValTest) > tol)
{
cout.precision(16);
cout << "maxVal " << maxVal << " should be " << maxValTest << endl;
retVal = false;
}
if (fabs((meanVal - meanValTest)/maxValTest) > tol)
{
cout.precision(16);
cout << "meanVal " << meanVal << " should be " << meanValTest << endl;
retVal = false;
}
if (fabs((median - medianTest)/maxValTest) > tol)
{
cout.precision(16);
cout << "median " << median << " should be " << medianTest << endl;
retVal = false;
}
if (fabs((stdev - stdevTest)/maxValTest) > tol)
{
cout.precision(16);
cout << "stdev " << stdev << " should be " << stdevTest << endl;
retVal = false;
}
reader->Delete();
imageCast->Delete();
statistics->Delete();
return !retVal;
}
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkImageHistogram.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// .NAME vtkImageHistogram - Compute the histogram for an image.
// .SECTION Description
// vtkImageHistogram generates a histogram from its input, and optionally
// produces a 2D black-and-white image of the histogram as its output.
// Unlike the class vtkImageAccumulate, a multi-component image does not
// result in a multi-dimensional histogram. Instead, the resulting
// histogram will be the sum of the histograms of each of the individual
// components, unless SetActiveComponent is used to choose a single
// component.
// .SECTION Thanks
// Thanks to David Gobbi at the Seaman Family MR Centre and Dept. of Clinical
// Neurosciences, Foothills Medical Centre, Calgary, for providing this class.
#ifndef __vtkImageHistogram_h
#define __vtkImageHistogram_h
#include "vtkThreadedImageAlgorithm.h"
class vtkImageStencilData;
class vtkIdTypeArray;
class VTK_IMAGING_EXPORT vtkImageHistogram : public vtkThreadedImageAlgorithm
{
public:
static vtkImageHistogram *New();
vtkTypeMacro(vtkImageHistogram,vtkThreadedImageAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Scale types for the histogram image.
enum {
Linear = 0,
Log = 1,
Sqrt = 2,
};
// Description:
// Set the component for which to generate a histogram. The default
// value is -1, which produces a histogram that is the sum of the
// histograms of the individual components.
vtkSetMacro(ActiveComponent, int);
vtkGetMacro(ActiveComponent, int);
// Description:
// If this is On, then the histogram binning will be done automatically.
// For char and unsigned char data, there will be 256 bins with unit
// spacing. For data of type short and larger, there will be between
// 256 and MaximumNumberOfBins, depending on the range of the data, and
// the BinOrigin will be set to zero if no negative values are present,
// or to the smallest negative value if negative values are present.
// For float data, the MaximumNumberOfBins will always be used.
// The BinOrigin and BinSpacing will be set so that they provide a mapping
// from bin index to scalar value.
vtkSetMacro(AutomaticBinning, int);
vtkBooleanMacro(AutomaticBinning, int);
vtkGetMacro(AutomaticBinning, int);
// Description:
// The maximum number of bins to use when AutomaticBinning is On.
// When AutomaticBinning is On, the size of the output histogram
// will be set to the full range of the input data values, unless
// the full range is greater than this value. By default, the max
// value is 65536, which is large enough to capture the full range
// of 16-bit integers.
vtkSetMacro(MaximumNumberOfBins, int);
vtkGetMacro(MaximumNumberOfBins, int);
// Description:
// The number of bins in histogram (default 256). This is automatically
// computed unless AutomaticBinning is Off.
vtkSetMacro(NumberOfBins, int);
vtkGetMacro(NumberOfBins, int);
// Description:
// The value for the center of the first bin (default 0). This is
// automatically computed unless AutomaticBinning is Off.
vtkSetMacro(BinOrigin, double);
vtkGetMacro(BinOrigin, double);
// Description:
// The bin spacing (default 1). This is automatically computed unless
// AutomaticBinning is Off.
vtkSetMacro(BinSpacing, double);
vtkGetMacro(BinSpacing, double);
// Description:
// Use a stencil to compute the histogram for just a part of the image.
void SetStencil(vtkImageStencilData *stencil);
vtkImageStencilData *GetStencil();
// Description:
// If this is On, then a histogram image will be produced as the output.
// Regardless of this setting, the histogram is always available as a
// vtkIdTypeArray from the GetHistogram method.
vtkSetMacro(GenerateHistogramImage, int);
vtkBooleanMacro(GenerateHistogramImage, int);
vtkGetMacro(GenerateHistogramImage, int);
// Description:
// Set the size of the histogram image that is produced as output.
// The default is 256 by 256.
vtkSetVector2Macro(HistogramImageSize, int);
vtkGetVector2Macro(HistogramImageSize, int);
// Description:
// Set the scale to use for the histogram image. The default is
// a linear scale, but sqrt and log provide better visualization.
vtkSetClampMacro(HistogramImageScale, int,
vtkImageHistogram::Linear, vtkImageHistogram::Sqrt);
void SetHistogramImageScaleToLinear() {
this->SetHistogramImageScale(vtkImageHistogram::Linear); }
void SetHistogramImageScaleToLog() {
this->SetHistogramImageScale(vtkImageHistogram::Log); }
void SetHistogramImageScaleToSqrt() {
this->SetHistogramImageScale(vtkImageHistogram::Sqrt); }
vtkGetMacro(HistogramImageScale, int);
const char *GetHistogramImageScaleAsString();
// Description:
// Get the histogram as a vtkIdTypeArray. You must call Update()
// before calling this method.
vtkIdTypeArray *GetHistogram();
// Description:
// Get the total count of the histogram. This will be the number of
// voxels times the number of components.
vtkIdType GetTotal() { return this->Total; }
// Description:
// This is part of the executive, but is public so that it can be accessed
// by non-member functions.
virtual void ThreadedRequestData(vtkInformation *request,
vtkInformationVector **inputVector,
vtkInformationVector *outputVector,
vtkImageData ***inData,
vtkImageData **outData, int ext[6], int id);
protected:
vtkImageHistogram();
~vtkImageHistogram();
virtual int RequestUpdateExtent(vtkInformation *vtkNotUsed(request),
vtkInformationVector **inInfo,
vtkInformationVector *vtkNotUsed(outInfo));
virtual int RequestInformation(vtkInformation *vtkNotUsed(request),
vtkInformationVector **inInfo,
vtkInformationVector *vtkNotUsed(outInfo));
virtual int RequestData(vtkInformation *,
vtkInformationVector **,
vtkInformationVector *);
virtual int FillInputPortInformation(int port, vtkInformation *info);
virtual int FillOutputPortInformation(int port, vtkInformation *info);
// Description:
// Compute the range of the data. The GetScalarRange() function of
// vtkImageData only computes the range of the first component, but
// this filter requires the range for all components.
void ComputeImageScalarRange(vtkImageData *data, double range[2]);
int ActiveComponent;
int AutomaticBinning;
int MaximumNumberOfBins;
int HistogramImageSize[2];
int HistogramImageScale;
int GenerateHistogramImage;
int NumberOfBins;
double BinOrigin;
double BinSpacing;
vtkIdTypeArray *Histogram;
vtkIdType Total;
vtkIdType *ThreadOutput[VTK_MAX_THREADS];
int ThreadBinRange[VTK_MAX_THREADS][2];
private:
vtkImageHistogram(const vtkImageHistogram&); // Not implemented.
void operator=(const vtkImageHistogram&); // Not implemented.
};
#endif
/*=========================================================================
Program: Visualization Toolkit
Module: vtkImageHistogramStatistics.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/