Author Topic: Programmatic way to do an STF AutoStretch?  (Read 3133 times)

Offline rga218

  • Newcomer
  • Posts: 37
Programmatic way to do an STF AutoStretch?
« on: 2014 March 22 09:28:31 »
Hi, is there a straightforward programmatic way to do an STF AutoStretch? At the moment I am manipulating STFs in my scripts by setting the -c0, -c1, and -m command-line arguments to the ScreenTransferFunction process. I've been choosing the appropriate arguments using a bit of trial-and-error, but STF AutoStretch buttons seem to do a much better job. Is there programmatic equivalent to clicking the STF AutoStretch and STF AutoStretch (Boosted) buttons in the Screen Transfer Functions Toolbar?

Thank you,

Bob
Roberto Abraham
Professor of Astronomy & Astrophysics
University of Toronto

Offline Andres.Pozo

  • PTeam Member
  • PixInsight Padawan
  • ****
  • Posts: 927
Re: Programmatic way to do an STF AutoStretch?
« Reply #1 on: 2014 March 22 12:30:09 »
There is a script "AutoStretch.js" distributed with my scripts (.../PixInsight/src/scripts/AdP) that does the same as the autostretch of a few versions ago of PI. It is based on a script of Juan that you can find somewhere in the forum. I think the boosted autostretch can be simulated with different SHADOWS_CLIP  and TARGET_BKG constants.

This script can be included from other scripts. For example AperturePhotometry uses it.

Offline rga218

  • Newcomer
  • Posts: 37
Re: Programmatic way to do an STF AutoStretch?
« Reply #2 on: 2014 March 22 13:13:47 »
Exactly what I need... thanks Andrés!

Bob
Roberto Abraham
Professor of Astronomy & Astrophysics
University of Toronto

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Programmatic way to do an STF AutoStretch?
« Reply #3 on: 2014 March 22 14:06:42 »
The following routine is a JavaScript version of the STF AutoStretch function implemented in the standard ScreenTransferFunction tool:

Code: [Select]
/*
 * Default STF Parameters
 */
// Shadows clipping point in (normalized) MAD units from the median.
#define DEFAULT_AUTOSTRETCH_SCLIP  -2.80
// Target mean background in the [0,1] range.
#define DEFAULT_AUTOSTRETCH_TBGND   0.25
// Apply the same STF to all nominal channels (true), or treat each channel
// separately (false).
#define DEFAULT_AUTOSTRETCH_CLINK   true

/*
 * STF Auto Stretch routine
 */
function STFAutoStretch( view, shadowsClipping, targetBackground, rgbLinked )
{
   if ( shadowsClipping == undefined )
      shadowsClipping = DEFAULT_AUTOSTRETCH_SCLIP;
   if ( targetBackground == undefined )
      targetBackground = DEFAULT_AUTOSTRETCH_TBGND;
   if ( rgbLinked == undefined )
      rgbLinked = DEFAULT_AUTOSTRETCH_CLINK;
   
   var stf = new ScreenTransferFunction;

   var n = view.image.isColor ? 3 : 1;

   var median = view.computeOrFetchProperty( "Median" );

   var mad = view.computeOrFetchProperty( "MAD" );
   mad.mul( 1.4826 ); // coherent with a normal distribution

   if ( rgbLinked )
   {
      /*
       * Try to find how many channels look as channels of an inverted image.
       * We know a channel has been inverted because the main histogram peak is
       * located over the right-hand half of the histogram. Seems simplistic
       * but this is consistent with astronomical images.
       */
      var invertedChannels = 0;
      for ( var c = 0; c < n; ++c )
         if ( median.at( c ) > 0.5 )
            ++invertedChannels;

      if ( invertedChannels < n )
      {
         /*
          * Noninverted image
          */
         var c0 = 0, m = 0;
         for ( var c = 0; c < n; ++c )
         {
            if ( 1 + mad.at( c ) != 1 )
               c0 += median.at( c ) + shadowsClipping * mad.at( c );
            m  += median.at( c );
         }
         c0 = Math.range( c0/n, 0.0, 1.0 );
         m = Math.mtf( targetBackground, m/n - c0 );

         stf.STF = [ // c0, c1, m, r0, r1
                     [c0, 1, m, 0, 1],
                     [c0, 1, m, 0, 1],
                     [c0, 1, m, 0, 1],
                     [0, 1, 0.5, 0, 1] ];
      }
      else
      {
         /*
          * Inverted image
          */
         var c1 = 0, m = 0;
         for ( var c = 0; c < n; ++c )
         {
            m  += median.at( c );
            if ( 1 + mad.at( c ) != 1 )
               c1 += median.at( c ) - shadowsClipping * mad.at( c );
            else
               c1 += 1;
         }
         c1 = Math.range( c1/n, 0.0, 1.0 );
         m = Math.mtf( c1 - m/n, targetBackground );

         stf.STF = [ // c0, c1, m, r0, r1
                     [0, c1, m, 0, 1],
                     [0, c1, m, 0, 1],
                     [0, c1, m, 0, 1],
                     [0, 1, 0.5, 0, 1] ];
      }
   }
   else
   {
      /*
       * Unlinked RGB channnels: Compute automatic stretch functions for
       * individual RGB channels separately.
       */
      var A = [ // c0, c1, m, r0, r1
               [0, 1, 0.5, 0, 1],
               [0, 1, 0.5, 0, 1],
               [0, 1, 0.5, 0, 1],
               [0, 1, 0.5, 0, 1] ];

      for ( var c = 0; c < n; ++c )
      {
         if ( median.at( c ) < 0.5 )
         {
            /*
             * Noninverted channel
             */
            var c0 = (1 + mad.at( c ) != 1) ? Math.range( median.at( c ) + shadowsClipping * mad.at( c ), 0.0, 1.0 ) : 0.0;
            var m  = Math.mtf( targetBackground, median.at( c ) - c0 );
            A[c] = [c0, 1, m, 0, 1];
         }
         else
         {
            /*
             * Inverted channel
             */
            var c1 = (1 + mad.at( c ) != 1) ? Math.range( median.at( c ) - shadowsClipping * mad.at( c ), 0.0, 1.0 ) : 1.0;
            var m  = Math.mtf( c1 - median.at( c ), targetBackground );
            A[c] = [0, c1, m, 0, 1];
         }
      }

      stf.STF = A;
   }

   console.writeln( "<end><cbr/><br/><b>", view.fullId, "</b>:" );
   for ( var c = 0; c < n; ++c )
   {
      console.writeln( "channel #", c );
      console.writeln( format( "c0 = %.6f", stf.STF[c][0] ) );
      console.writeln( format( "m  = %.6f", stf.STF[c][2] ) );
      console.writeln( format( "c1 = %.6f", stf.STF[c][1] ) );
   }

   stf.executeOn( view );

   console.writeln( "<end><cbr/><br/>" );
}

Example of use:

Code: [Select]
STFAutoStretch( ImageWindow.activeWindow.currentView );
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline rga218

  • Newcomer
  • Posts: 37
Re: Programmatic way to do an STF AutoStretch?
« Reply #4 on: 2014 March 22 14:13:02 »
Wonderful! Thanks Juan... very much appreciated.

Bob
« Last Edit: 2014 March 22 14:27:10 by rga218 »
Roberto Abraham
Professor of Astronomy & Astrophysics
University of Toronto