[Insight-developers] Simplifying traits

Miller, James V (CRD) millerjv@crd.ge.com
Thu, 29 Mar 2001 09:39:23 -0500


I am still leaning towards eliminating scalar traits. I would really like to get back to standard
pointer/iterator semantics.

foo = *it;
*it = garf;

The effect of this would be:

1. DataAccessors would have to return a reference.  This would mean that data accessors could only be
used to map memory (i.e. access a scalar from a pixel that held a scalar and vector).  DataAccessors
could not be used for casting or for calculating a function of a pixel.

2. A given filter would assume its inputs were of the correct "type".  If a filter is expecting to
work on scalars, dereferencing an iterator would have to return a scalar.  If a filter is expecting
to work on vectors, derefencing an iterator would have to return a vector. If an algorithm needed
both scalars and vectors, they would be passed in as separate inputs.

The reason for leaning in this direction is that the syntax for accessing a pixel within a filter is
getting rather complicated. Furthermore, we are having reference and const issues in the current
framework.  Last night I was working on a line of code that read

value = (double) ScalarTraits<PixelType>::GetScalar( it.Get() );

and the compiler was giving the error:

GetScalar() cannot convert parameter 1 from "float" to "float &"

Note that this error wasn't even a const issue! Just a reference issue.

Jim





-----Original Message-----
From: Brad King [mailto:brad.king@kitware.com]
Sent: Friday, March 23, 2001 4:37 PM
To: Insight Developers
Subject: [Insight-developers] Simplifying traits


Hello, all:

Here are some ideas to consider before deciding to throw out the use of
ScalarTraits an VectorTraits.  Our current approach is not the simplest
approach to using traits.

We can make traits easier to use.  Consider the following filter:

template <class TInputImage, class TOutputImage>
class MyFilter
{
public:
  typedef TInputImage InputImageType;
  typedef typename InputImageType::PixelType InputPixelType;
  typedef ScalarTraits<InputPixelType> PixelScalarTraits;
  typedef typename PixelScalarTraits::ScalarValueType
          PixelScalarValueType;
  
  inline static PixelScalarValueType& GetPixelScalar(PixelType& p)
    { return PixelScalarTraits::GetScalar(p); }

  inline static void SetPixelScalar(PixelType& p,
                                    const PixelScalarValueType& v)
    { PixelScalarTraits::SetScalar(p, v); }

  // ....
};

Note that the function definitions can be put in ImageToImageFilter and be
inherited into other filters.  Then, with minimal setup work, a filter
implementation can access a Pixel's scalar value like this:

PixelScalarValueType v = GetPixelScalar(myPixel);
  // do something to v.
SetPixelScalar(myPixel, v);

This is in place of the current code:

typename ScalarTraits<PixelType>::ScalarValueType v =
  ScalarTraits<PixelType>::GetScalar(myPixel);
  // do something to v.
ScalarTraits<PixelType>::SetScalar(myPixel, v);

Also, I have noticed that there are a bunch of extra ScalarTrait
specializations for more than the basic types.  An example is
"ScalarTraits< RGBPixel<float> >".  These should not be done, because if
someone wants to use an RGBPixel with a template argument other than those
defined in itkPixelTraits.h, they will have to figure out how to write
their own trait specialization for it.  Currently, this can be solved (I
think) by putting the proper typedefs (ValueType, etc) into RGBPixel and
letting the primary template of ScalarTraits handle it from there.

The "real" way to do such a specialization of the ScalarTraits for
RGBPixel would be to do a partial specialization:

template <typename TComponent>
class ScalarTraits< RGBPixel<TComponent> > { /* ... */ };

Unfortunately, not all of our compilers support partial specialization, so
we can't do this.

The other option is to not require scalar traits to be a speicalization of
ScalarTraits at all.  If instead we make such traits a template argument,
then any class can be defined and passed to the argument:

template <class TPixel, unsigned int VDimension,
          class TPixelTraits = ScalarTraits<TPixel> >
class Image
{
public:
  typedef TPixel PixelType;
  enum { Dimension = VDimension };
  typedef TPixelTraits PixelTraits;
  // ....
};

Then, filters could pull the Pixel traits out of their image template
parameters:

template <class TInputImage, class TOutputImage>
class MyFilter
{
public:
  typedef TInputImage InputImageType;
  typedef typename InputImageType::PixelTraits InputPixelTraits;
  // ... use traits as in previous MyFilter example.
};

Making traits a template argument is currently the approach that the Mesh
class uses.  It even encapsulates the "CellTraits" as a member of the
"MeshTraits" template argument.  We could make the same relationship for
the Image.  That is:

template <typename TPixel, unsigned int VDimension>
class DefaultImageTraits
{
public:
  typedef TPixel PixelType;
  enum { Dimension = VDimension };
  typedef DefaultPixelTraits<PixelType> PixelTraits;
  // ... other useful traits?
};

template <typename TPixel,
          unsigned int VDimension,
          class TImageTraits = DefaultImageTraits<TPixel, VDimension> >
class Image
{
public:
  typedef TImageTraits ImageTraits;
  typedef typename ImageTraits::PixelType   PixelType;
  typedef typename ImageTraits::PixelTraits PixelTraits;

  // ...
};

Assume that we have encapsulated both the current scalar and vector traits
into "DefaultPixelTraits".

Thoughts, anyone?
-Brad



_______________________________________________
Insight-developers mailing list
Insight-developers@public.kitware.com
http://public.kitware.com/mailman/listinfo/insight-developers