[vtkusers] using stencils to render stl objects

Richard Beare richard.beare at gmail.com
Tue Aug 5 06:06:37 EDT 2008


Hi,

I have an stl model generated by solidworks that I'm trying to render
into a 3D image. I've successfully created various views but run into
issues when trying to consolidate the various world coordinate
information, and I experience segmentation faults depending on
transformation of the polydata.

Anyway, my pipeline is

1) Load a template image using itk. This image is derived from the MRI
scan which I'll eventually register the rendered model to

2) transfer the itk image to vtk.

3) Load the stl using the vtkSTLReader

4) Apply a series of transformations, at the moment done individually
so I can figure out what's going on.

5) Generate a stencil and apply it.

My questions are: should the vtkPolyDataToImageStencil have problems
if the stl and image bounds don't overlap? I've attempted to use a
clipping filter to eliminate potential problems, but no luck. And,
should I be doing this a different way? The code is as follows:

template <class PixType, int dim>
void createPhantom(const CmdLineType &CmdLineObj)
{
    vtkSTLReader *stlReader = vtkSTLReader::New();
    vtkTransformPolyDataFilter *stlTransform1 =
vtkTransformPolyDataFilter::New();
    vtkTransformPolyDataFilter *stlTransform2 =
vtkTransformPolyDataFilter::New();
    vtkTransformPolyDataFilter *stlTransform3 =
vtkTransformPolyDataFilter::New();
    vtkTransform * tf1 = vtkTransform::New();
    vtkTransform * tf2 = vtkTransform::New();
    vtkTransform * tf3 = vtkTransform::New();

    // Load up the sample image using itk
    typedef typename itk::Image<PixType, dim> ImageType;
    typename ImageType::Pointer TempIm =
readIm<ImageType>(CmdLineObj.templateIm);

    // figure out world coordinates of image centre
    typedef typename itk::ContinuousIndex<double,
ImageType::ImageDimension> ContinuousIndexType;

    typename ImageType::SizeType size =
TempIm->GetLargestPossibleRegion().GetSize();
    ContinuousIndexType Middle;
    typename ImageType::PointType WorldMiddle, ModelMiddle;
    for (unsigned i = 0; i < ImageType::ImageDimension; i++)
    {
        Middle[i] = ((float)size[i])/2;
    }
    TempIm->TransformContinuousIndexToPhysicalPoint(Middle, WorldMiddle);
    TempIm->FillBuffer(100);
    // import the image to vtk
    typedef typename itk::ImageToVTKImageFilter<ImageType> itk2vtkType;
    typename itk2vtkType::Pointer itkexporter = itk2vtkType::New();
    itkexporter->SetInput(TempIm);
    itkexporter->Update();

    typename ImageType::PointType origin = TempIm->GetOrigin();
    std::cout << origin << std::endl;
    stlReader->SetFileName(CmdLineObj.StlFile.c_str());
    stlReader->Update();
    std::cout << "Loaded" << std::endl;

    printBounds(stlReader->GetOutput());
    // apply the transforms one at a time - inefficient but clear
    // first centre the cad model
    computeMiddle(stlReader->GetOutput(), ModelMiddle);
    tf1->Translate(-ModelMiddle[0], -ModelMiddle[1], -ModelMiddle[2]);

    std::cout << ModelMiddle;
    stlTransform1->SetInput(stlReader->GetOutput());
    stlTransform1->SetTransform(tf1);
    stlTransform1->Update();

    printBounds(stlTransform1->GetOutput());

    tf2->RotateX(90);
    stlTransform2->SetTransform(tf2);
    stlTransform2->SetInput(stlTransform1->GetOutput());
    stlTransform2->Update();

    computeMiddle(stlTransform2->GetOutput(), ModelMiddle);

    // we want the centre of the phantom to be at the image centre

    stlTransform3->SetInput(stlTransform2->GetOutput());
    tf3->Translate(WorldMiddle[0] - ModelMiddle[0],
                   WorldMiddle[1] - ModelMiddle[1],
                   WorldMiddle[2] - ModelMiddle[2]);

    stlTransform3->SetTransform(tf3);
    stlTransform3->Update();

    std::cout << "Bounds of stl object are: ";
//    double bounds[6];
//    stlReader->GetOutput()->GetBounds(bounds);
    double bounds[6];
    stlTransform3->GetOutput()->ComputeBounds();
    stlTransform3->GetOutput()->GetBounds(bounds);
    {
    for (unsigned i = 0; i<6; i++)
      {
      std::cout << bounds[i] << ",";
      }
    std::cout << std::endl << "Make sure the template image is
appropriate" << std::endl;
    }

    // clip the polydata against the image bounds
    double imagebounds[6];
    vtkBox *imagebox = vtkBox::New();
    vtkClipPolyData *boxclipper = vtkClipPolyData::New();

    itkexporter->GetOutput()->GetBounds(imagebounds);
    imagebox->SetBounds(imagebounds);
    boxclipper->SetClipFunction(imagebox);
    boxclipper->SetInput(stlTransform3->GetOutput());


    vtkPolyDataToImageStencil *surfaceConverter =
vtkPolyDataToImageStencil::New();
//    surfaceConverter->SetInput(stlReader->GetOutput());
    surfaceConverter->SetInput(boxclipper->GetOutput());
    surfaceConverter->SetInformationInput(itkexporter->GetOutput());
    surfaceConverter->SetTolerance( 0.0 );

    // set up the stencil
    vtkImageStencil * stencil = vtkImageStencil::New();
    stencil->SetInput( itkexporter->GetOutput() );
    stencil->SetStencil( surfaceConverter->GetOutput() );
    stencil->SetBackgroundValue( 200 );
    stencil->ReverseStencilOn();
    stencil->Update();

    // send the result back to itk for saving
    typedef typename itk::VTKImageToImageFilter<ImageType> vtk2itkType;
    typename vtk2itkType::Pointer itkimporter = vtk2itkType::New();
    itkimporter->SetInput(stencil->GetOutput());
    itkimporter->Update();

    typedef typename itk::MaskImageFilter<ImageType, ImageType,
ImageType> MaskType;
    typename MaskType::Pointer maskfilt = MaskType::New();
    maskfilt->SetInput1(itkimporter->GetOutput());
    maskfilt->SetInput2(TempIm);

    typedef typename itk::ImageFileWriter<ImageType> WriterType;
    typename WriterType::Pointer writer = WriterType::New();
    writer->SetInput(itkimporter->GetOutput());
    writer->SetFileName(CmdLineObj.OutputIm.c_str());
    writer->Update();

}



More information about the vtkusers mailing list