Author Topic: PCL - Pixel Interpolation  (Read 6796 times)

Offline Carlos Milovic

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2172
  • Join the dark side... we have cookies
    • http://www.astrophoto.cl
PCL - Pixel Interpolation
« on: 2007 November 01 13:08:19 »
Here is a question to vitalize a bit this section with C++ code ;)

Let's say I have an image and I need to make operation between pixels, but I need the value of a virtual pixel in a non-integer coordinate. So, the obvious thing to do (apart from using a nearest neightbour scheme) is to interpolate. The PCL includes many in-build interpolations... so, how to a get the desired "pixel" value, with a user defined interpolation (of course, this is a bidimensional interpolation)?


BTW, let's assume that the integer values are the center of the pixels, not the top left corner.
Regards,

Carlos Milovic F.
--------------------------------
PixInsight Project Developer
http://www.pixinsight.com

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
PCL - Pixel Interpolation
« Reply #1 on: 2007 November 05 03:19:36 »
Hi Carlos,

Excellent programming topic :)

You can use the BicubicPixelInterpolation class. Here is a small snippet that you can use to test your routines:

Code: [Select]
#include <pcl/PixelInterpolation.h>

namespace pcl
{

Image img; // this is the image you want to interpolate

// Let's use a bicubic pixel interpolation.
BicubicPixelInterpolation B;

// Create an interpolator object for the first channel of img.
BicubicPixelInterpolation::Interpolator<FloatPixelTraits>& I =
   *B.NewInterpolator( (FloatPixelTraits*)0, img[0], img.Width(), img.Height() );

// Now interpolate at arbitrary locations. Interpolators are functional classes.
// You can invoke them as if they were functions.
float v1 = I( 0.12345, 6.78901 );
float v2 = I( 9.87654, 3.21098 );
// ...

// When you're done with the interpolation, you must destroy the interpolator object.
delete &I;

} // pcl


Note that the interpolator constructor call:

Code: [Select]
B.NewInterpolator( (FloatPixelTraits*)0, img[0], img.Width(), img.Height() );

takes a first argument that is a pointer to the pixel traits class of the image. This is necessary due to language syntax limitations, but this argument is not used by the interpolator except to identify the pixel traits type. Always passs a zero pointer casted to the pixel traits class of the image being interpolated.

A more elaborated example involves exception handling and a fully templatized use of the interpolator class:

Code: [Select]
#include <pcl/PixelInterpolation.h>
#include <pcl/ErrorHandler.h>

namespace pcl
{

// This routine can be invoked for any supported image type.
template class <P>
void MyInterpolationRoutine( const Generic2DImage<P>& img, PixelInterpolation& P )
{
   PixelInterpolation::Interpolator<P>* interpolator = 0;

   try
   {
      interpolator = P.NewInterpolator(
         (P*)0, img[img.SelectedChannel()], img.Width(), img.Height() );

      // Do the interpolation stuff
      typename P::sample v1 = (*interpolator)( 0.12345, 6.78901 );
      typename P::sample v2 = (*interpolator)( 9.87654, 3.21098 );
      // ...

      // When done, delete the interpolator
      delete interpolator;
      interpolator = 0;

      return;
   }

   catch ( ... ) // catch-all
   {
      if ( interpolator != 0 )
         delete interpolator;
      throw; // rethrow the catched exception
   }
}

template class <P>
void foo( const Generic2DImage<P>& img )
{
   try
   {
      BicubicPixelInterpolation B;
      BicubicBSplinePixelInterpolation Bs;

      // You can call the interpolation routine with different pixel interpolations.
      MyInterpolationRoutine( img, B );
      MyInterpolationRoutine( img, Bs );

      // ...

      return;
   }

   // Handle all PCL exceptions
   ERROR_HANDLER
}

} // pcl


Interpolator objects are dynamically allocated, so it is very important to ensure that they will be properly destroyed in the event of an exception being thrown. Otherwise you'll be creating a memory leak.

Hope this clarifies the use of pixel interpolations with the PCL.

Quote
let's assume that the integer values are the center of the pixels, not the top left corner.


The PCL works on the basis that real (floating point) pixel coordinates refer to the upper left corner of each pixel. If you want to move the origin of coordinates by a fraction of a pixel, I suggest that you write an ad-hoc conversion function. For example:

Code: [Select]
inline DPoint ImageToMyWorld( double x, double y )
{
   return DPoint( x+0.5, y+0.5 );
}

inline DPoint ImageToMyWorld( const DPoint& p )
{
   return ImageToMyWorld( p.x, p.y );
}

// ...

typename P::sample v1 = (*interpolator)( ImageToMyWorld( 0.12345, 6.78901 ) );


In this way you can easily move your origin of coordinates in a consistent and elegant way.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline Carlos Milovic

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2172
  • Join the dark side... we have cookies
    • http://www.astrophoto.cl
PCL - Pixel Interpolation
« Reply #2 on: 2007 November 05 13:44:50 »
Thanks for the complete answer ;) You know that I'm not that fond of pointers, so I was afraid that it was something like this.  :oops:
Regards,

Carlos Milovic F.
--------------------------------
PixInsight Project Developer
http://www.pixinsight.com