Script: Out of Memory

outdoorboy

Well-known member
Hi,

i am trying to stack 1000 10 second shots without tracking that are calibrated and registered.
This script calculates the common image area of all shots.

JavaScript:
#include <pjsr/ColorSpace.jsh>
#include <pjsr/SampleType.jsh>
#include <pjsr/ResizeMode.jsh>

var folder;
var n = 0;
var dest;


function FileData( image, description, instance )
{
   this.image = image;
   this.description = description;
   this.filePath = instance.filePath;

   var windows;

   if ( instance.format.canStoreICCProfiles )
      this.iccProfile = instance.iccProfile;
   else
      this.iccProfile = undefined;

   if ( instance.format.canStoreKeywords )
      this.keywords = instance.keywords;
   else
      this.keywords = undefined;

   if ( instance.format.canStoreImageProperties && instance.format.supportsViewProperties )
   {
      this.properties = [];
      let properties = instance.imageProperties;
      for ( let i = 0; i < properties.length; ++i )
      {
         let value = instance.readImageProperty( properties[i][0]/*id*/ );
         if ( value != null )
            this.properties.push( { id:properties[i][0], type:properties[i][1], value:value } );
      }
   }
   else
      this.properties = undefined;

   if ( instance.format.canStoreThumbnails )
      this.thumbnail = instance.thumbnail;
   else
      this.thumbnail = undefined;

   this.openImages = () =>
   {
      windows = ImageWindow.open( this.filePath );
      for ( let i = 0; i < windows.length; ++i )
      {
         windows[i].show();
         windows[i].zoomToOptimalFit();
      }
   };

   this.closeImages = () =>
   {
      for ( let i = 0; i < windows.length; ++i )
      {
         windows[i].forceClose();
      }
   };
}

/*
 * Reads an image file.
 *
 * filePath    Path to the input file. The input format will be selected from
 *             the suffix (aka extension) of the file name in this path.
 *
 * inputHints  If defined, a string of input hints suitable for the format of
 *             the input file.
 *
 * floatSample If true, images will be read in a floating point format. If
 *             false, images will be read in unsigned integer format. If
 *             undefined, images will be read in the same format they are
 *             stored in the input file.
 *
 * bitsPerSample  If defined and valid, images will be read with the specified
 *             number of bits per pixel sample. If undefined or equal to zero,
 *             images will be read in the same format they are stored in the
 *             input file.
 *
 * Returns a new FileData object.
 */
function readImageFile( filePath, inputHints, floatSample, bitsPerSample )
{
   if ( inputHints === undefined )
      inputHints = "";

   let suffix = File.extractExtension( filePath ).toLowerCase();
   let format = new FileFormat( suffix, true/*toRead*/, false/*toWrite*/ );
   if ( format.isNull )
      throw new Error( "No installed file format can read \'" + suffix + "\' files." );

   let file = new FileFormatInstance( format );
   if ( file.isNull )
      throw new Error( "Unable to instantiate file format: " + format.name );

   let description = file.open( filePath, inputHints );
   if ( description.length < 1 )
      throw new Error( "Unable to open file: " + filePath );
   if ( description.length > 1 )
      console.warningln( "<end><cbr>** Ignoring additional images in file: " + filePath );

   if ( floatSample === undefined || floatSample <= 0 )
      floatSample = description[0].ieeefpSampleFormat;
   if ( bitsPerSample === undefined || bitsPerSample <= 0 )
      bitsPerSample = description[0].bitsPerSample;
   let image = new Image( 1, 1, 1, ColorSpace_Gray, bitsPerSample, floatSample ? SampleType_Real : SampleType_Integer );
   if ( !file.readImage( image ) )
      throw new Error( "Unable to read image: " + filePath );

   let data = new FileData( image, description[0], file );

   file.close();

   return data;
}

/*
 * Writes an image file.
 *
 * filePath    Path to the output file. The output format will be selected from
 *             the suffix (aka extension) of the file name in this path.
 *
 * fileData    Reference to a valid FileData object.
 *
 * overwrite   If true, an existing file with the specified filePath will be
 *             overwritten. If false or undefined, existing files will be
 *             preserved by creating new files with modified file names.
 *
 * outputHints If defined, a string of output hints suitable for the format of
 *             the newly generated file.
 */
