eLynx SDK v3.3.0
C++ image processing API reference

What are pixel templates?


Why using pixel templates?

The idea is very simple: defining image as array width x height of pixels we can write generic image processing algorithms based on pixels. We implement only one generic algorithm to cover all image types.

Go to top


What kind of pixel types do we need for astrophotography?

We used to use:

Go to top


What are the pixel formats available in sdk?

We define all requested pixel format in eLynx::Image::EPixelFormat.

We use five different resolutions but not for all types:

We classify pixels by mode, eLynx::Image::EPixelMode:

The most used formats are:

PixelEnum.png

Go to top


How pixel templates are modelized?

Pixel templates are basic struct without any virtual method, so no virtual table.
They derive from eLynx::Image::PixelBase that defines pixel operators.
Template type < T > is the resolution.

We define ten pixel template structs:

template<typename T> struct PixelL;
template<typename T> struct PixelLA;
template<typename T> struct PixelComplex;
template<typename T> struct PixelRGB;
template<typename T> struct PixelHLS;
template<typename T> struct PixelXYZ;
template<typename T> struct PixelLuv;
template<typename T> struct PixelLab;
template<typename T> struct PixelLch;
template<typename T> struct PixelHLab;
template<typename T> struct PixelRGBA;
Pixel1.png

We define 35 pixel structs from pixel templates:

typedef PixelL<ubyte>        PixelLub;
typedef PixelL<ushort>       PixelLus;
typedef PixelL<int>          PixelLi;
typedef PixelL<float>        PixelLf;
typedef PixelL<double>       PixelLd;
typedef PixelLA<ubyte>       PixelLAub;
typedef PixelLA<ushort>      PixelLAus;
typedef PixelLA<int>         PixelLAi;
typedef PixelLA<float>       PixelLAf;
typedef PixelLA<double>      PixelLAd;
typedef PixelComplex<int>    PixelComplexi;
typedef PixelComplex<float>  PixelComplexf;
typedef PixelComplex<double> PixelComplexd;
typedef PixelRGB<ubyte>      PixelRGBub;
typedef PixelRGB<ushort>     PixelRGBus;
typedef PixelRGB<int>        PixelRGBi;
typedef PixelRGB<float>      PixelRGBf;
typedef PixelRGB<double>     PixelRGBd;
typedef PixelHLS<float>      PixelHLSf;
typedef PixelHLS<double>     PixelHLSd;
typedef PixelXYZ<float>      PixelXYZf;
typedef PixelXYZ<double>     PixelXYZd;
typedef PixelLab<float>      PixelLabf;
typedef PixelLab<double>     PixelLabd;
typedef PixelLuv<float>      PixelLuvf;
typedef PixelLuv<double>     PixelLuvd;
typedef PixelLab<float>      PixelLchf;
typedef PixelLab<double>     PixelLchd;
typedef PixelLab<float>      PixelHLabf;
typedef PixelLab<double>     PixelHLabd;
typedef PixelRGBA<ubyte>     PixelRGBAub;
typedef PixelRGBA<ushort>    PixelRGBAus;
typedef PixelRGBA<int>       PixelRGBAi;
typedef PixelRGBA<float>     PixelRGBAf;
typedef PixelRGBA<double>    PixelRGBAd;
Pixel2.png

Go to top


How to access to pixel datas?

Each pixel template is defined as a array of channels of template resolution < T >.
For explanations we take PixelRGB as concrete example.

template<typename T>
struct PixelRGB : public PixelBase< PixelRGB<T> >
{
  typedef T type;

  union {
    type _channel[3];
    struct {
      type _red;
      type _green;
      type _blue;
    };
  };
  static const uint GetChannelCount()        { return 3; }
  static const EResolution GetResolution()   { return ResolutionTypeTraits< T >::_Resolution; }
  ...  
};

We use union to have both generic and specific sample naming.
Here _channel[0] is _red, _channel[1] is _green and _channel[2] is _blue.

Writing code with generic pixel we MUST only use _channel access:

template <class Pixel>
Pixel elxMin(const Pixel& iPixel1, const Pixel& iPixel2)
{
  Pixel tmp;
  const uint nChannel = Pixel::GetChannelCount();
  for (uint c=0; c<nChannel; c++)
  {
    tmp._channel[c] = (iPixel1._channel[c] < iPixel2._channel[c] ) ?
      iPixel1._channel[c] : iPixel2._channel[c];
  }
  return tmp;
}

With specialized pixel we can use specific sample naming.
Writing code with specialized pixel with generic resolution:

template <typename T>
void TracePixelRGB(const PixelRGB<T>& iPixel)
{
  cout << "template RGB"
       << " red="   << iPixel._red
       << " green=" << iPixel._green 
       << " blue="  << iPixel._blue << endl;
}

Writing code with specialized pixel with resolution specialization:

