Author Topic: A few pointers on use of Image and ImageWindow classes in JavaScript  (Read 6712 times)

Offline astrospotter

  • Newcomer
  • Posts: 41

If there is in fact some reference on use of Image and ImageWindow and some conceptual or docs on the FFT function  I am an experienced C++ programmer and could sort this out.  (Most all my code background is not in graphics work).  Web searches tell me these are PixInsight specific and not some form of generic JavaScript or I could get help from web.  Searching PI help I only find a page 'under construction' on script development.  So I'm stuck.  Please help.

I have had no trouble putting together a full 'shell' for this code to pull in multiple files using mostly code stolen from batch debayer (thanks).   I am stuck on very basic working with images concepts  AND FFT/IFFT to those images.


The general problem:
I wish to take an fft of a sourceImage and then manipulate the magnitude Image with a filter of my own construction. I believe from other examples I can manipulate the Image once in memory but am stuck on fundamentals of getting that image.

Here is completely wrong code but just as a start ...

var C = Image.newComplexImage();
C.assign(sourceImage);                         // sourceImage I can do a .show() on and I see this image on screen ok
C.FFT(true);                                            // I think this may be an FFT but conceptually don't know what complex image is

// So now I 'think' I have a magnitude DFT image within this complex image but don't know how to get at it
var outImageWindow = new ImageWindow(srcWidth, srcHeight, 3,32, true, true, "output");

// Here is where I am flat out guessing and have tried numerous things but just don't know how to get at the DFT magnitude OR if I have even acquired it yet in above FFT. 

var outputView - outImageWindow.mainView;     // I really have no idea conceptually how all this is supposed to work
var outputImage = C.FFT(true);   // I have messed with Image.crossPowerSpectrumMatrix() here as well with no luck

// Would like to stretch this DFT mag image then  filter that with simplistic walking of x for each row (y).
// I think once in 'image' form that part I can do so no need to go there in any reply.

// After that I wish to show that image then save it to a new file.  I see examples of how to save an image to
// a file so that I feel ok with.   I am having most of my grief in obtaining the DFT magnitude and showing the image.

Thanks for any pointers to docs or example scripts that are documented enough to reverse engineer.
I have tried for several hours to reverse engineer from existing scripts in PI before asking such questions but I am tapped out and cannot find answers to Graphics windows and ComplexImage so present my goal and my feeble attempts to reverse engineer this stuff.  I am stuck in lack of syntax land and cannot escape.   

Mark


Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Hi Mark,

Unfortunately we still have no reference documentation for the PixInsight JavaScript Runtime (PJSR). We'll start fixing this problem this Fall/Winter. The new version 1.8 of PixInsight includes an integrated PJSR documentation system (Object Explorer), similar to the Process Explorer window.

In the meanwhile, the only references for PJSR programming are the existing scripts and, above all, this forum. So please feel free to ask any doubts here and we'll try to do our best to help you.

Quote
I wish to take an fft of a sourceImage and then manipulate the magnitude Image with a filter of my own construction.

Take a look at this code snippet:

Code: [Select]
/*
 * Returns the discrete Fourier transform (DFT) of an image as a new complex image.
 */
function DFT( image )
{
   var C = Image.newComplexImage();
   C.assign( image );
   C.FFT( true/*centered*/ ); // DFT centered on the transformation matrix
   return C;
}

This code defines a function that takes an image as argument and returns a complex image with its discrete Fourier transform. In PixInsight, each pixel of a complex image is a complex number with a real and an imaginary part. The real and imaginary components allow you to compute the magnitude and the phase of the DFT with the Complex.mag() and Complex.arg() methods, respectively.

A few important remarks about FFTs in PixInsight (this applies to both PJSR and PCL):

- PixInsight implements FFT routines able to work with vectors and matrices of arbitrary dimensions. You don't need to care about dimensions being powers of two, etc.

- The FFT routines can increase the original dimensions of the image, for optimization purposes. This means that the width and height of the C image in the function above can be slightly larger than the dimensions of the original image (usually the difference is less than 10 pixels).

- The FFT and inverse FFT routines can work with centered or non-centered DFTs. In a centered DFT, the 'DC' component of the transform (that is, the 'zero frequency' component) is located at the geometric center of the transform matrix (in the example above, at the central pixel of C). In a non-centered transform, the DC component is the top left pixel of the DFT. This can be controlled with a Boolean parameter of the Image.FFT() and Image.inverseFFT() methods.

- The inverse one-dimensional DFT is always scaled by the length of the transformed vector. This means that the inverse DFT of an image must be divided by the area of the transform matrix to yield the original range of pixel values. For example:

var R = new Image;
// ...
var I = Image.newComplexImage();
I.assign( R );
I.FFT();
I.inverseFFT();
R.assign( I ); // R = magnitude of I multiplied by I.width*I.height
R.apply( I.width*I.height, ImageOp_Div ); // return to the original range


Once you have the DFT of the image, you can modify it to implement your filter. For example, you can alter the magnitude component of the DFT pixel by pixel as follows:

Code: [Select]
function MyMagnitudeFilterFunction( dft )
{
   for ( var y = 0; y < dft.height; ++y ) // for each row
      for ( var x = 0; x < dft.width; ++x ) // for each column
      {
         var c = dft.sample( x, y );

         /*
          * c is a Complex object. c.real and c.imag are the real and imaginary
          * parts of the DFT for the current x,y coordinates.
          */
         var mag = c.mag();
         var phase = c.arg();
         mag = .... // Apply your function here
         c = Complex.polar( mag, phase );
         
         dft.setSample( c, x, y );
      }
}

Or you can modify the complex image as a whole, depending on what you want to achieve. Finally, you can perform the inverse Fourier transform to get your transformed image. This is a little working example:

Code: [Select]
#include <pjsr/ImageOp.jsh>
#include <pjsr/UndoFlag.jsh>

function DFT( image )
{
   var C = Image.newComplexImage();
   C.assign( image );
   C.FFT( true/*centered*/ ); // DFT centered on the transformation matrix
   return C;
}

function IdealHighPassFilter( dft, radius )
{
   var x0 = dft.width/2;
   var y0 = dft.height/2;
   var r = Math.round( Math.range( radius, 0, 1 ) * Math.max( dft.width, dft.height ) );
   var r2 = r*r;
   for ( var y = y0-r; y <= y0+r; ++y )
   {
      var dy = y - y0;
      for ( var x = x0-r; x <= x0+r; ++x )
      {
         var dx = x - x0;
         if ( dx*dx + dy*dy < r2 )
            dft.setSample( 0, x, y );
      }
   }
}

var dft = DFT( ImageWindow.activeWindow.mainView.image );
IdealHighPassFilter( dft, 0.1 ); // remove a 10% of the low frequencies
dft.inverseFFT( true/*centered*/ );

var outputWindow = new ImageWindow( 1, 1, 1, 32/*bitsPerSample*/, true/*floatSample*/ );
var outputView = outputWindow.mainView;
outputView.beginProcess( UndoFlag_NoSwapFile ); // don't save an undo state
outputView.image.assign( dft ); // get the magnitude of DFT
outputView.image.apply( dft.width*dft.height, ImageOp_Div ); // rescale
outputView.endProcess();

outputWindow.show();
outputWindow.zoomToFit();

This example applies an ideal filter in the frequency domain. The ideal high-pass filter simply removes a range of low-frequency components of the DFT by setting their magnitudes to zero. As you can see, the results of an ideal filter are anything but 'ideal' (terrible ringing...), but this is just an example to show you the mechanics.

Let me know if this is the kind of information that you need.

(2012/08/26 07:54 UTC - Edited to fix a few mistakes in the examples)
« Last Edit: 2012 August 27 00:54:31 by Juan Conejero »
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Mark,
For me, it is sometimes helpful to look at the PCL documentation to find out what PJSR does. You can find it on the main website. You should also be aware of the limitations of PJSR (such as no concurrent operation with other windows such as reatime preview or histogram, plus limitations with storing instances in history). If you are comfortable with C++, consider switching to it when you go beyond prototyping.
Georg
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)

Offline Carlos Milovic

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2172
  • Join the dark side... we have cookies
    • http://www.astrophoto.cl
Also, since you are a C++ programer, you may write a module. Here http://pixinsight.com/forum/index.php?topic=2275.0 are some of the processes I wrote, and their source codes are here: http://pteam.pixinsight.com/pcldev/carlos/src
Feel free to use them as a starting point for your own processes. If you are interested in frequency filtering, I recommend you to take a look at the "ButterworthFilter" process. It is a very simple process, that shows all the basics.
Regards,

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

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Also look at the PCL tutorial in the only issue  :-[ of the Pixinsight Magazine http://pixinsight.com/magazine/.
Georg
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)

Offline astrospotter

  • Newcomer
  • Posts: 41
Thanks Juan and other fine gents!

The pieces Juan supplied seem quite reasonable and I 'get it' now.  the MyMagnitudeFilterFunction() example is 'gold' showing available functions and sample extraction from the DFT.     I was unable to reverse engineer the pieces I wanted syntactically.
   Complex numbers and mag/phase pairs I worked with all to often in my electrical engineering classes so together with the brief code examples I feel that is great info.

Thanks Gents,
Mark Johnston

Offline astrospotter

  • Newcomer
  • Posts: 41
Re: A few pointers on use of Image and ImageWindow classes in JavaScript
« Reply #6 on: 2012 September 02 12:19:51 »
ATTENTION Juan:    Your reply contained the exact key pieces of information that I felt needed to be somehow brought to light for would-be javascript script writers who use DFT/IDFT or wish to display some processed image data.

SUGGESTION:  It may be handy if your reply only were placed in a 'sticky thread' at the top of this development section with a title like  'Working with DFT and IDFT and display of image data within java script'  I realize these are burried in other scripts but a 'how to' simple example like you supplied is 'gold'.

Just a thought and of course I realize you are very busy but these pieces are so key and so valuable I thought it worth mention.

The tool I formed works well from the standpoint of these aspects and now I have a 'platform' to work on witout frustration of the key mechanisms I required to get to the data.

Thanks again Juan (and all who replied as I may very well move to C++ as time and my needs for PI progress)   
« Last Edit: 2012 September 02 12:40:34 by astrospotter »