function writeImageFile( filePath, fileData, overwrite, outputHints )
{
   function notSupportedWarning( format, what )
   {
      console.warningln( "<end><cbr>** Warning: The " + format.name +
         " format does not support " + what + ". Existing metadata won't be stored." );
   }

   if ( overwrite === undefined )
      overwrite = false;
   if ( outputHints === undefined )
      outputHints = "";

   console.writeln( "<end><cbr><br>Output file:" );

   if ( File.exists( filePath ) )
   {
      if ( overwrite )
      {
         console.warningln( "<end><cbr>** Warning: Overwriting existing file: <raw>" + filePath + "</raw>" );
      }
      else
      {
         console.noteln( "<end><cbr>* File already exists: <raw>" + filePath + "</raw>" );
         for ( let u = 1; ; ++u )
         {
            let tryFilePath = File.appendToName( filePath, '_' + u.toString() );
            if ( !File.exists( tryFilePath ) )
            {
               filePath = tryFilePath;
               break;
            }
         }
         console.noteln( "<end><cbr>* Writing to: <raw>" + filePath + "</raw>" );
      }
   }
   else
   {
      console.writeln( "<raw>" + filePath + "</raw>" );
   }

   let suffix = File.extractExtension( filePath ).toLowerCase();
   let format = new FileFormat( suffix, false/*toRead*/, true/*toWrite*/ );
   if ( format.isNull )
      throw new Error( "No installed file format can write \'" + suffix + "\' files." );

   let f = new FileFormatInstance( format );
   if ( f.isNull )
      throw new Error( "Unable to instantiate file format: " + format.name );

   if ( !f.create( filePath, outputHints ) )
      throw new Error( "Error creating output file: " + filePath );

   let d = new ImageDescription( fileData.description );
   d.bitsPerSample = fileData.image.bitsPerSample;
   d.ieeefpSampleFormat = fileData.image.isReal;
   if ( !f.setOptions( d ) )
      throw new Error( "Unable to set output file options: " + filePath );

   if ( fileData.iccProfile != undefined )
      if ( format.canStoreICCProfiles )
         f.iccProfile = fileData.iccProfile;
      else
         notSupportedWarning( format, "ICC profiles" );

   if ( fileData.keywords != undefined )
      if ( format.canStoreKeywords )
         f.keywords = fileData.keywords;
      else
         notSupportedWarning( format, "FITS keywords" );

   if ( fileData.thumbnail != undefined )
      if ( format.canStoreThumbnails )
         f.thumbnail = fileData.thumbnail;
      else
         notSupportedWarning( format, "thumbnail images" );

   if ( fileData.properties != undefined )
      if ( format.canStoreImageProperties && format.supportsViewProperties )
         for ( let i = 0; i < fileData.properties.length; ++i )
            f.writeImageProperty( fileData.properties[i].id,
                                  fileData.properties[i].value,
                                  fileData.properties[i].type );
      else
         notSupportedWarning( format, "image properties" );

   if ( !f.writeImage( fileData.image ) )
      throw new Error( "Error writing output file: " + filePath );

   f.close();
}

 /*
 * FileList
 *
 * Recursively search a directory tree for all existing files with the
 * specified file extensions.
 *
 * https://gitlab.com/roberto.sartori/batch-linearfit-rgb/-/blob/main/BatchLinearFit_RGB.js
 */
function FileList( dirPath, extensions, verbose )
{
   /*
    * Regenerate this file list for the specified base directory and file
    * extensions.
    */
   this.regenerate = function( dirPath, extensions, verbose )
   {
      // Security check: Do not allow climbing up a directory tree.
      if ( dirPath.indexOf( ".." ) >= 0 )
         throw new Error( "FileList: Attempt to redirect outside the base directory: " + dirPath );

      // The base directory is the root of our search tree.
      this.baseDirectory = File.fullPath( dirPath );
      if ( this.baseDirectory.length == 0 )
         throw new Error( "FileList: No base directory has been specified." );

      // The specified directory can optionally end with a separator.
      if ( this.baseDirectory[ this.baseDirectory.length - 1 ] == '/' )
         this.baseDirectory.slice( this.baseDirectory.length - 1, -1 );

      // Security check: Do not try to search on a nonexisting directory.
      if ( !File.directoryExists( this.baseDirectory ) )
         throw new Error( "FileList: Attempt to search a nonexistent directory: " + this.baseDirectory );

      // If no extensions have been specified we'll look for all existing files.
      if ( extensions == undefined || extensions == null || extensions.length == 0 )
         extensions = [ '' ];

      if ( verbose )
      {
         console.writeln( "<end><cbr><br>==> Finding files from base directory:" );
         console.writeln( this.baseDirectory );
      }

      // Find all files with the required extensions in our base tree recursively.
      this.files = [];
      for ( let i = 0; i < extensions.length; ++i )
         this.files = this.files.concat( searchDirectory( this.baseDirectory + "/*" + extensions[ i ], true /*recursive*/ ) );

   };

   this.baseDirectory = "";
   this.files = [];
   this.index = [];

   if ( dirPath != undefined )
      this.regenerate( dirPath, extensions, verbose );

   if ( verbose )
   {
      console.writeln( "<end><cbr>" + this.files.length + " file(s) found:" );
      for ( let i = 0; i < this.files.length; ++i )
         console.writeln( this.files[ i ] );
   }
}

