[vtkusers] PolyData-Simplification after vtkContourFilter
Lars Friedrich Lars
lars-friedrich at gmx.net
Tue Oct 21 06:00:48 EDT 2008
hello,
I wrote a little application which reads a binary 3D-image, extracts the 3D-surface (vtkContourFilter) and then cuts it with a vtkPlane (vtkCutter) so that the corresponding 2D-contour in plane results.
In order to reduce the resulting vtkPolyData I incorporated an algorithm posted by dean inglis (http://www.vtk.org/pipermail/vtk-developers/2008-January/004913.html). the result looks strange: the polydata after simplification criss-crosses.
I don't think that this is a problem with the algorithm, it's rather a numbering problem of the contour filter's output.
Has anyone else observed this phenomenon? Is there a workaround/fix? Or am I misunderstanding some essential paradigms?
I attachted the code of the application below.
regards,
lars
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkProperty.h"
#include "vtkContourFilter.h"
#include "vtkMetaImageReader.h"
#include "vtkImageData.h"
#include "vtkDataSetMapper.h"
#include "vtkCutter.h"
#include "vtkPlane.h"
#include "vtkCellArray.h"
#include "vtkMath.h"
//---------------------------------------------------------------------------
// guarantees that only the minimum required number of points
// is used for open or closed line polydata
// by dean inglis
//
void ConvertPointSequenceToPolyData( vtkPoints* inPts,
const int& closed, vtkPolyData* outPoly )
{
if ( !inPts || !outPoly ) { return; }
int npts = inPts->GetNumberOfPoints();
if ( npts < 2 ) { return; }
double p0[3];
double p1[3];
inPts->GetPoint( 0, p0 );
inPts->GetPoint( npts - 1, p1 );
if ( p0[0] == p1[0] && p0[1] == p1[1] && p0[2] == p1[2] && closed ) { --npts; }
vtkPoints* temp = vtkPoints::New();
temp->SetNumberOfPoints( npts );
for ( int i = 0; i < npts; ++i )
{
temp->SetPoint( i, inPts->GetPoint( i ) );
}
vtkCellArray *cells = vtkCellArray::New();
cells->Allocate( cells->EstimateSize( npts + closed, 2 ) );
cells->InsertNextCell( npts + closed );
for ( int i = 0; i < npts; ++i )
{
cells->InsertCellPoint( i );
}
if ( closed )
{
cells->InsertCellPoint( 0 );
}
outPoly->SetPoints( temp );
temp->Delete();
outPoly->SetLines( cells );
cells->Delete();
}
int ReducePolyData2D( vtkPolyData* inPoly,
vtkPolyData* outPoly, const int& closed )
{
if ( !inPoly || !outPoly ){ return 0; }
vtkPoints* inPts = inPoly->GetPoints();
if ( !inPts ){ return 0; }
int n = inPts->GetNumberOfPoints();
if ( n < 3 ) { return 0; }
double p0[3];
inPts->GetPoint( 0, p0 );
double p1[3];
inPts->GetPoint( n - 1, p1 );
bool minusNth = ( p0[0] == p1[0] && p0[1] == p1[1] && p0[2] == p1[2] );
if ( minusNth && closed ) { --n; }
struct frenet
{
double t[3]; // unit tangent vector
bool state; // state of kappa: zero or non-zero T/F
};
frenet* f;
f = new frenet[n];
double tL;
// calculate the tangent vector by forward differences
for ( int i = 0; i < n; ++i )
{
inPts->GetPoint( i, p0 );
inPts->GetPoint( ( i + 1 ) % n, p1 );
tL = sqrt( vtkMath::Distance2BetweenPoints( p0, p1 ) );
if ( tL == 0.0 ){ tL = 1.0; }
for ( int j = 0 ; j < 3; ++j )
{
f[i].t[j] = (p1[j] - p0[j]) / tL;
}
}
// calculate kappa from tangent vectors by forward differences
// mark those points that have very low curvature
double eps = 1.e-10;
for ( int i = 0; i < n; ++i )
{
f[i].state = ( fabs( vtkMath::Dot( f[i].t, f[( i + 1 ) % n].t ) - 1.0 ) < eps );
}
vtkPoints* tempPts = vtkPoints::New();
// mark keepers
vtkIdTypeArray* ids = vtkIdTypeArray::New();
// for now, insist on keeping the first point for closure
ids->InsertNextValue( 0 );
for ( int i = 1; i < n; ++i )
{
bool pre = f[( i - 1 + n ) % n].state; // means fik != 1
bool cur = f[i].state; // means fik = 1
bool nex = f[( i + 1 ) % n].state;
// possible vertex bend patterns for keep: pre cur nex
// 0 0 1
// 0 1 1
// 0 0 0
// 0 1 0
// definite delete pattern
// 1 1 1
bool keep = false;
if ( pre && cur && nex ) { keep = false; }
else if ( !pre && !cur && nex ) { keep = true; }
else if ( !pre && cur && nex ) { keep = true; }
else if ( !pre && !cur && !nex ) { keep = true; }
else if ( !pre && cur && !nex ) { keep = true; }
if ( keep ) // not a current sure thing but the preceding delete was
{
ids->InsertNextValue( i );
}
}
for ( int i = 0; i < ids->GetNumberOfTuples(); ++i )
{
tempPts->InsertNextPoint( inPts->GetPoint( ids->GetValue( i ) ) );
}
if ( closed )
{
tempPts->InsertNextPoint( inPts->GetPoint( ids->GetValue( 0 ) ) );
}
ConvertPointSequenceToPolyData( tempPts, closed, outPoly );
ids->Delete();
tempPts->Delete();
delete [] f;
return 1;
}
int main(int argc, char *argv[])
{
vtkRenderer *aRenderer = vtkRenderer::New();
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer(aRenderer);
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
vtkMetaImageReader *reader = vtkMetaImageReader::New();
reader->SetFileName("/data/image-stuff/labelex/labelex.mhd");
reader->Update();
vtkContourFilter *iso = vtkContourFilter::New();
int level = 1.0;
iso->SetInput(reader->GetOutput());
iso->SetValue(0, level);
iso->UseScalarTreeOn();
vtkPolyDataMapper *isoMapper = vtkPolyDataMapper::New();
isoMapper->SetInput(iso->GetOutput());
isoMapper->ScalarVisibilityOff();
vtkActor *isoActor = vtkActor::New();
isoActor->SetMapper(isoMapper);
isoActor->GetProperty()->SetColor(0.8, 0.0, 0.0);
isoActor->GetProperty()->SetOpacity(0.5);
vtkPlane *cutPlane = vtkPlane::New();
double *center = reader->GetOutput()->GetCenter();
std::cout << "volume-center: " << center[0] << "," << center[1] << "," << center[2] << std::endl;
double *planeOrigin = new double[3];
double *off = new double[3];
off[0] = 0;
off[1] = 0;
off[2] = 0;
for (int i = 0; i < 3; ++i)
planeOrigin[i] = center[i] + off[i];
cutPlane->SetOrigin(planeOrigin);
std::cout << "-> plane-origin: " << planeOrigin[0] << "," << planeOrigin[1] << "," << planeOrigin[2] << std::endl;
double n1 = 0;
double n2 = 0;
double n3 = 1;
cutPlane->SetNormal(n1, n2, n3);
vtkCutter *cutter = vtkCutter::New();
cutter->SetInput(iso->GetOutput());
cutter->SetCutFunction(cutPlane);
cutter->SetGenerateCutScalars(false);
// --- point reduction test
// ACTIVATE/DEACTIVATE the polydata-simplification
int reductionOnOff = 1;
vtkPolyData* originalContour = NULL;
vtkPolyData* reducedContour = vtkPolyData::New();
int closed = 1;
int reductionSuccess;
cutter->Update();
originalContour = cutter->GetOutput();
if (ReducePolyData2D(originalContour, reducedContour, closed))
{ std::cout << "REDUCTION SUCCEEDED!" << std::endl;
reductionSuccess = 1;
}
else
{ std::cout << "REDUCTION FAILED!" << std::endl;
reductionSuccess = 0;
}
reductionSuccess = reductionSuccess && reductionOnOff;
// --- \ point reduction test
vtkDataSetMapper *cutMapper = vtkDataSetMapper::New();
if (reductionSuccess)
cutMapper->SetInput(reducedContour);
else
cutMapper->SetInput(originalContour);
cutMapper->ScalarVisibilityOff();
vtkActor *cutActor = vtkActor::New();
cutActor->SetMapper(cutMapper);
cutActor->GetProperty()->SetColor(0.0, 8.0, 0.0);
cutActor->GetProperty()->SetLineWidth(2.0);
cutActor->GetProperty()->SetOpacity(1.0);
aRenderer->AddActor(isoActor);
aRenderer->AddActor(cutActor);
aRenderer->ResetCamera ();
aRenderer->SetBackground(1,1,1);
renWin->SetSize(1024, 768);
aRenderer->ResetCameraClippingRange ();
iren->Initialize();
iren->Start();
delete[] planeOrigin;
cutActor->Delete();
cutMapper->Delete();
cutPlane->Delete();
cutter->Delete();
isoActor->Delete();
isoMapper->Delete();
iso->Delete();
reader->Delete();
iren->Delete();
renWin->Delete();
aRenderer->Delete();
return 0;
}
--
Psssst! Schon vom neuen GMX MultiMessenger gehört? Der kann`s mit allen: http://www.gmx.net/de/go/multimessenger
More information about the vtkusers
mailing list