[Insight-users] Bug with fix Mean Image Filter : Color Spaces are not Vector Spaces

Luis Ibanez luis.ibanez at kitware.com
Wed May 18 19:31:37 EDT 2005



Hi Brad,


This is a common misconception originated by the fact that
Computer Scientist and Software Engineers misuse the term


                      "Vector"


The word "Vector" was coined by William Hamilton in his book
"Elements of Quaternions" published in 1886 (post-mortem).


In the same text Hamilton coined the terms:

                     "Scalar"
                     "Versor"
                     "Tensor"



A "Vector" is by definition mathematical object that embodies
the concept of "direction in space". Strictly speaking, a Vector
describes the relationshiop between two points in space, and
captures both their relative distance and orientation.



Computer scientists and software engineers missused the term
vector in order to represent the concept of an "Indexed Set".
Mechanical Engineers and Civil Engineers, who deal with the
real world of physical objects will not commit this mistake
and will keep the word "Vector" attached to a geometrical
concept. Biologist, on the other hand will associate "Vector"
to a "vehicle" that allows them to direct something in a
particular direction.



Textbooks in programming do not help to clarify those concepts
and losely use the term "Vector" for the purpose of representing
an "Enumerated set of common elements".

STL follows this trend and continue using the word "Vector" for
what it was not supposed to be used.

Linear Algebra devoids the "Vector" from its notion of Geometrical
reality and makes it an abstract set of numbers with arithmetic
operations associated.




In ITK we deal with real objects that inhabit the physical space.

We chose to give the appropriate name to the mathematical objects
that describe geometrical relationships in N-Dimensional space.


Is for this reason that we explicitly make clear the distincion
between:


              1) Point
              2) Vector
              3) CovariantVector



... despite de fact that most people would be happy with a simple
use of double[3] for the three concepts and then will proceed to
perform all sort of conceptually flawed operations such as
"adding two points" or "dividing a point by a scalar", or
"adding a covariant vector to a point", or "adding a covariant
vector to a vector".



In order to enforce the decent use of the Geometrical concepts in ITK
we organized this classes in a hierarchy that supported reuse of code
and yet compartamentalize the behavior of the individual classes.
The use of the "FixedArray" as base class of the "Point", the "Vector"
and the "CovariantVector" was a design decision based on calling
things by their correct name.




A "FixedArray" is an enumerated collection with a fixed number
of elements. You can instantiate a fixed array of letters, or
a fixed array of images, or a fixed array of transforms, or a
fixed array of geometrical shapes.

Therefore, the FixedArray should only implement the functionality
that is necesary to "access" those enumerated elements. No assumptions
can be made at this point on any other operations required by the
elements of the FixedArray, except the fact of having a default
constructor.



The "itkPoint" is a type that represents the spatial coordinates
of a spatial location. Based on geometrical concepts we defined
the valid operations of the Point class. In particular we made
sure that no operator+() was defined between Points, and that no
operator*( escalar ) nor operator/() scalar were defined for points.


In other words, you could do in ITK operations such as:

          Vector  = Point - Point
          Point  +=  Vector
          Point  -=  Vector
          Point  = BarycentricCombination( Point, Point )



and you cannot (because you *should not*) do operation such as

          Point = Point * Scalar    // INVALID OPERATION
          Point = Point + Point     // INVALID OPERATION
          Point = Point / Scalar    // INVALID OPERATION




The "itkVector" is, by Hamilton's definition, the subtraction
between two points. Therefore a "Vector" must satisfy the
following basic operations:


          Vector = Point - Point
          Point  = Point + Vector
          Point  = Point - Vector
          Vector = Vector + Vector
          Vector = Vector - Vector


A "Vector" object is intended to be instantiated over elements
that support matematical operation such as addition, subtraction
and multiplication by scalars.




The "itkRGBPixel" type, embodies a different concept from the ones
of Vectors in space. The RGB is a representation a human physiological
capability to analyze visual light using three sprectral sensors.
The RGB space *is not* a vector space. For example, negative numbers are
not appropriate in a color space because they will be the equivalent of
'negative stimulation' on the human eye. People in colorimetry use
negative color values as an artificial construct for color comparision
in the sense that

         ColorA = ColorB - ColorC

*just* as a way of saying that they can produce ColorB by combining
ColorA and ColorB.  But they are aware that (at least in emitted light)
it is not possible to "substracts light". So when they say

         ColorA = ColorB - ColorC

they actually mean

         ColorB = ColorA + ColorC




On the other hand, when dealing with printed color and with paint
(as opposed to emmitted light like in computer screens) the physical
behavior of color allows for subtraction, because strictly speaking
the objects that you see as red are those that absorb all light
frequencies *except* those in the red section of the spectrum.