FileList.prototype = new Object;

function getFiles()
{
   let gdd = new GetDirectoryDialog;
   let files = [];

   gdd.caption = "Select your directory";
   if ( gdd.execute() )
   {
      let rootDir = gdd.directory;
      folder = rootDir;

      // get the list of compatible file extensions
      let openFileSupport = new OpenFileDialog;
      openFileSupport.loadImageFilters();
      let filters = openFileSupport.filters[ 0 ]; // all known format
      filters.shift();
      filters = filters.concat( filters.map( f => ( f.toUpperCase() ) ) );

      // perform the search
      let filesFound = 0;
      let addedFiles = 0;
      let L = new FileList( rootDir, filters, false /*verbose*/ );
      L.files.forEach( filePath =>
      {
         filesFound++;
         files.push( filePath );
      } );
   }

   return files;
}

function ofd ()
{
   var ofd = new OpenFileDialog;
   ofd.initialPath = "C:/";
   ofd.caption = "Select reference image path";
   ofd.filters = [
      [ "All supported formats", ".xisf", ".fit", ".fits", ".fts" ],
      [ "FITS Files", ".fit", ".fits", ".fts" ],
      [ "XISF Files",  ".xisf"]
   ];
   if (ofd.execute())
   {
      return ofd.fileName;
   }
   else
   {
      return "";
   }
}

function intersect(source, dest)
{
   var P = new PixelMath;
   P.expression = "iif(" + source.id + ">0," + dest.currentView.id + "," + source.id + ")";
   P.expression1 = "";
   P.expression2 = "";
   P.expression3 = "";
   P.useSingleExpression = true;
   P.symbols = "";
   P.clearImageCacheAndExit = false;
   P.cacheGeneratedImages = false;
   P.generateOutput = true;
   P.singleThreaded = false;
   P.optimization = true;
   P.use64BitWorkingImage = false;
   P.rescale = false;
   P.rescaleLower = 0;
   P.rescaleUpper = 1;
   P.truncate = true;
   P.truncateLower = 0;
   P.truncateUpper = 1;
   P.createNewImage = false;
   P.showNewImage = true;
   P.newImageId = "";
   P.newImageWidth = 0;
   P.newImageHeight = 0;
   P.newImageAlpha = false;
   P.newImageColorSpace = PixelMath.prototype.SameAsTarget;
   P.newImageSampleFormat = PixelMath.prototype.SameAsTarget;

   P.executeOn(dest.currentView);
}

function stf(view)
{
   var P = new ScreenTransferFunction;
   P.STF = [ // c0, c1, m, r0, r1
      [0.00000, 1.00000, 0.00010, 0.00000, 1.00000],
      [0.00000, 1.00000, 0.00010, 0.00000, 1.00000],
      [0.00000, 1.00000, 0.00010, 0.00000, 1.00000],
      [0.00000, 1.00000, 0.50000, 0.00000, 1.00000]
   ];
   P.interaction = ScreenTransferFunction.prototype.SeparateChannels;

   P.executeOn(view.currentView);
}

function myFunction(value)
{
   var source;
   let data = readImageFile( value );

   var windows = ImageWindow.open( data.filePath );

   // Get access to the current active image window.
   var source = windows[0].mainView;
   Console.writeln("id: " + source.id);

   if ( source.isNull )
      throw new Error( "No active image" );
   else
   {
      intersect(source, dest);
   }

   windows[0].forceClose();

   n += 1;

   Console.writeln("\n" + n + " Dateien verarbeitet.\n");
}

function main()
{
   Console.show();

   let files = getFiles();

   if (Parameters.isViewTarget)
   {
      Console.writeln("executing in view target context");
      Console.writeln("target: ", Parameters.targetView.id);
   }
   else if (Parameters.isGlobalTarget)
   {
      Console.writeln("executing in global context");
   }
   else
   {
      Console.writeln("executing in direct context");

      // Get access to the current active image window.
      dest = ImageWindow.activeWindow;
      if ( dest.isNull )
      {
         let data = readImageFile( files[0] );

         dest = ImageWindow.open( data.filePath );

         for ( let i = 0; i < dest.length; ++i )
         {
            dest[i].mainView.id = "dest";
            dest[i].show();
            dest[i].zoomToOptimalFit();
         }

         dest = ImageWindow.activeWindow;
         stf(dest);

         //throw new Error( "No image WHITE" );
      }

      files.forEach(myFunction);

      Console.writeln(n + " Dateien verarbeitet.");
   }
}

main();

However I get an "out of memory". In the task manager you can see that the memory is added up
with each image, but it is not released.

When I quit PixInsigt the memory is released.

Where is the error?

CS, Franz
 
Back
Top