Commit 60d9d023 authored by David Gobbi's avatar David Gobbi

Add vtkImageConnectivityFilter

This is the vtkImageData equivalent of vtkPolyDataConnectivityFilter.
It performs connectivity checks on points with values within a specific
scalar range (by default, it checks all points with values > 0).  Its
output is a label image, where each connected region is assigned an
integer label value.  Unlabeled points are assigned a value of zero.
parent a1a94d0c
Pipeline #26151 passed with stage
set(Module_SRCS
vtkImageConnector.cxx
vtkImageConnectivityFilter.cxx
vtkImageContinuousDilate3D.cxx
vtkImageContinuousErode3D.cxx
vtkImageDilateErode3D.cxx
......
vtk_add_test_cxx(${vtk-module}CxxTests tests
TestImageThresholdConnectivity.cxx
TestImageConnectivityFilter.cxx
)
vtk_test_cxx_executable(${vtk-module}CxxTests tests
......
/*=========================================================================
Program: Visualization Toolkit
Module: ImageConnectivityFilter.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 ImageConnectivityFilter class
//
// The command line arguments are:
// -I => run in interactive mode
#include "vtkSmartPointer.h"
#include "vtkCamera.h"
#include "vtkImageConnectivityFilter.h"
#include "vtkImageData.h"
#include "vtkImageProperty.h"
#include "vtkImageReader2.h"
#include "vtkImageSlice.h"
#include "vtkImageSliceMapper.h"
#include "vtkInteractorStyleImage.h"
#include "vtkIdTypeArray.h"
#include "vtkIntArray.h"
#include "vtkPoints.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkVersion.h"
#include "vtkTestUtilities.h"
#include <string>
int TestImageConnectivityFilter(int argc, char *argv[])
{
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleImage> style =
vtkSmartPointer<vtkInteractorStyleImage>::New();
style->SetInteractionModeToImageSlicing();
vtkSmartPointer<vtkRenderWindow> renWin =
vtkSmartPointer<vtkRenderWindow>::New();
iren->SetRenderWindow(renWin);
iren->SetInteractorStyle(style);
// Use a 3D image for the test
std::string fname =
vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/headsq/quarter");
vtkSmartPointer<vtkImageReader2> reader =
vtkSmartPointer<vtkImageReader2>::New();
reader->SetDataByteOrderToLittleEndian();
reader->SetDataExtent(0, 63, 0, 63, 2, 4);
reader->SetDataSpacing(3.2, 3.2, 1.5);
reader->SetFilePrefix(fname.c_str());
// Create two seed points
vtkSmartPointer<vtkPoints> seedPoints =
vtkSmartPointer<vtkPoints>::New();
seedPoints->InsertNextPoint(25.6, 100.8, 2.25);
seedPoints->InsertNextPoint(100.8, 100.8, 2.25);
vtkSmartPointer<vtkUnsignedCharArray> seedScalars =
vtkSmartPointer<vtkUnsignedCharArray>::New();
seedScalars->InsertNextValue(2);
seedScalars->InsertNextValue(5);
vtkSmartPointer<vtkPolyData> seedData =
vtkSmartPointer<vtkPolyData>::New();
seedData->SetPoints(seedPoints);
seedData->GetPointData()->SetScalars(seedScalars);
// Generate a grid of renderers for the various tests
for (int i = 0; i < 9; i++)
{
int j = 2 - i / 3;
int k = i % 3;
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkCamera *camera = renderer->GetActiveCamera();
renderer->SetBackground(0.0, 0.0, 0.0);
renderer->SetViewport(k/3.0, j/3.0, (k + 1)/3.0, (j + 1)/3.0);
renWin->AddRenderer(renderer);
vtkSmartPointer<vtkImageConnectivityFilter> connectivity =
vtkSmartPointer<vtkImageConnectivityFilter>::New();
connectivity->SetInputConnection(reader->GetOutputPort());
if (i == 0)
{
connectivity->GenerateRegionExtentsOn();
connectivity->SetScalarRange(800, 1200);
// No seeds
// Default extraction mode
// Default label mode
}
else if (i == 1)
{
connectivity->SetScalarRange(800, 1200);
// No seeds
connectivity->SetExtractionModeToLargestRegion();
// Default label mode
}
else if (i == 2)
{
connectivity->SetScalarRange(800, 1200);
// No seeds
connectivity->SetSizeRange(10, 99);
// Default label mode
}
else if (i == 3)
{
connectivity->SetScalarRange(800, 1200);
connectivity->SetSeedData(seedData);
// Default extraction mode
// Default label mode (use seed scalars)
}
else if (i == 4)
{
connectivity->SetScalarRange(800, 1200);
connectivity->SetSeedData(seedData);
connectivity->SetExtractionModeToAllRegions();
connectivity->SetLabelModeToSizeRank();
}
else if (i == 5)
{
// Seeds with no scalars
connectivity->SetScalarRange(800, 1200);
seedData->GetPointData()->SetScalars(NULL);
connectivity->SetSeedData(seedData);
}
else if (i == 6)
{
connectivity->SetScalarRange(1200, 4095);
}
else if (i == 7)
{
connectivity->SetScalarRange(0, 800);
}
else if (i == 8)
{
// use default scalar range
}
if (i == 0)
{
// Test OutputExtent != InputExtent
int extent[6] = { 0, 63, 0, 63, 3, 3 };
connectivity->UpdateExtent(extent);
}
else
{
// Test updating whole extent
connectivity->Update();
}
// Test getting info about the output regions
vtkIdTypeArray *sizeArray = connectivity->GetExtractedRegionSizes();
vtkIdTypeArray *idArray = connectivity->GetExtractedRegionSeedIds();
vtkIdTypeArray *labelArray = connectivity->GetExtractedRegionLabels();
vtkIntArray *extentArray = connectivity->GetExtractedRegionExtents();
vtkIdType rn = connectivity->GetNumberOfExtractedRegions();
std::cout << "\nTest Case: " << i << std::endl;
std::cout << "number of regions: " << rn << std::endl;
for (vtkIdType r = 0; r < rn; r++)
{
std::cout << "region: " << r << ","
<< " seed: " << idArray->GetValue(r) << ","
<< " label: " << labelArray->GetValue(r) << ","
<< " size: " << sizeArray->GetValue(r) << ","
<< " extent: [";
if (connectivity->GetGenerateRegionExtents())
{
std::cout << extentArray->GetValue(6*r) << ","
<< extentArray->GetValue(6*r+1) << ","
<< extentArray->GetValue(6*r+2) << ","
<< extentArray->GetValue(6*r+3) << ","
<< extentArray->GetValue(6*r+4) << ","
<< extentArray->GetValue(6*r+5);
}
std::cout << "]" << std::endl;
}
vtkSmartPointer<vtkImageSliceMapper> imageMapper =
vtkSmartPointer<vtkImageSliceMapper>::New();
imageMapper->SetInputConnection(connectivity->GetOutputPort());
imageMapper->BorderOn();
imageMapper->SliceFacesCameraOn();
imageMapper->SliceAtFocalPointOn();
double point[3] = { 100.8, 100.8, 5.25 };
camera->SetFocalPoint(point);
point[2] += 500.0;
camera->SetPosition(point);
camera->SetViewUp(0.0, 1.0, 0.0);
camera->ParallelProjectionOn();
camera->SetParallelScale(3.2*32);
vtkSmartPointer<vtkImageSlice> image =
vtkSmartPointer<vtkImageSlice>::New();
image->SetMapper(imageMapper);
image->GetProperty()->SetColorWindow(6);
image->GetProperty()->SetColorLevel(3);
renderer->AddViewProp(image);
}
renWin->SetSize(192, 256);
iren->Initialize();
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkImageConnectivityFilter.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.
=========================================================================*/
/*=========================================================================
Copyright (c) 2014 David Gobbi
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of David Gobbi nor the names of any contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
// .NAME vtkImageConnectivityFilter - Label an image by connectivity
// .SECTION Description
// vtkImageConnectivityFilter will identify connected regions within an
// image and label them. Only points with scalar values within a
// prescribed range are considered for inclusion, by default this range
// includes all scalar values with a value greater than zero. Points
// within the prescribed scalar range are considered to be connected
// if a path exists between the points that does not traverse any
// points that are not within the prescribed scalar range.
// Adjacency of points is governed by 4-connectivity for 2D images, and
// 6-connectivity for 3D images.
//
// The output of this filter is a label image. By default, each region
// is assigned a different label, where the labels are integer values
// starting at a value of 1. The SetLabelMode() method can be used to
// change the way that labels are assigned. Labels can be assigned
// by providing input seed points for each region to be labelled, or
// they can be assigned by ranking the regions by size.
//
// If a set of seeds is provided with the SetSeedData() method,
// then the default behavior is to only output the regions that are
// connected to the seeds, and if the seeds have scalars, then these
// scalars will be used to label the regions. Seeds with a scalar
// value equal to zero are ignored. See the documentation for the
// SetExtractionMode() method for details on how to control which
// regions will labeled.
//
// Regions can be selected by size with the SetSizeRange() method,
// which can be useful for identifying objects of a certain size,
// e.g. for rejecting small regions that are likely to be noise.
// It is also possible to label only the largest region and ignore
// all others, with SetExtractionModeToLargestRegion().
//
// In addition to the labels, the following additional information
// is provided: the number of regions identified, the size of each
// region, a list of all label values used, and the seed for each
// region (if seeds were used). Optionally, this filter can also
// compute the extent of each region if GenerateRegionExtentsOn()
// is called. These extents can be useful for cropping the output
// of the filter.
//
// .SECTION see also
// vtkConnectivityFilter, vtkPolyDataConnectivityFilter
#ifndef vtkImageConnectivityFilter_h
#define vtkImageConnectivityFilter_h
#include "vtkImagingMorphologicalModule.h" // For export macro
#include "vtkImageAlgorithm.h"
class vtkIdTypeArray;
class vtkIntArray;
class vtkDataSet;
class vtkImageData;
class vtkImageStencilData;
class VTKIMAGINGMORPHOLOGICAL_EXPORT vtkImageConnectivityFilter :
public vtkImageAlgorithm
{
public:
static vtkImageConnectivityFilter *New();
vtkTypeMacro(vtkImageConnectivityFilter, vtkImageAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Enum constants for SetLabelMode().
enum LabelModeEnum {
SeedScalar = 0,
ConstantValue = 1,
SizeRank = 2
};
// Description:
// Enum constants for SetExtractionMode().
enum ExtractionModeEnum {
SeededRegions = 0,
AllRegions = 1,
LargestRegion = 2
};
// Description:
// The input for seed locations (input port 1).
// Each point in the supplied data set will be used as a seed, unless
// the data set has scalars, in which case only the points with scalar
// values that are not equal to zero will be used as seeds.
void SetSeedConnection(vtkAlgorithmOutput *port);
vtkAlgorithmOutput *GetSeedConnection();
void SetSeedData(vtkDataSet *data);
// Description:
// The input for a stencil (input port 2).
// The output labels will be restricted to the region inside the stencil,
// as if no input voxels existed outside the stencil. This allows you to
// apply this filter within an arbitrary region of interest.
void SetStencilConnection(vtkAlgorithmOutput *port);
vtkAlgorithmOutput *GetStencilConnection();
void SetStencilData(vtkImageStencilData *data);
// Description:
// Set the scalar type for the output label image.
// This should be one of UnsignedChar, Short, UnsignedShort, or Int
// depending on how many labels are expected. The default is UnsignedChar,
// which allows for 255 label values. If the total number of regions is
// greater than the maximum label value N, then only the largest N regions
// will be kept and the rest will be discarded.
void SetLabelScalarTypeToUnsignedChar() {
this->SetLabelScalarType(VTK_UNSIGNED_CHAR); }
void SetLabelScalarTypeToShort() {
this->SetLabelScalarType(VTK_SHORT); }
void SetLabelScalarTypeToUnsignedShort() {
this->SetLabelScalarType(VTK_UNSIGNED_SHORT); }
void SetLabelScalarTypeToInt() {
this->SetLabelScalarType(VTK_INT); }
const char *GetLabelScalarTypeAsString();
vtkSetMacro(LabelScalarType, int);
vtkGetMacro(LabelScalarType, int);
// Description:
// Set the mode for applying labels to the output.
// Labeling by SeedScalar uses the scalars from the seeds as labels, if
// present, or the regions will be labeled consecutively starting at 1,
// if the seeds have no scalars. Labeling by SizeRank means that the
// largest region is labeled 1 and other regions are labeled consecutively
// in order of decreasing size (if there is a tie, then the seed point ID
// is used as a tiebreaker). Finally, Constant means that all regions
// will have the value of SetLabelConstantValue(). The default is to
// label using the seed scalars, if present, or to label consecutively,
// if no seed scalars are present.
void SetLabelModeToSeedScalar() { this->SetLabelMode(SeedScalar); }
void SetLabelModeToConstantValue() { this->SetLabelMode(ConstantValue); }
void SetLabelModeToSizeRank() { this->SetLabelMode(SizeRank); }
const char *GetLabelModeAsString();
vtkSetMacro(LabelMode, int);
vtkGetMacro(LabelMode, int);
// Description:
// Set which regions to output from this filter.
// This can be all the regions, just the seeded regions, or the largest
// region (which will the the largest seeded region, if there are seeds).
// The default is to output all the seeded regions, if there are seeds,
// or to output all the regions, if there are no seeds.
void SetExtractionModeToSeededRegions(){
this->SetExtractionMode(SeededRegions); }
void SetExtractionModeToAllRegions() {
this->SetExtractionMode(AllRegions); }
void SetExtractionModeToLargestRegion() {
this->SetExtractionMode(LargestRegion); }
const char *GetExtractionModeAsString();
vtkSetMacro(ExtractionMode, int);
vtkGetMacro(ExtractionMode, int);
// Description:
// The label used when LabelMode is ConstantValue.
// The default value is 255.
vtkSetMacro(LabelConstantValue, int);
vtkGetMacro(LabelConstantValue, int);
// Description:
// Get the number of extracted regions.
vtkIdType GetNumberOfExtractedRegions();
// Description:
// Get the label used for each extracted region.
vtkIdTypeArray *GetExtractedRegionLabels() {
return this->ExtractedRegionLabels; }
// Desciption:
// Get the size of each extracted region, as a voxel count.
vtkIdTypeArray *GetExtractedRegionSizes() {
return this->ExtractedRegionSizes; }
// Description:
// Get the PointId of the seed for each region.
// If no seed was used, the PointId will be -1.
vtkIdTypeArray *GetExtractedRegionSeedIds() {
return this->ExtractedRegionSeedIds; }
// Description:
// Get the extent (a 6-tuples) for each output region.
// This is only valid if GenerateRegionExtentsOn() was called before
// the filter was executed.
vtkIntArray *GetExtractedRegionExtents() {
return this->ExtractedRegionExtents; }
// Description:
// Turn this on to request creation of the ExtractedRegionExtents array.
vtkSetMacro(GenerateRegionExtents, int);
vtkBooleanMacro(GenerateRegionExtents, int);
vtkGetMacro(GenerateRegionExtents, int);
// Description:
// Set the size range for the extracted regions.
// Only regions that have sizes within the specified range will be present
// in the output. The default range is (1, VTK_ID_MAX).
vtkSetVector2Macro(SizeRange, vtkIdType);
vtkGetVector2Macro(SizeRange, vtkIdType);
// Description:
// Set the scalar range used to define potential regions.
// Only voxels with values that are within this range will be considered
// for region membership. This is an inclusive range, meaning that the
// upper and lower limits are considered to be within the range. The
// default range goes from 0.5 to VTK_DOUBLE_MAX.
vtkSetVector2Macro(ScalarRange, double);
vtkGetVector2Macro(ScalarRange, double);
// Description:
// For multi-component input images, select which component to use.
vtkSetMacro(ActiveComponent, int);
vtkGetMacro(ActiveComponent, int);
protected:
vtkImageConnectivityFilter();
~vtkImageConnectivityFilter();
int LabelMode;
int ExtractionMode;
double ScalarRange[2];
vtkIdType SizeRange[2];
int LabelConstantValue;
int ActiveComponent;
int LabelScalarType;
int GenerateRegionExtents;
vtkIdTypeArray *ExtractedRegionLabels;
vtkIdTypeArray *ExtractedRegionSizes;
vtkIdTypeArray *ExtractedRegionSeedIds;
vtkIntArray *ExtractedRegionExtents;
void ComputeInputUpdateExtent(int inExt[6], int outExt[6]);
virtual int FillInputPortInformation(int port, vtkInformation *info);
virtual int RequestInformation(
vtkInformation *, vtkInformationVector **, vtkInformationVector *);
virtual int RequestUpdateExtent(
vtkInformation *, vtkInformationVector **, vtkInformationVector *);
virtual int RequestData(
vtkInformation *, vtkInformationVector **, vtkInformationVector *);
private:
vtkImageConnectivityFilter(const vtkImageConnectivityFilter&) VTK_DELETE_FUNCTION;
void operator=(const vtkImageConnectivityFilter&) VTK_DELETE_FUNCTION;
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment