如何向3D Slicer (version 4)中加入CLI插件
对于目前的Slicer4,在只是使用C++编程语言的情况下,添加插件的方法主要有两种:一种是CLIExtension,一种是LoadableExtension.前者本文将详细介绍,其优点是只需写简单.xml.in文件便能由Slicer4自动生成UI;后者则需要使用QtDesigner来设计UI。
下面的步骤是建立在已经编译好的Slicer4的基础上,本人使用的系统是win7 64位系统,Slicer4源码位于I:\Slicer4,构建目录位于I:\Slicer4-SuperBuild。
首先,打开 所有程序 -> Microsoft Visual Studio 2008 -> Visual Studio Tools -> Visual Studio 2008 x64 Win4 命令提示 这个terminal,输入如下命令:
cd I:\Slicer4-SuperBuild\python-build\PCbuild\amd64
I:
python.exe I:\Slicer4\Utilities\Scripts\ModuleWizard.py --template I:\Slicer4\Extensions\Testing\CLIExtensionTemplate --target I:\Slicer4\Modules\CLI\MyModule MyModule (MyModule是我自己起的模块名,该名可以任意修改)
接着,打开I:\Slicer4\Modules\CLI下的CMakelists.txt,修改如下:
set(cli_modules
ACPCTransform
AddScalarVolumes
CastScalarVolume
......
ThresholdScalarVolume
TractographyLabelMapSeeding
VotingBinaryHoleFillingImageFilter
MyModule (需要添加这个,只改这一处)
)
然后,在I:\Slicer4\Modules\CLI\MyModule目录下,有MyModule.cxx和MyModule.xml.in两个文件,其中已有简单的代码例子,是关于高斯滤波的。可以修改这两个文件来实现你的功能,后者按照xml文件格式编写即可,注意.xml.in中描述的参数名称要与.cxx中的输入输出参数名称对应。下面本人写的一个简单的例子:
MyModule.cxx
#include <iostream>
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkPluginUtilities.h"
#include "MyModule2CLP.h"
#include "itkThresholdImageFilter2.h"
// Use an anonymous namespace to keep class types and function names
// from colliding when module is used as shared object module. Every
// thing should be in an anonymous namespace except for the module
// entry point, e.g. main()
//
namespace
{
template <class T>
int DoIt( int argc, char * argv[], T )
{
PARSE_ARGS;
typedef T PixelType;
typedef itk::Image<PixelType,3> ImageType;
typedef itk::ImageFileReader<ImageType> ReaderType;
typedef itk::ImageFileWriter<ImageType> WriterType;
typedef itk::ThresholdImageFilter2 <ImageType> FilterType;
typename ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName( inputVolume.c_str() );
typename FilterType::Pointer filter = FilterType::New();
filter->SetInput( reader->GetOutput() );
filter->SetMedian(Median);
filter->SetOutsideValue(OutsideValue);
filter->SetInsideValue(InsideValue);
filter->SetLower(Lower);
filter->SetUpper(Upper);
filter->SetSelect(Select);
typename WriterType::Pointer writer = WriterType::New();
writer->SetFileName( outputVolume.c_str() );
writer->SetInput( filter->GetOutput() );
writer->Update();
return EXIT_SUCCESS;
}
} // end of anonymous namespace
int main( int argc, char * argv[] )
{
PARSE_ARGS;
itk::ImageIOBase::IOPixelType pixelType;
itk::ImageIOBase::IOComponentType componentType;
try
{
itk::GetImageType(inputVolume, pixelType, componentType);
// This filter handles all types on input, but only produces
// signed types
switch( componentType )
{
case itk::ImageIOBase::UCHAR:
return DoIt( argc, argv, static_cast<unsigned char>(0) );
break;
case itk::ImageIOBase::CHAR:
return DoIt( argc, argv, static_cast<char>(0) );
break;
case itk::ImageIOBase::USHORT:
return DoIt( argc, argv, static_cast<unsigned short>(0) );
break;
case itk::ImageIOBase::SHORT:
return DoIt( argc, argv, static_cast<short>(0) );
break;
case itk::ImageIOBase::UINT:
return DoIt( argc, argv, static_cast<unsigned int>(0) );
break;
case itk::ImageIOBase::INT:
return DoIt( argc, argv, static_cast<int>(0) );
break;
case itk::ImageIOBase::ULONG:
return DoIt( argc, argv, static_cast<unsigned long>(0) );
break;
case itk::ImageIOBase::LONG:
return DoIt( argc, argv, static_cast<long>(0) );
break;
case itk::ImageIOBase::FLOAT:
return DoIt( argc, argv, static_cast<float>(0) );
break;
case itk::ImageIOBase::DOUBLE:
return DoIt( argc, argv, static_cast<double>(0) );
break;
case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE:
default:
std::cout << "unknown component type" << std::endl;
break;
}
}
catch( itk::ExceptionObject & excep )
{
std::cerr << argv[0] << ": exception caught !" << std::endl;
std::cerr << excep << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
MyModule.xml.in
<?xml version="1.0" encoding="utf-8"?>
<executable>
<category>
</category>
<title>
MyModule2 </title>
<description>
</description>
<version>
</version>
<documentation-url>
</documentation-url>
<license></license>
<contributor>
</contributor>
<acknowledgements>
</acknowledgements>
<parameters>
<label>Input/Output</label>
<description>Input/output parameters</description>
<double>
<name>Median</name>
<longflag>--Median</longflag>
<description>Median</description>
<label>Median</label>
<default>128</default>
</double>
<double>
<name>OutsideValue</name>
<longflag>--OutsideValue</longflag>
<description>OutsideValue </description>
<label>OutsideValue</label>
<default>0</default>
</double>
<double>
<name>InsideValue</name>
<longflag>--InsideValue</longflag>
<description>InsideValue</description>
<label>InsideValue</label>
<default>128</default>
</double>
<double>
<name>Lower</name>
<longflag>--Lower</longflag>
<description>Lower</description>
<label>Lower</label>
<default>64</default>
</double>
<double>
<name>Upper</name>
<longflag>--Upper</longflag>
<description>Upper</description>
<label>Upper</label>
<default>128</default>
</double>
<integer-enumeration>
<name>Select</name>
<longflag>--Select</longflag>
<description>Select</description>
<label>Select</label>
<default>0</default>
<element>0</element>
<element>1</element>
<element>2</element>
<element>3</element>
</integer-enumeration>
</parameters>
<parameters>
<label>Input/Output</label>
<description>Input/output parameters</description>
<image>
<name>inputVolume</name>
<label>Input Volume</label>
<channel>input</channel>
<index>0</index>
<default>None</default>
<description>Input volume</description>
</image>
<image>
<name>outputVolume</name>
<label>Output Volume</label>
<channel>output</channel>
<index>1</index>
<default>None</default>
<description>Output filtered</description>
</image>
</parameters>
</executable>
itkThresholdImageFilter2.h
#ifndef __itkThresholdImageFilter2_h
#define __itkThresholdImageFilter2_h
#include "itkInPlaceImageFilter.h"
#include "itkConceptChecking.h"
namespace itk
{
/**
*/
template <class TImage>
class ITK_EXPORT ThresholdImageFilter2 : public InPlaceImageFilter<TImage,TImage>
{
public:
/** Standard class typedefs. */
typedef ThresholdImageFilter2 Self;
typedef InPlaceImageFilter<TImage,TImage> Superclass;
typedef SmartPointer<Self> Pointer;
typedef SmartPointer<const Self> ConstPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(ThresholdImageFilter2, InPlaceImageFilter);
/** Typedef to describe the type of pixel. */
typedef typename TImage::PixelType PixelType;
/** The pixel type must support comparison operators. */
#ifdef ITK_USE_CONCEPT_CHECKING
/** Begin concept checking */
itkConceptMacro(PixelTypeComparableCheck,
(Concept::Comparable<PixelType>));
itkConceptMacro(PixelTypeOStreamWritableCheck,
(Concept::OStreamWritable<PixelType>));
/** End concept checking */
#endif
itkSetMacro(Median,PixelType);
itkGetConstMacro(Median,PixelType);
void ThresholdMedian(const PixelType &thresh);
itkSetMacro(Select,PixelType);
itkGetConstMacro(Select,PixelType);
void ThresholdSelect(const PixelType &thresh);
itkSetMacro(InsideValue,PixelType);
itkGetConstMacro(InsideValue,PixelType);
void ThresholdInsideValue(const PixelType &thresh);
itkSetMacro(OutsideValue,PixelType);
itkGetConstMacro(OutsideValue,PixelType);
void ThresholdAbove(const PixelType &thresh);
void ThresholdBelow(const PixelType &thresh);
void ThresholdOutside(const PixelType &lower, const PixelType &upper);
itkSetMacro(Lower, PixelType);
itkGetConstMacro(Lower, PixelType);
itkSetMacro(Upper, PixelType);
itkGetConstMacro(Upper, PixelType);
/** Some additional typedefs. */
typedef TImage InputImageType;
typedef typename InputImageType::ConstPointer InputImagePointer;
typedef typename InputImageType::RegionType InputImageRegionType;
typedef typename InputImageType::PixelType InputImagePixelType;
/** Some additional typedefs. */
typedef TImage OutputImageType;
typedef typename OutputImageType::Pointer OutputImagePointer;
typedef typename OutputImageType::RegionType OutputImageRegionType;
typedef typename OutputImageType::PixelType OutputImagePixelType;
protected:
ThresholdImageFilter2();
~ThresholdImageFilter2() {};
void PrintSelf(std::ostream& os, Indent indent) const;
/** ThresholdImageFilter can be implemented as a multithreaded filter.
* Therefore, this implementation provides a ThreadedGenerateData() routine
* which is called for each processing thread. The output image data is
* allocated automatically by the superclass prior to calling
* ThreadedGenerateData(). ThreadedGenerateData can only write to the
* portion of the output image specified by the parameter
* "outputRegionForThread"
*
* \sa ImageToImageFilter::ThreadedGenerateData(),
* ImageToImageFilter::GenerateData() */
void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
int threadId );
private:
ThresholdImageFilter2(const Self&); //purposely not implemented
void operator=(const Self&); //purposely not implemented
PixelType m_Median;
PixelType m_OutsideValue;
PixelType m_Lower;
PixelType m_Upper;
PixelType m_Select;
PixelType m_InsideValue;
};
} // end namespace itk
#ifndef ITK_MANUAL_INSTANTIATION
#include "itkThresholdImageFilter2.txx"
#endif
#endif
itkThresholdImageFilter2.txx
#ifndef __itkThresholdImageFilter2_txx
#define __itkThresholdImageFilter2_txx
#include "itkThresholdImageFilter2.h"
#include "itkImageRegionIterator.h"
#include "itkImageRegionConstIterator.h"
#include "itkNumericTraits.h"
#include "itkObjectFactory.h"
#include "itkProgressReporter.h"
namespace itk
{
/**
*
*/
template <class TImage>
ThresholdImageFilter2<TImage>
::ThresholdImageFilter2()
{
m_Median = 0.5*(NumericTraits<PixelType>::max()+NumericTraits<PixelType>::NonpositiveMin());
m_OutsideValue = NumericTraits<PixelType>::Zero;
m_Lower = NumericTraits<PixelType>::NonpositiveMin();
m_Upper = NumericTraits<PixelType>::max();
m_Select=0;
m_InsideValue=0.5*(NumericTraits<PixelType>::max()+NumericTraits<PixelType>::NonpositiveMin());
this->InPlaceOff();
}
/**
*
*/
template <class TImage>
void
ThresholdImageFilter2<TImage>
::PrintSelf(std::ostream& os, Indent indent) const
{
Superclass::PrintSelf(os,indent);
os << indent << "Median: "
<< static_cast<typename NumericTraits<PixelType>::PrintType>(m_Median)
<< std::endl;
os << indent << "OutsideValue: "
<< static_cast<typename NumericTraits<PixelType>::PrintType>(m_OutsideValue)
<< std::endl;
os << indent << "Lower: "
<< static_cast<typename NumericTraits<PixelType>::PrintType>(m_Lower)
<< std::endl;
os << indent << "Upper: "
<< static_cast<typename NumericTraits<PixelType>::PrintType>(m_Upper)
<< std::endl;
os << indent << "Select: "
<< static_cast<typename NumericTraits<PixelType>::PrintType>(m_Select)
<< std::endl;
os << indent << "InsideValue: "
<< static_cast<typename NumericTraits<PixelType>::PrintType>(m_InsideValue)
<< std::endl;
}
/**
*
*/
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThresholdMedian(const PixelType &thresh)
{
m_Median=thresh;
this->Modified();
}
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThresholdSelect(const PixelType &thresh)
{
m_Select=thresh;
this->Modified();
}
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThresholdInsideValue(const PixelType &thresh)
{
m_InsideValue=thresh;
this->Modified();
}
/**
* The values greater than or equal to the value are set to OutsideValue
*/
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThresholdAbove(const PixelType &thresh)
{
if (m_Upper != thresh
|| m_Lower > NumericTraits<PixelType>::NonpositiveMin())
{
m_Lower = NumericTraits<PixelType>::NonpositiveMin();
m_Upper = thresh;
this->Modified();
}
}
/**
* The values less than or equal to the value are set to OutsideValue
*/
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThresholdBelow(const PixelType &thresh)
{
if (m_Lower != thresh || m_Upper < NumericTraits<PixelType>::max())
{
m_Lower = thresh;
m_Upper = NumericTraits<PixelType>::max();
this->Modified();
}
}
/**
* The values outside the range are set to OutsideValue
*/
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThresholdOutside(const PixelType &lower, const PixelType &upper)
{
if (lower > upper)
{
itkExceptionMacro(<<"Lower threshold cannot be greater than upper threshold.");
return;
}
if (m_Lower != lower || m_Upper != upper)
{
m_Lower = lower;
m_Upper = upper;
this->Modified();
}
}
/**
*
*/
template <class TImage>
void
ThresholdImageFilter2<TImage>
::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
int threadId)
{
itkDebugMacro(<<"Actually executing");
// Get the input and output pointers
InputImagePointer inputPtr = this->GetInput();
OutputImagePointer outputPtr = this->GetOutput(0);
// Define/declare an iterator that will walk the output region for this
// thread.
typedef ImageRegionConstIterator<TImage> InputIterator;
typedef ImageRegionIterator<TImage> OutputIterator;
InputIterator inIt(inputPtr, outputRegionForThread);
OutputIterator outIt(outputPtr, outputRegionForThread);
// support progress methods/callbacks
ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
// walk the regions, threshold each pixel
while( !outIt.IsAtEnd() )
{
const PixelType value = inIt.Get();
if (m_Select==0)
{
if (value <= m_Median)
{
// pixel passes to output unchanged and is replaced by m_OutsideValue in
// the inverse output image
outIt.Set(0);
}
else
{
outIt.Set(255);
}
++inIt;
++outIt;
progress.CompletedPixel();
}
else if(m_Select==1)
{
if (m_Lower <= value && value <= m_Upper)
{
// pixel passes to output unchanged and is replaced by m_OutsideValue in
// the inverse output image
outIt.Set( inIt.Get() );
}
else
{
outIt.Set( m_OutsideValue );
}
++inIt;
++outIt;
progress.CompletedPixel();
}
else if(m_Select==2)
{
if (m_Lower <= value && value <= m_Upper)
{
// pixel passes to output unchanged and is replaced by m_OutsideValue in
// the inverse output image
outIt.Set( m_InsideValue );
}
else
{
outIt.Set( inIt.Get() );
}
++inIt;
++outIt;
progress.CompletedPixel();
}
else
{outIt.Set( 0 );
++inIt;
++outIt;
progress.CompletedPixel();
}
}
}
} // end namespace itk
#endif
xml参数类型选择可以参考http://www.slicer.org/slicerWiki/index.php/Slicer3:Execution_Model_Documentation
最后,用Visual Studio 2008打开I:\Slicer4-SuperBuild\Slicer-build\Slicer.sln,点击 生成解决方案。编译成功后,你的插件便可以在Slicer4中使用。

浙公网安备 33010602011771号