The concept of addition and subtraction of colors has to be carefully
interpreted. In fact, RGB has a different definition regarding you
are talking about the channels associated to the three color sensors
of the human eye, or to the three phosphors found in most computer
screeens or to the color inks that are used for printing reproduction.

See for example:

          http://www.drycreekphoto.com/Learn/color_spaces.htm

and

          http://www.color.org

Color spaces are usually non linear and do not even from a group.


When you anticipate to perform the operation of "Mean" on a RGB type
you are assuming that in the color space provides the action of finding
a color "in the middle" of two colors, can be found by using a linear
operation between their numerical representation. This is unfortunately
not the case in  color spaces due to the fact that they are based on
human perception.



You can of course, just ignore the "RGB color space" nature of
the image and manage RGB images as a set of three independent
channels.

In that case, you could simply "Adapt" or "Convert" your RGB image
into a image of itk::Vector< float, 3 > and use operations such as
"Mean" on it.




To summarize:



1) Color space is not a Vector space.

    This is the reason why the itk::RGBPixel type does not
    provide any arithmetic operations. Only Luminance is
    implemented.



2) If you are willing to disregard the physical nature of
    what R,G,B values mean, then you can simply read your
    RGB images using a type such as

         typedef  itk::Vector< float, 3 >  PixelType;
         typedef  itk::Image< PixelType, 2 >   ImageType;
         typedef  itk::ImageFileReader< ImageType > ReaderType;

    and use this ImageType for instantiating the MeanImageFilter.


    Note that the result of the "Mean operation" may not be
    what you expect to be the "color in the middle" in the
    sense of human visual perception.





Please let us know if you have further questions,



     Thanks




        Luis







=====================================================================
Bradley Lowekamp wrote:

> 
>     /it.Set( static_vast<OutputPixelType>(sum * ( 1.0 /
>     double(neighbothoodSize))) );/
> 
> 
> That should work too. But I think that it is an oversite that 
> NumericTraits<RGBPixel> does not have ScalarRealType.
> 
> With regards to the added operator to RGBPixel (and likely for RGBAPixel 
> too), I am still confused about the differences between FixedArray and 
> Vector classes. I think I read in the Software Guide instances where 
> each were used, though I can't seemed to find an example of FixedArray 
> at the moment. The Vector class provides many math operators so I also 
> don't understand why they specific pixel types were not derived from the 
> Vector class.
> 
> 
> Thanks.
> 
> ========================================================
> Bradley Lowekamp
> Management Systems Designers Contractor for
> Office of High Performance Computing and Communications
> National Library of Medicine
> 'blowekamp at mail.nih.gov
> 
> 
> On May 18, 2005, at 9:22 AM, Miller, James V ((Research)) wrote:
> 
>     Can you use:
>      
>      
>     /A better option is probably to add scalar division (by a floating
>     point type) to the RGBPixel type./
>      
>     /Jim/
> 
>         -----Original Message-----
>         *From:* insight-users-bounces+millerjv=crd.ge.com at itk.org
>         [mailto:insight-users-bounces+millerjv=crd.ge.com at itk.org]*On
>         Behalf Of *Bradley Lowekamp
>         *Sent:* Tuesday, May 17, 2005 4:58 PM
>         *To:* insight-users at itk.org
>         *Subject:* [Insight-users] Bug with fix Mean Image Filter
> 
> 
>         I was trying to use mean Image Filter with RGBPixel Type. This
>         failed because this pixel type did not supported the needed
>         operator. This was the line
> 
> 
> 
>         /// get the mean value/
> 
>         /it.Set( static_vast<OutputPixelType>(sum /
>         double(neighbothoodSize)) );/
> 
> 
> 
>         RGBPixels do not support the divide by scalars operator. Perhaps
>         because this type may have only been designed to used with
>         unsigned chars? Any way the fix I coded up was:
> 
> 
>         // get the mean value/ /
> 
>         /it.Set( static_vast<OutputPixelType>(sum *
>         (1.0/NumericTraits<OutputPixelType>::ScalarRealType(neighbothoodSize)))
>         );/
> 
> 
> 
>         However, that didn't work because
>         NumericTraits<RGBPixel<unsigned char>> does not have a
>         ScalarRealType member, like every other numeric traits. I
>         actually am using RGBPixelType<double> but I implemented the
>         numeric traits my self.
> 
> 
>         Thanks.
> 
> 
> 
> 
>         ========================================================
> 
>         Bradley Lowekamp
> 
>         Management Systems Designers Contractor for
> 
>         Office of High Performance Computing and Communications
> 
>         National Library of Medicine
> 
>         'blowekamp at mail.nih.gov
> 
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Insight-users mailing list
> Insight-users at itk.org
> http://www.itk.org/mailman/listinfo/insight-users







More information about the Insight-users mailing list