Author Topic: Masking a script with a dynamically generated PixelMath instance  (Read 8967 times)

Offline Juan Conejero

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

This is a small script from other thread that applies a simple convolution with a low-pass filter. It was originally intended to be part of a star shaping procedure. The idea is to generate a special star mask (a mask that is not black only for stars larger than a given size), e.g. with wavelets, activate it on the target image of interest, and then apply this script.  Hey, and it works well 8)

There is no user interface; any changes must be made by editing the source code. I wrote a filter that has a somewhat prominent central value, with the purpose of preserving reasonable stellar profiles. But of course you can experiment with anything representable as a kernel filter; it's pretty straightforward. Nothing stops you from trying a high-pass filter, for example, or anything more exotic.

More technically now. Actually, what makes this script of special interest? As I've said, the intent was to apply a star shaping procedure, so the script must work masked. Fine. But then we have a small problem: script actions cannot be masked...

The solution is to create a temporary working image as a copy of the target image, convolve it with a kernel filter, and then merge it with the target image (through its active mask) with a dynamically generated instance of the PixelMath process. This is possible because all installed processes are automatically scriptable in PixInsight. Since PixelMath is of course a maskable process, we have our cookie and can eat it :mrgreen:

Here we go:

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

function main()
{
   // Hide the processing console window (only if it isn't a floating window,
   // i.e. if it's docked).
   console.hide();

   // Get access to the currently active image window.
   var window = ImageWindow.activeWindow;

   // Do we have one?
   if ( window.isNull )
      throw Error( "There is no active image window!" );

   // Get access to its main view, so we can pick some properties of the image
   // it encapsulates.
   var view = window.mainView;

   // Create a working image with identical parameters to the target image.
   var workingWindow = new ImageWindow( view.image.width,
                                        view.image.height,
                                        view.image.numberOfChannels,
                                        window.bitsPerSample,
                                        window.isFloatSample,
                                        view.image.colorSpace != ColorSpace_Gray,
                                        "temporary" );
   
   // Access to the working image's main view
   var workingView = workingWindow.mainView;

   // Begin processing the working view's image. Since this is a temporary
   // working object, we don't want to write a swap file to undo it.
   workingView.beginProcess( UndoFlag_NoSwapFile );

   // Copy the target image to our working image
   workingView.image.apply( view.image );

   // Apply a convolution. This is the magic part :o)
   workingView.image.convolve( [ 1,  2,  4,  2, 1,
                                 2,  6, 12,  6, 2,
                                 4, 12, 24, 12, 4,
                                 2,  6, 12,  6, 2,
                                 1,  2,  4,  2, 1 ] );

   // Done with working view. Never forget this, or the PJSR will bite you.
   workingView.endProcess();

   // Now create a PixelMath instance to merge our (convolved) working image
   // with the target image. Hopefully, this will happen through a mask.
   var mergeThem = new PixelMath;
   mergeThem.expression = workingView.id;
   mergeThem.useSingleExpression = true;
   mergeThem.rescale = false;
   mergeThem.executeOn( view );

   // Job done: destroy our working image.
   workingWindow.close();
}

main();
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Re: Masking a script w/ dynamically generated PixelMath inst
« Reply #1 on: 2007 September 12 11:43:58 »
Quote from: "Juan Conejero"
script actions cannot be masked...

Code: [Select]
  workingView.image.convolve( [ blah ] );

Code: [Select]
  mergeThem.executeOn( view );


Ok, so this is how I understand that:

 - The user applies a mask to the image before running the script.
 - workingView.image.convolve bypasses the mask. I can understand that, because .convolve is acting directly on the image.
 - mergeThem does not bypass the mask. I can understand it too, since it's an external process, not an image operation.

But then, why isn't there a "Convolve" process? If we had one, we wouldn't need this PixelMath instance, since the Convolve external process would respect the mask.

Does this make sense?

Bueno, así es como lo veo:

 - El usuario aplica una máscara a la imagen antes de ejecutar el script.
 - workingView.image.convolve se salta la máscara. Puedo entenderlo, dado que .convolve actúa directamente sobre la imagen.
 - mergeThem no se salta la máscara. También puedo entenderlo, dado que es un proceso externo y no una operación sobre una imagen.

Pero entonces, ¿por qué no hay un proceso "Convolve"? Si hubiera uno, no necesitaríamos esa instancia de PixelMath, ya que el proceso externo Convolve respetaría la máscara.

¿Tiene sentido?
--
 David Serrano

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Masking a script with a dynamically generated PixelMath instance
« Reply #2 on: 2007 September 12 12:09:54 »
Absolutely, it makes sense.

Of course, there will be a Convolution process with a sophisticated kernel filter editor and a thorough collection of predefined filters; it's in the to-do list with high priority.

So, assuming that Convolution is a maskable process defined by an installed module, we wouldn't need this script at all.

But now imagine that you want to apply a different procedure, for example one that is more complex, or involving different processes. Let's say, several convolutions and a wavelet transform, perhaps varying as a function of some statistical properties of the target image. Then if you want to apply such a procedure through a mask, the technique used in this script would save your day.

The script describes a general procedure to mask any transformation that you can store as a temporary image with the same dimensions as the target image.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/