template <>
void TracePixelRGB(const PixelRGB<ubyte>& iPixel)
{
  cout << "template RGB in ubyte"
       << " red="   << int(iPixel._red)
       << " green=" << int(iPixel._green )
       << " blue="  << int(iPixel._blue) << endl;
}

Writing code with full specialized pixel:

void TracePixelRGBub(const PixelRGBub& iPixel)
{
  cout << "specialized RGBub"
       << " red="   << int(iPixel._red)
       << " green=" << int(iPixel._green )
       << " blue="  << int(iPixel._blue) << endl;
}

Using all together:

PixelRGBub p1(10, 50, 233), p2(25, 255, 0);
TracePixelRGB(p1);
TracePixelRGB(p2);
PixelRGBub p3 = elxMin(p1, p2);
TracePixelRGBub(p3);

At run time we get:
template RGB in ubyte red=10 green=50 blue=233
template RGB in ubyte red=25 green=255 blue=0
specialized RGBub red=10 green=50 blue=0

PixelRGBd p1(0.5, 1.0, 0.33), p2(0.99, 0.1, 0.2);
TracePixelRGB(p1);
TracePixelRGB(p2);
PixelRGBd p3 = elxMin(p1, p2);
TracePixelRGB(p3);

At run time we get:
template RGB red=0.5 green=1 blue=0.33
template RGB red=0.99 green=0.1 blue=0.2
template RGB red=0.5 green=0.1 blue=0.2

Go to top


How to access to pixels from ImageImpl?

It's simple because ImageImpl is defined as a < Pixel > template.
You access pixel with GetPixel(), GetPixelEnd() and GetPixel(x,y):

template <class Pixel>
bool Process(ImageImpl<Pixel>& ioImage)
{
  if (!ioImage.IsValid()) return false;
  
  // get first pixel of image
  Pixel * prCurrent = ioImage.GetPixel();
  
  // get last pixel of image
  Pixel * prEnd = ioImage.GetPixelEnd();
  
  // process all pixels
  do 
  { 
    // do something with prCurrent pixel
  } 
  while (++prCurrent != prEnd);
  
  // get pixel at position x=10 and y=20
  prCurrent = ioImage.GetPixel(10, 20);
  
  return true;
}

Go to top


How to access to pixels from AbstractImage?

We only know pixel format at runtime with AbstractImage. So it's not a good idea to access pixels from this class. But as AbstractImage can be used in pixel template methods, we write PixelIteror to access template image's pixels. But be aware that it means that AbstractImage has < Pixel > type.
If AbstractImage is of another pixel type an exception is thrown.
You can access to pixel with PixelIterator:

template <typename Pixel>
bool Process(AbstractImage& ioImage)
{
  if (!ioImage.IsValid()) return false;

  // get first pixel of image
  PixelIterator<Pixel> prCurrent = elxDowncast<Pixel>(ioImage.Begin());

  // get last pixel of image
  PixelIterator<Pixel> prEnd = elxDowncast<Pixel>(ioImage.End());

  // process all pixels
  do 
  { 
    // do something with prCurrent pixel
  } 
  while (++prCurrent != prEnd);
  return true;
}

We can run process because image1 is of PixelRGBf type:

ImageRGBf imageRGBf(40, 30);
AbstractImage& image1 = imageRGBf;
Process<PixelRGBf>(image1);

But next code will generate an exception because image2 is PixelRGBd
type and it's processed as PixelRGBf type:

ImageRGBd imageRGBd(30, 40);
AbstractImage& image2 = imageRGBd;
Process<PixelRGBf>(image2);

We can also use PixelIterator from const AbstractImage:

template <typename Pixel>
boost::shared_ptr< ImageImpl<Pixel> > Copy(const AbstractImage& iImage)
{
  if (!iImage.IsValid()) 
    return boost::shared_ptr< ImageImpl<Pixel> >();

  const uint w = iImage.GetWidth();
  const uint h = iImage.GetHeight();

  // create the new image
  boost::shared_ptr< ImageImpl<Pixel> > spImage( new ImageImpl<Pixel>(w,h) );
  if (!elxUseable(spImage.get())) 
    return boost::shared_ptr< ImageImpl<Pixel> >();

  // get first pixel of input image
  PixelIterator<const Pixel> prCurrent = elxConstDowncast<const Pixel>(iImage.Begin());

  // get first pixel of output image
  Pixel * prDst = spImage->GetPixel();

  // get last pixel of output image
  Pixel * prEnd = spImage->GetPixelEnd();

  // copy all pixels
  do 
  {
    *prDst = *prCurrent++;
  } 
  while (++prDst != prEnd);
  return spImage;
}

Using const AbstractImage:

ImageRGBus imageRGBus(100, 10);
AbstractImage& image3 = imageRGBus;
boost::shared_ptr< ImageRGBus > spImage = Copy<PixelRGBus>(image3);

Go to top


How to access to pixels from ImageVariant?

TODO

Go to top


Generated on Thu Dec 9 2010 by doxygen 1.7.2