Author Topic: Implementación preliminar de auto-star-profile-transform.js  (Read 70668 times)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Implementación preliminar de auto-star-profile-transform.js
« Reply #15 on: 2007 September 14 01:59:17 »
Sólo una breve puntualización:

Code: [Select]
float medianOrig = img.Median();
float medianTemp;
float medianFinal; // definido por el usuario

float convergencia = 1e-6;
int iters; //definida por el usuario
// ...more code omitted


Pero eso mismo exactamente lo hace la rutina FindMidtonesBalance que publiqué aquí anoche, y además no es necesario imponer un número máximo de iteraciones, porque la rutina itera hasta que se satisface un error máximo de convergencia. En esta rutina:

FindMidtonesBalance( v0, v1, eps )

v0 es el valor inicial (que sería medianOrig en tu código), v1 es el valor que querríamos obtener (medianFinal) al aplicarle un balance de medios tonos determinado, y eps es el error máximo que queremos cometer (1e-5 es más que suficiente en la mayoría de los casos). La función nos devuelve el valor de medios tonos que tendría que ser aplicado con MTF para que v0 se transformara en v1. Es lo mismo que tu AutoHistogram, pero con MTF en vez de una función gamma. FindMidtonesBalance() converge cuadráticamente, con lo cual el número de iteraciones es despreciable.

Sigo con el duro trabajo: la implementación de Settings y RGBColorSystem en el runtime de JS...
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Implementación preliminar de auto-star-profile-transform.js
« Reply #16 on: 2007 September 14 05:55:38 »
Quote from: "Juan Conejero"
y además no es necesario imponer un número máximo de iteraciones, porque la rutina itera hasta que se satisface un error máximo de convergencia.


Pero este hilo existe precisamente porque es mejor ajustar el histograma varias veces con una máscara distinta cada vez. Si no me equivoco, tu función calcula el valor necesario para alcanzar un valor de mediana deseado con una sola pasada de MTF. Sin embargo, una de mis premisas básicas de diseño es que el usuario debe elegir el número de pasadas. Y claro, cuantas más pasadas, más cercano a 0.5 tiene que ser el valor de MTF a usar en cada una de ellas.

En mi código, que ya tengo listo, he cogido un poco del pseudocódigo de Carlos y un poco de tu función. Aquí va:

Code: [Select]
/*
    masked-stretch-transform.js v0.2 (formerly auto-star-profile-transform.js)
    Iteratively stretch histogram with an appropriate luminance mask each time.
    Copyright (C) 2007  David Serrano

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
    Special thanks go to Carlos Sonnenstein and Carlos Milovic for
    their (in)valuable contributions.

    Changelog:
    0.2:   Some code reorganization.
           Now deduces the MTF value from given values: iterations and target median.
    0.1.1: Bug fix: masked was not being inverted.
    0.1:   Initial version.
*/

// TODO: make sure get_median does the right thing (obtain luma, then get its median).
// TODO: devise a way for not generating swapfiles for the histogram loop. It's sooo slooow...

#include <pjsr/ColorSpace.jsh>
#include <pjsr/SampleType.jsh>
#include <pjsr/UndoFlag.jsh>
#include <pjsr/MTF.jsh>

#feature-id AutoStarProfileTransform
#feature-info At the time of stretching the histogram of an image, \
    it's better to do it several times changing the mask used every \
    time - a long, boring task that is perfect for script automation. \
    This script does precisely that.
//#feature-icon masked-stretch-transform.xpm

#define VERSION "0.2"
#define E 1e-5

function get_luma (view) {
    view.image.extractLuminance (luma = new Image);
    return luma;
}

{
    var stats = new ImageStatistics;  // closure
    function get_median (view) {
        var l = get_luma (view);
        stats.generate (l);
        return stats.median;
    }
}

// from orig median "om" to target median "tm" in "it" iters
function calc_mtf (om, tm, it) {
    var tmp;
    var dark = 0;
    // this is 1 instead of 0.5 because we should't assume that the
    // user is always going to lighten the image (ie keep the mtf
    // value < 0.5). Users are always cleverer and we shouldn't take
    // decisions on their behalf. As the saying goes, "If something
    // prevents you from doing stupid things, it also prevents you
    // from doing clever things".
    var light = 1;
    // this initial value could depend on the number of iterations.
    //
    // Since in the majority of cases the user will want to lighten
    // the image, it's better to set this value a bit higher, so the
    // loop following will end up with a image too light, and then
    // the first variable to be adjusted will be "light", not "dark".
    // Therefore, in the majority of cases, the second pass of the
    // loop will search in [0, 0.35] instead of [0.35, 1].
    var mtf = 0.35;

    while (1) {
        tmp = om;
        for (var i = 0; i < it; i++)
            tmp = MidtonesTransferFunction (mtf, tmp) * (1-tmp) + tmp*tmp;

        if (Math.abs (tmp - tm) < E)
            return mtf;

        if (tmp > tm) {     // where's Perl...
            dark = mtf;
        } else {
            light = mtf;
        }
        mtf = (dark + light) / 2;
    }
}

//these will be specified by the user
var iter = 3;
var target_median = 0.04;

var aw = ImageWindow.activeWindow;

if (aw.isNull)
    throw Error ("No active image window.");

var v = ImageWindow.activeWindow.mainView;

var mtf = calc_mtf (get_median (v), target_median, iter);
console.writeln (format ("Using MTF of %6.04f", mtf));
var hist = new HistogramTransform;
hist.H = [
    // shadows, midtones, highlights, ext_shadows, ext_hilights
    [0, 0.5, 1, 0, 1], // R
    [0, 0.5, 1, 0, 1], // G
    [0, 0.5, 1, 0, 1], // B
    [0, mtf, 1, 0, 1], // RGB
    [0, 0.5, 1, 0, 1], // Alpha
];

// window that will hold the luminance for masking
var luma_w = new ImageWindow (1, 1, 1, v.image.bitsPerSample, false, false, "MST_luma");

for (var i = 0; i < iter; i++) {
    var luma = get_luma (v);

    // transfer image to window and apply the window as mask
    with (luma_w.mainView) {
        // Inform the core application that we are going to modify this view's image
        beginProcess (UndoFlag_NoSwapFile);
        // ### Note that after this transfer, luma is no longer a reference to a valid Image object
        image.transfer (luma);
        endProcess();
    }
    //luma_w.show();
    aw.maskVisible = false;
    aw.maskInverted = true;
    aw.mask = luma_w;

    // stretch
    hist.executeOn (v);

    // clean up
    luma_w.removeMaskReferences();  // automatically removes mask from aw
    gc();
}

luma_w.close();
// no need to set luma to null, since .transfer removed the reference to the Image object
luma_w = null;
gc();


 - El programa necesita un archivo MTF.jsh en el directorio donde están todos los *.jsh (include/pjsr). Ese archivo es el trozo de código Javascript que Juan puso un par de mensajes más arriba. Felicidades Juan, tu traducción al vuelo funciona a la primera :).

 - Los parámetros configurables no están tan visibles como antes, están en las líneas 101 y 102. Ya va haciendo falta un interface porque esto difícilmente va a cambiar.

 - Tal como dice uno de los TODO's, el programa crea un archivo de swap en cada pasada de HistogramTransform, lo cual nos echa el rendimiento abajo. He probado, a ciegas, a poner esto de "beginProcess (UndoFlag_NoSwapFile)" y "endProcess" alrededor de la llamada a "hist.executeOn (v)" pero me salió un error tal que la imagen ya estaba siendo procesada o algo así. Esta es la salida de la consola, donde se ve lo del swap:

Code: [Select]
HistogramTransform: Processing view: Image01
Writing swap file...
Processing channel #0: LUT-based histogram transform: 100%
Processing channel #1: LUT-based histogram transform: 100%
Processing channel #2: LUT-based histogram transform: 100%
0.597 s
MST_luma: Masking from swap file...
Calculating view statistics...


Lo de statistics también molaba quitarlo.

 - Y tal como muestra el otro TODO, no sé si estoy haciendo bien el cálculo de la mediana original. Al principio lo hacía a pelo, es decir, "stats.generate (image); stats.median;". Sin embargo me fijé que el valor obtenido me coincidía con el valor que el proceso Statistics me daba para el canal rojo. Y entonces decidí, para calcular la mediana, hacer primero una luminancia y luego sacar su mediana. Esto se ve en la función get_median(), línea 55.

El resultado es aparentemente satisfactorio, pero nuevamente me encuentro con el problema de comprobar si la mediana de la imagen resultante es la que yo quería... si hago dos procesos PixelMath sobre la imagen ya estirada, uno con "Lum($target)" y otro con "Med($target)", obtengo una imagen gris (lógicamente) en la que el valor de todos los píxels (0.0428) tiene mucho que ver con la mediana deseada (0.0400) (error del 7%) pero no sé si esto es coincidencia o no! :D. Si pido otros parámetros (4 iteraciones y mediana objetivo 0.09) y realizo estos dos PixelMath, me queda una imagen gris cuyos pixels valen 0.126; el error ya alcanza el 33%...

Bueno, sea como sea, a ver qué tal os va esta versión. No olvidéis crear el MTF.jsh! ;)
--
 David Serrano

Offline Jordi Gallego

  • PixInsight Addict
  • ***
  • Posts: 279
Implementación preliminar de auto-star-profile-transform.js
« Reply #17 on: 2007 September 15 07:38:09 »
Gracias David (y compañia), voy a intentar probarlo esta tarde :wink:

Saludos
Jordi
Jordi Gallego
www.astrophoto.es

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Implementación preliminar de auto-star-profile-transform.js
« Reply #18 on: 2007 September 15 07:48:48 »
Quote from: "Jordi Gallego"
Gracias David (y compañia), voy a intentar probarlo esta tarde :wink:


Perfecto :). Si todo me sale bien, esta tarde pongo la 0.3, que ya tendrá un diálogo para ponerle los valores y no necesitará el MTF.jsh (aunque a cambio sí necesitará la última versión de PixInsight).
--
 David Serrano

Offline Jordi Gallego

  • PixInsight Addict
  • ***
  • Posts: 279
Implementación preliminar de auto-star-profile-transform.js
« Reply #19 on: 2007 September 15 08:14:16 »
David: funciona :D  :D !

Lo he probado con una imagen que había "estirado" con 16 pasadas y no se ver diferencia entre las dos!

Una pregunta: como se relaciona el segundo parámetro ajustable por el usuario "target_median" con el valor de medios tonos aplicado en cada iteración?: he visto por ejemplo que cuando lo pongo a 0.10, el ajuste de histograma que aplica es 0.45662 :?

Saludos especialmente felices de mi tendinitis del brazo derecho :D  :D

Jordi
Jordi Gallego
www.astrophoto.es

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Implementación preliminar de auto-star-profile-transform.js
« Reply #20 on: 2007 September 15 08:34:45 »
Quote from: "Jordi Gallego"
Una pregunta: como se relaciona el segundo parámetro ajustable por el usuario "target_median" con el valor de medios tonos aplicado en cada iteración?


No tiene ninguna relación obvia (sí que hay relación, claro está, pero no salta a la vista). target_median es la mediana que quieres que tenga la imagen resultante. Cuanto más bajo sea el valor, más oscura quedará la imagen, y por tanto cada iteración tendrá un valor de MTF menos agresivo (más cercano a 0.5). Pero el valor de MTF no sólo depende de esto, sino también del número de iteraciones. A más iteraciones, también menos agresiva será cada una de ellas. ¿Me explico?

Saluda, o mejor dicho despide ;), a tu tendinitis!
--
 David Serrano

Offline Jordi Gallego

  • PixInsight Addict
  • ***
  • Posts: 279
Implementación preliminar de auto-star-profile-transform.js
« Reply #21 on: 2007 September 15 10:32:08 »
Gracias David, queda claro :wink:

Saludos
Jordi

Voy a colgar en la galería una imagen estirada "iterativamente"
Jordi Gallego
www.astrophoto.es

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Implementación preliminar de auto-star-profile-transform.js
« Reply #22 on: 2007 September 15 10:59:44 »
Versión 0.3, ya con interface de usuario :). Jordi, no hace falta que reproceses la toma que acabas de colgar, dado que el algoritmo por dentro no ha cambiado.

[Edito: esta es la 0.8]

Code: [Select]
/*
    masked-stretch-transform.js v0.8
    Iteratively stretch histogram with an appropriate luminance mask each time.
    Copyright (C) 2007  David Serrano

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
    Special thanks go to (in chronological order):
    - Carlos Sonnenstein, Carlos Milovic and Juan Conejero for their invaluable
      contributions (ideas, knowledge, code and probably more).
    - My english teacher for telling me that a contribution can't be valuable ;)
      (refer to v0.4 if you don't get this).

    Changelog:
    0.8:   Now supports mask blurring with a convolution.
           User interface reorganization.
           Changed default parameters.
    0.7.1: Corrected an scoping bug spotted by Iñaki Lizaso.
    0.7:   Now masks can be blurred by removing ÀTrousWavelet dyadic layers.
           Bug fix: mask shadows clipping wasn't working at all.
           Better settings management, following the aberration-spotter scheme.
           Removed settings compatibility with v0.4.
    0.6.1: Got rid of the confirmation dialog when closing a temporary image.
    0.6:   User can now specify the amount of shadows that will be clipped in
           each mask.
    0.5.1: Adapted Settings.lastReadOK calls to latest PixInsight (build 329).
    0.5:   Code for calculating mtf completely rewritten (again). Now, instead
           of using a binary search like in 0.4, it does linear interpolations.
           New option to delete the settings saved by the script.
           Sets up an RGB working space that gives all three color components
           the same importance when calculating the luminance.
    0.4.1: Better Settings handling. Still reads v0.4 settings.
    0.4:   Code for calculating mtf completely rewritten. Now works over a
           small copy of the image, with real HT's and real masks.
           Increased maximum number of iters to 200. Users always want more ;).
           More code reorganization. Now I even like it :).
    0.3.1: Fixed a couple of issues with settings. Should work as expected now.
    0.3:   Now the code is more OO. Hope it's well structured.
           Uses the new Math.mtf() built-in function. Checks if iter == 0.
           Initial user interface (mostly copy & paste).
    0.2:   Some code reorganization.
           Now deduces MTF from given values: iterations and target median.
    0.1.1: Bug fix: masked was not being inverted.
    0.1:   Initial version.
*/

// TODO: restore the image's original RGBWS.
// TODO: couldn't manage to disable some GUI elements depending on which
//       RadioButton is pressed.

#define VERSION "0.8"
#define E 1e-4            // epsilon
#define SET_PREFIX "MST"
#define BLUR_METHOD_NONE 0
#define BLUR_METHOD_ATW  1
#define BLUR_METHOD_CONV 2

#include <pjsr/ColorSpace.jsh>
#include <pjsr/DataType.jsh>
#include <pjsr/FrameStyle.jsh>
#include <pjsr/Interpolation.jsh>
#include <pjsr/NumericControl.jsh>
#include <pjsr/ResizeMode.jsh>
#include <pjsr/SampleType.jsh>
#include <pjsr/Sizer.jsh>
#include <pjsr/UndoFlag.jsh>

#feature-id MaskedStretchTransform
#feature-info At the time of stretching the histogram of an image, \
    it's better to do it several times changing the mask used every \
    time - a long, boring task that is perfect for script automation. \
    This script does precisely that.
//#feature-icon masked-stretch-transform.xpm

function err_dialog() {   // bad name, I know
    this.__base__ = Dialog;
    this.__base__();

    this.l = new Label (this);
    with (this.l) {
        margin = 15;
        wordWrapping = true;
        minWidth = 500;
        text = "Unable to calculate MTF value, probably because the " +
            "median desired is too far from the current one. Increase " +
            "the number of iterations.";
    }

    this.b = new PushButton (this);
    this.b.text = " OK ";
    this.b.onClick = function() { this.dialog.ok(); };

    this.hsizer = new HorizontalSizer;
    with (this.hsizer) {
        margin = 6;
        spacing = 6;
        addStretch();
        add (this.b);
        addStretch();
    }

    this.sizer = new VerticalSizer;
    with (this.sizer) {
        margin = 6;
        spacing = 6;
        add (this.l);
        addSpacing (4);
        add (this.hsizer);
    }

    this.windowTitle = "Error";
    this.adjustToContents();
}
err_dialog.prototype = new Dialog;
var err_dialog = new err_dialog;

function mst_user_data() {
    this.iter = 15;
    this.target_median = 0.08;
    this.shadows_clipping = 0;   // mask shadows clipping
    this.blur_method = BLUR_METHOD_NONE;
    this.atw_layers = 2;         // numberOfLayers to remove to masks
    this.atw_scaling = 0;        // scaling function
    this.conv_pixels = 7;
    this.delete_settings = false;
}
var user_data = new mst_user_data;

function mst_engine() {
    var stats = new ImageStatistics;
    var win;    // image window we'll modify
    var hist = new HistogramTransform;
    var shadows_clipping = new HistogramTransform;
    var mtf;

    this.atw_scaling_function = function (name, kernel) {
        this.name = name;
        this.kernel = kernel;
    }

    this.atw_scaling_functions = new Array (
        new this.atw_scaling_function ("3x3 Linear Interpolation", [
            1/16, 1/8, 1/16,
            1/8,  1/4, 1/8,
            1/16, 1/8, 1/16
        ]),
        new this.atw_scaling_function ("3x3 Gaussian", [
            1/25, 1/5, 1/25,
            1/5,  1,   1/5,
            1/24, 1/5, 1/25
        ]),
        new this.atw_scaling_function ("5x5 B3 Spline", [
            1/256, 1/64, 3/128, 1/64, 1/256,
            1/64,  1/16, 3/32,  1/16, 1/64,
            3/128, 3/32, 9/64,  3/32, 3/128,
            1/64,  1/16, 3/32,  1/16, 1/64,
            1/256, 1/64, 3/128, 1/64, 1/256
        ]),
        new this.atw_scaling_function ("5x5 Gaussian", [
            0.00723,0.0459, 0.085,  0.0459, 0.00723,
            0.0459, 0.29155,0.53995,0.29155,0.0459,
            0.085,  0.53995,1,      0.53995,0.085,
            0.0459, 0.29155,0.53995,0.29155,0.0459,
            0.00723,0.0459, 0.085,  0.0459, 0.00723
        ])
    );

    // Contributed by Juan Conejero. Will be removed when the same functionality
    // makes its way to the PCL.
    this.gaussian_filter = function (size, shape) {
        const epsilon = 0.01;        // maximum truncation error
        size = Math.max (3, size|1); // ensure odd dimension >= 3

        // The filter array
        var h = new Array;

        // Standard deviation of the filter distribution
        var sigma = (size >> 1) / Math.pow (-shape * Math.ln (epsilon), 1/shape);
        var rk = shape * Math.pow (sigma, shape);

        // Optimized code
        for (var i = 0, n2 = size >> 1, y = -n2; y <= n2; ++y) {
            if (y > 0) {
                for (var x = 0, yy = y+y; x < size; ++x, ++i) {
                    h[i] = h[i - yy*size];
                }
            } else {
                for (var x = -n2; x <= n2; ++x, ++i) {
                    h[i] = (x > 0) ?
                        h[i - (x+x)] :
                        Math.exp (-Math.pow (Math.sqrt (x*x + y*y), shape) / rk);
                }
            }
        }
        return h;
    }

    this.set_win = function (w) {
        if (w.isNull)
            throw Error ("Invalid/No image window.");

        this.win = w;
    }

    this.get_luma = function (view) {
        view.image.statusEnabled = true;
        view.image.extractLuminance (luma = new Image);
        return luma;
    }

    // obtains luma, then its median.
    this.get_median = function (view) {
        var l = this.get_luma (view);
        l.statusEnabled = true;
        stats.generate (l);
        return stats.median;
    };

    this.modify_mask = function (view) {
        // let's clip the shadows a bit
        if (user_data.shadows_clipping) {
            shadows_clipping.executeOn (view);
        }

        // do atw
        if (user_data.blur_method == BLUR_METHOD_ATW) {
            var atw = view.image.ATW (
                this.atw_scaling_functions[user_data.atw_scaling].kernel,
                user_data.atw_layers
            );
            with (view) {
                beginProcess (UndoFlag_PixelData);
                image.transfer (atw[user_data.atw_layers]);  // residual layer
                endProcess();
            }
        }

        // convolution
        if (user_data.blur_method == BLUR_METHOD_CONV) {
            with (view) {
                beginProcess (UndoFlag_PixelData);
                if (user_data.conv_pixels <= 15) {
                    image.convolve (
                        this.gaussian_filter (user_data.conv_pixels, 2)
                    );
                } else {
                    image.convolveFFT (
                        this.gaussian_filter (user_data.conv_pixels, 2)
                    );
                }
                endProcess();
            }
        }
    }

    this.stretch = function (win) {
        var v = win.mainView;

        hist.H = [
            // shadows, midtones, highlights, ext_shadows, ext_hilights
            [0, 0.5,      1, 0, 1], // R
            [0, 0.5,      1, 0, 1], // G
            [0, 0.5,      1, 0, 1], // B
            [0, this.mtf, 1, 0, 1], // RGB
            [0, 0.5,      1, 0, 1], // Alpha
        ];

        // window that will hold the luminance for masking
        var luma_w = new ImageWindow (
            500, 500, 1, v.image.bitsPerSample,
            v.image.sampleType == SampleType_Real,
            false, "MST_luma"
        );

        for (var i = 0; i < user_data.iter; i++) {
            var luma = this.get_luma (v);

            // transfer image to window, modify and apply as mask
            with (luma_w.mainView) {
                beginProcess (UndoFlag_NoSwapFile);
                image.transfer (luma);  // luma is no longer an Image after this
                endProcess();
            }

            this.modify_mask (luma_w.mainView);

            //luma_w.show();
            win.maskVisible = false;
            win.maskInverted = true;
            win.mask = luma_w;

            // stretch
            hist.executeOn (win.mainView);

            // clean up
            luma_w.removeMaskReferences();  // automatically removes mask from win
            gc();
        }

        luma_w.undoAll();
        luma_w.purge();
        luma_w.close();
        luma_w = null;
        gc();
    }

    this._do_calc_mtf = function (w) {
        var om = this.get_median (w.mainView);  // original median
        var tm = user_data.target_median;
        var it = user_data.iter;

        // if users don't try this, Murphy will do
        if (Math.abs (om - tm) < E) {
            this.mtf = 0.5;
            return;
        }

        // we'll call stretch, which modifies our precious image. Let's
        // save it for restoring when needed, so stretch begins from the
        // same image every time
        var backup_img = new ImageWindow (
            1, 1, 1,
            w.mainView.image.bitsPerSample,
            w.mainView.image.sampleType == SampleType_Real,
            w.mainView.image.colorSpace != ColorSpace_Gray,
            "backup_img"
        );
        with (backup_img.mainView) {
            beginProcess (UndoFlag_NoSwapFile);
            image.assign (w.mainView.image);
            endProcess();
        }
        //backup_img.show();

        var mtf1; var median1;
        var mtf2; var median2;
        var temp_median;

        if (om < tm) {    // going to lighten the image
            mtf1 = 0.20;
            this.mtf = mtf1; this.stretch (w);
            median1 = this.get_median (w.mainView);
            // did we have a lucky strike?
            if (Math.abs (median1 - tm) < E)
                return;  // this.mtf is already set
            if (tm > median1) {
                // user wants a big stretch, we won't handle it
                this.mtf = -1;
            }

            mtf2 = 0.50; median2 = om;
        } else {
            mtf1 = 0.50; median1 = om;

            mtf2 = 0.70;
            this.mtf = mtf2; this.stretch (w);
            median2 = this.get_median (w.mainView);
            // did we have a lucky strike?
            if (Math.abs (median2 - tm) < E)
                return;  // this.mtf is already set
            if (tm < median2) {
                // user wants a big stretch, we won't handle it
                this.mtf = -1;
            }
        }

        // we're not setting this.mtf to -1 in the following loop, but it
        // can have this value from the previous checks made. So this is
        // actually "if (-1 != this.mtf) { while (1) {  blah blah; } }"
        // with just one level of indentation
        while (-1 != this.mtf) {
            // refresh the image to work on it again
            with (w.mainView) {
                beginProcess (UndoFlag_NoSwapFile);
                image.assign (backup_img.mainView.image);
                endProcess();
            }

            // heart of the algorithm
            this.mtf = (1 * (tm-median2) / (median1-median2)) * (mtf1-mtf2) + mtf2;
            this.stretch (w);
            temp_median = this.get_median (w.mainView);

            if (Math.abs (temp_median - tm) < E)
                break;  // this.mtf is already set

            // USERS KEEP ON DEMANDING PERL!! ;)
            // (($temp_median > $tm) ? ($mtf1, $median1) : ($mtf2, $median2)) =
            //     ($this_mtf, $temp_median);
            if (temp_median > tm) {     // image too light
                mtf1 = this.mtf;
                median1 = temp_median;
            } else {
                mtf2 = this.mtf;
                median2 = temp_median;
            }
        }

        backup_img.close();
        backup_img = null;
        gc();
    }

    this.calc_mtf = function() {
        v = this.win.mainView;
        var thumb_h = 300;

        // apply a better RGB working space
        var rgbws = new RGBWorkingSpace;
        with (rgbws) {
            channels = [  // Y, x, y
                [1.000000, 0.648431, 0.330856],
                [1.000000, 0.321152, 0.597871],
                [1.000000, 0.155886, 0.066044]
            ];
            gamma = 2.20;
            sRGBGamma = true;
            applyGlobalRGBWS = false;
            executeOn (v);   // TODO: how to revert this?
        }

        // build HT object for the mask shadows clipping
        shadows_clipping.H = [
            // shadows, midtones, highlights, ext_shadows, ext_hilights
            [0,                          0.5, 1, 0, 1], // R
            [0,                          0.5, 1, 0, 1], // G
            [0,                          0.5, 1, 0, 1], // B
            [user_data.shadows_clipping, 0.5, 1, 0, 1], // RGB
            [0,                          0.5, 1, 0, 1], // Alpha
        ];

        // duplicate and resample image
        var thumbnail = new ImageWindow (
            thumb_h, 1, 1,   // isn't "1, 1" in order to see the progress
            v.image.bitsPerSample,
            v.image.sampleType == SampleType_Real,
            v.image.colorSpace != ColorSpace_Gray,
            "MST_thumbnail"
        );
        with (thumbnail.mainView) {
            beginProcess (UndoFlag_NoSwapFile);
            image.assign (v.image);
            image.resample (
                thumb_h, 42,
                Interpolation_BicubicBSpline,
                ResizeMode_AbsolutePixels,
                AbsoluteResizeMode_ForceWidth
            );
            endProcess();
        }
        thumbnail.show();
        thumbnail.fitWindow();

        this._do_calc_mtf (thumbnail);

        thumbnail.undoAll();
        thumbnail.purge();
        thumbnail.close();
        thumbnail = null;
        gc();

        if (-1 == this.mtf) {
            err_dialog.execute();
            return false;
        }

        return true;
    }

    this.work = function() {
        this.stretch (this.win);
    }
}
var engine = new mst_engine;

function mst_dialog() {
    this.__base__ = Dialog;
    this.__base__();

    this.label_width = this.font.width ("Wavelets scaling function:");

    // help label
    this.helpLabel = new Label (this);
    with (this.helpLabel) {
        frameStyle = FrameStyle_Box;
        margin = 4;
        wordWrapping = true;
        useRichText = true;
        text = "<b>MaskedStretchTransform v"+VERSION+"</b> - A " +
            "script to perform a histogram stretch of an image via several " +
            "small luminance-masked HistogramTransform's. This is good for " +
            "preventing small stars from growing without control.<br><br>" +
            "Choose the number of iterations and the median of the desired " +
            "image (typically in the range 0.05 - 0.10). Then click 'Ok' " +
            "and wait for a new image to be created. A smaller copy of the "+
            "image will show the progress of the script.<br><br>" +
            "You can specify an optional number of ÁTrousWavelet layers to " +
            "be removed from the mask in order to blur it. Alternatively, " +
            "it can be blurred using a convolution too.<br><br>" +
            "This program can't do aggresive changes with few iterations. " +
            "A message will appear if you try to do so.";
    }

    // iterations
    this.iter_NC = new NumericControl (this);
    with (this.iter_NC) {
        label.text = "Iterations:";
        label.minWidth = this.label_width;
        setRange (1, 200);
        slider.setRange (0, 199);
        //slider.minWidth = 150;
        setPrecision (0);
        setValue (user_data.iter);
        toolTip = "Number of HistogramTransform passes."
        onValueUpdated = function (value) { user_data.iter = value; };
    }

    // median
    this.median_NC = new NumericControl (this);
    with (this.median_NC) {
        label.text = "Target median:";
        label.minWidth = this.label_width;
        setRange (0.001, 0.2);
        slider.setRange (0, 1000);
        slider.minWidth = 400;
        setPrecision (3);
        setValue (user_data.target_median);
        toolTip = "Desired median of the resulting image.";
        onValueUpdated = function (value) { user_data.target_median = value; };
    }

    // mask shadows clipping
    this.shadows_clipping_NC = new NumericControl (this);
    with (this.shadows_clipping_NC) {
        label.text = "Shadows clipping:";
        label.minWidth = this.label_width;
        setRange (0, 0.4);
        slider.setRange (0, 401);
        //slider.minWidth = 400;
        setPrecision (3);
        setValue (user_data.shadows_clipping);
        toolTip = "Shadows clipping to perform on each luminance mask";
        onValueUpdated = function (value) { user_data.shadows_clipping = value; };
    }

    // mask blur method: label
    this.blur_method_LBL = new Label (this);
    with (this.blur_method_LBL) {
        text = "Blur method:";
        textAlignment = TextAlign_Right | TextAlign_VertCenter;
        minWidth = this.label_width;
    }

    // mask blur method: radio buttons
    this.blur_method_NONE_R = new RadioButton (this);
    with (this.blur_method_NONE_R) {
        text = "None";
        if (user_data.blur_method == BLUR_METHOD_NONE) { checked = true; }
        onCheck = function(checked) {
            if (checked) {
                user_data.blur_method = BLUR_METHOD_NONE;
            } else {
            }
        };
    }
    this.blur_method_ATW_R = new RadioButton (this);
    with (this.blur_method_ATW_R) {
        text = "ÀTrousWavelets";
        if (user_data.blur_method == BLUR_METHOD_ATW) { checked = true; }
        onCheck = function(checked) {
            if (checked) {
                user_data.blur_method = BLUR_METHOD_ATW;
            } else {
            }
        };
    }
    this.blur_method_CONV_R = new RadioButton (this);
    with (this.blur_method_CONV_R) {
        text = "Convolution";
        if (user_data.blur_method == BLUR_METHOD_CONV) { checked = true; }
        onCheck = function(checked) {
            if (checked) {
                user_data.blur_method = BLUR_METHOD_CONV;
            } else {
            }
        };
    }

    // mask blur method: sizer
    this.blur_method_HS = new HorizontalSizer (this);
    with (this.blur_method_HS) {
        spacing = 6;
        add (this.blur_method_LBL);
        add (this.blur_method_NONE_R);
        add (this.blur_method_ATW_R);
        add (this.blur_method_CONV_R);
    }

    // mask atw layers to remove
    this.atw_layers_NC = new NumericControl (this);
    with (this.atw_layers_NC) {
        label.text = "Wavelet layers to remove:";
        label.minWidth = this.label_width;
        setRange (1, 5);
        slider.setRange (0, 5);
        //slider.minWidth = 400;
        setPrecision (0);
        setValue (user_data.atw_layers);
        toolTip = "ÀTrousWavelet layers to remove from masks";
        onValueUpdated = function (value) { user_data.atw_layers = value; };
    }

    // mask atw scaling function: label
    this.atw_scaling_LBL = new Label (this);
    with (this.atw_scaling_LBL) {
        text = "Wavelets scaling function:";
        textAlignment = TextAlign_Right | TextAlign_VertCenter;
        minWidth = this.label_width;
        toolTip = "Scaling function used to calculate layers";
    }

    // mask atw scaling function: combobox
    this.atw_scaling_CB = new ComboBox (this);
    with (this.atw_scaling_CB) {
        for (var i = 0; i < engine.atw_scaling_functions.length; i++) {
            addItem (engine.atw_scaling_functions[i].name);
        }
        currentItem = user_data.atw_scaling;
        toolTip = "Scaling function used to calculate layers";
        onItemSelected = function (index) { user_data.atw_scaling = index; };
    }

    // mask atw scaling function: sizer
    this.atw_scaling_HS = new HorizontalSizer (this);
    with (this.atw_scaling_HS) {
        spacing = 6;
        add (this.atw_scaling_LBL);
        add (this.atw_scaling_CB, 100);
    }

    // mask convolution kernel size
    this.conv_pixels_NC = new NumericControl (this);
    with (this.conv_pixels_NC) {
        label.text = "Convolution kernel size:";
        label.minWidth = this.label_width;
        setRange (3, 31);
        slider.setRange (0, 14);
        setPrecision (0);
        setValue (user_data.conv_pixels);
        toolTip = "Kernel size for the convolution, in pixels";
        onValueUpdated = function (value) { user_data.conv_pixels = value; };
    }

    // mask sizer
    this.mask_VS = new VerticalSizer (this);
    with (this.mask_VS) {
        margin = 6;
        spacing = 6;
        add (this.shadows_clipping_NC);
        addSpacing (4);
        add (this.blur_method_HS);
        addSpacing (4);
        add (this.atw_layers_NC);
        add (this.atw_scaling_HS);
        addSpacing (4);
        add (this.conv_pixels_NC);
    }

    // mask groupbox
    this.mask_GB = new GroupBox (this);
    with (this.mask_GB) {
        title = "Mask";
        sizer = this.mask_VS;
    }

    // delete settings checkbox
    this.ds_CB = new CheckBox (this);
    with (this.ds_CB) {
        text = "Delete settings and exit";
        checked = user_data.delete_settings;
        toolTip = "Check to remove the stored settings and exit the program.";
        onCheck = function (checked) { user_data.delete_settings = checked; };
    }

    // buttons
    this.ok_Button = new PushButton (this);
    this.ok_Button.text = " OK ";
    this.ok_Button.onClick = function() { this.dialog.ok(); };

    this.cancel_Button = new PushButton (this);
    this.cancel_Button.text = " Cancel ";
    this.cancel_Button.onClick = function() { this.dialog.cancel(); };

    this.buttons_Sizer = new HorizontalSizer;
    this.buttons_Sizer.spacing = 4;
    this.buttons_Sizer.addStretch();
    this.buttons_Sizer.add (this.ok_Button);
    this.buttons_Sizer.add (this.cancel_Button);

    // pack everything
    this.sizer = new VerticalSizer;
    with (this.sizer) {
        margin = 6;
        spacing = 6;
        add (this.helpLabel);
        addSpacing (4);
        add (this.iter_NC);
        add (this.median_NC);
        add (this.mask_GB);
        addSpacing (4);
        add (this.ds_CB);
        addSpacing (4);
        add (this.buttons_Sizer);
    }

    this.windowTitle = "MaskedStretchTransform v" + VERSION;
    this.adjustToContents();
}
mst_dialog.prototype = new Dialog;

function mst_settings() {
    var conf = new Array (
        // important: use the same name as the user_data variables
        new Array ("iter",             DataType_UInt8),
        new Array ("target_median",    DataType_Float),
        new Array ("shadows_clipping", DataType_Float),
        new Array ("blur_method",      DataType_UInt8),
        new Array ("atw_layers",       DataType_UInt8),
        new Array ("atw_scaling",      DataType_UInt8),
        new Array ("conv_pixels",      DataType_UInt8)
    );

    this.load = function() {
        var temp;

        for (var i in conf) {
            var str  = conf[i][0];
            var type = conf[i][1];

            temp = Settings.read (SET_PREFIX + "/" + str, type);
            if (Settings.lastReadOK) {
                user_data[str] = temp;
            } else {
                console.writeln (format (
                    "Warning: couldn't read setting '%s/%s'", SET_PREFIX, str
                ));
            }
        }
    }

    this.save = function() {
        for (var i in conf) {
            var str  = conf[i][0];
            var type = conf[i][1];

            Settings.write (SET_PREFIX + "/" + str, type, user_data[str]);
        }
    }

    this.del = function() {
        Settings.remove (SET_PREFIX);
    }
}
var mst_settings = new mst_settings;

function main() {
    console.hide();

    engine.set_win (ImageWindow.activeWindow);

    mst_settings.load();
    var dialog = new mst_dialog;   // has to be done after settings are loaded
    if (!dialog.execute())
        return;
    if (user_data.delete_settings) {
        mst_settings.del();
        console.show();
        return;
    } else {
        mst_settings.save();
    }

    console.abortEnabled = true;

    var startts = new Date;
    if (engine.calc_mtf()) {
        console.writeln (format ("Using MTF of %6.04f.", engine.mtf));
        engine.work();
    } else {
        console.writeln ("Image not modified (but its RGBWS *was* modified).");
    }
    var endts = new Date;
    console.writeln (format ("<br>MaskedStretchTransform: %.2f s",
        (endts.getTime() - startts.getTime()) / 1000));

    console.show();
}

main();


Dado que las páginas del foro se hacen super largas con tanta versión por aquí y por allá, a partir de ahora editaré mis mensajes cuando tenga una versión nueva.

Técnicamente este mensaje es off-topic, puesto que el programa ya no tiene mucho de preliminar, pero bueno :arrow: .
--
 David Serrano

Offline Jordi Gallego

  • PixInsight Addict
  • ***
  • Posts: 279
Implementación preliminar de auto-star-profile-transform.js
« Reply #23 on: 2007 September 16 01:25:50 »
Funciona de maravilla David, gracias de nuevo.
Ahora que es tan sencillo y cómodo el usarlo habrá que estudiar como optimizar el proceso para mejorar el resultado final. Seguro que Carlos ya se lo está mirando :wink:

Saludos
Jordi
Jordi Gallego
www.astrophoto.es

Offline Maxi

  • PixInsight Addict
  • ***
  • Posts: 180
  • Barcelona / España - Spain
    • http://www.astromodelismo.es/index.htm
Implementación preliminar de auto-star-profile-transform.js
« Reply #24 on: 2007 September 16 02:27:10 »
Me pierdo  :?

Este scrip, para poderlo probar, hay que meter todo este codigo en algún sitio o ya viene implementado en alguna función del la nueva versión que nos ha anunciado Juan, que caduca el 29 de septiembre  :?:

Saludos

Offline C. Sonnenstein

  • PixInsight Addict
  • ***
  • Posts: 262
    • http://astrosurf.com/astro35mm
Implementación preliminar de auto-star-profile-transform.js
« Reply #25 on: 2007 September 16 02:34:48 »
Hola Maxi:

Quote from: "Maxi"
Me pierdo  :?

Este scrip, para poderlo probar, hay que meter todo este codigo en algún sitio o ya viene implementado en alguna función del la nueva versión que nos ha anunciado Juan, que caduca el 29 de septiembre  :?:

Tienes que copiar el siguiente código en Script Editor y guardarlo como archivo .js:

Code: [Select]
/*
    masked-stretch-transform.js v0.3
    Iteratively stretch histogram with an appropriate luminance mask each time.
    Copyright (C) 2007  David Serrano

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
    Special thanks go to Carlos Sonnenstein and Carlos Milovic for
    their (in)valuable contributions.

    Changelog:
    0.3:   Now the code is more OO. Hope it's well structured.
           Uses the new Math.mtf() built-in function. Checks if iter == 0.
           Initial user interface (mostly copy & paste).
    0.2:   Some code reorganization.
           Now deduces the MTF value from given values: iterations and target median.
    0.1.1: Bug fix: masked was not being inverted.
    0.1:   Initial version.
*/

// TODO: make sure get_median does the right thing (obtain luma, then get its median).
// TODO: try to reduce the difference between desired and obtained medians.
// TODO: devise a way for not generating swapfiles for the histogram loop. It's sooo slooow...
// TODO: seems that the settings code isn't working properly.

#define VERSION "0.3"
#define E 1e-4            // epsilon

#include <pjsr/ColorSpace.jsh>
#include <pjsr/DataType.jsh>
#include <pjsr/FrameStyle.jsh>
#include <pjsr/NumericControl.jsh>
#include <pjsr/SampleType.jsh>
#include <pjsr/Sizer.jsh>
#include <pjsr/UndoFlag.jsh>

#feature-id MaskedStretchTransform
#feature-info At the time of stretching the histogram of an image, \
    it's better to do it several times changing the mask used every \
    time - a long, boring task that is perfect for script automation. \
    This script does precisely that.
//#feature-icon masked-stretch-transform.xpm

function mst_user_data() {
    this.iter = 5;
    this.target_median = 0.08;
}
var user_data = new mst_user_data;

function mst_engine() {
    var stats = new ImageStatistics;
    var hist;   // histogram transform
    var v;      // main view of active window

    this.get_luma = function (view) {
        view.image.extractLuminance (luma = new Image);
        return luma;
    }

    // obtains luma, then its median. Obtaining directly the median of the
    // view resulted in the median of the red channel only.
    this.get_median = function (view) {
        var l = this.get_luma (view);
        stats.generate (l);
        return stats.median;
    }

    // from orig median "om" to target median "tm" in "it" iters
    this.calc_mtf = function (om, tm, it) {
        var tmp;
        var low = 0;
        // this is 1 instead of 0.5 because we should't assume that the
        // user is always going to lighten the image (ie keep the mtf
        // value < 0.5). Users are always cleverer and we shouldn't take
        // decisions on their behalf. As the saying goes, "If something
        // prevents you from doing stupid things, it also prevents you
        // from doing clever things".
        var high = 1;
        // this initial value could depend on the number of iterations.
        //
        // Since in the majority of cases the user will want to lighten
        // the image, it's better to set this value a bit higher, so the
        // loop following will end up with a image too light, and then
        // the first variable to be adjusted will be "high", not "low".
        // Therefore, in the majority of cases, the second pass of the
        // loop will search in [0, 0.35] instead of [0.35, 1].
        var mtf = 0.35;

        while (1) {
            tmp = om;
            for (var i = 0; i < it; i++)
                tmp = Math.mtf (mtf, tmp) * (1-tmp) + tmp*tmp;

//console.writeln ("tried low (",low,") mtf (",mtf,") high (",high,") result (",tmp,")");
            if (Math.abs (tmp - tm) < E)
                return mtf;

            if (tmp > tm) {     // where's Perl...
                low = mtf;
            } else {
                high = mtf;
            }
            mtf = (low + high) / 2;
        }
    }

    this.build_HT = function() {
        var m = this.get_median (this.v);
        var mtf = this.calc_mtf (m, user_data.target_median, user_data.iter);

        console.writeln (format ("Current median: %6.04f. Using MTF of %6.04f", m, mtf));

        hist = new HistogramTransform;
        hist.H = [
            // shadows, midtones, highlights, ext_shadows, ext_hilights
            [0, 0.5, 1, 0, 1], // R
            [0, 0.5, 1, 0, 1], // G
            [0, 0.5, 1, 0, 1], // B
            [0, mtf, 1, 0, 1], // RGB
            [0, 0.5, 1, 0, 1], // Alpha
        ];
    }

    this.stretch = function (aw) {
        // window that will hold the luminance for masking
        var luma_w = new ImageWindow (1, 1, 1, this.v.image.bitsPerSample, false, false, "MST_luma");

        for (var i = 0; i < user_data.iter; i++) {
            var luma = this.get_luma (this.v);

            // transfer image to window and apply the window as mask
            with (luma_w.mainView) {
                // Inform the core application that we are going to modify this view's image
                beginProcess (UndoFlag_NoSwapFile);
                // ### Note that after this transfer, luma is no longer a reference to a valid Image object
                image.transfer (luma);
                endProcess();
            }
            //luma_w.show();
            aw.maskVisible = false;
            aw.maskInverted = true;
            aw.mask = luma_w;

            // stretch
            hist.executeOn (this.v);

            // clean up
            luma_w.removeMaskReferences();  // automatically removes mask from aw
            gc();
        }

        luma_w.close();
        // no need to set luma to null, since .transfer removed the reference to the Image object
        luma_w = null;
        gc();
    }


}
var engine = new mst_engine;

function mst_dialog() {
    this.__base__ = Dialog;
    this.__base__();

    // help label
    this.helpLabel = new Label (this);
    with (this.helpLabel) {
        frameStyle = FrameStyle_Box;
        margin = 4;
        wordWrapping = true;
        useRichText = true;
        text = "<b>MaskedStretchTransform v"+VERSION+"</b> - A " +
            "script to perform a histogram stretch of an image via several small " +
            "luminance-masked HistogramTransform's. This is good for preventing " +
            "small stars from growing without control.<br><br>" +
            "Choose the number of iterations and the median of the desired image " +
            "typically in the range 0.05 - 0.10). Then click 'Ok' and wait for a " +
            "new image to be created.<br><br>" +
            "<b>Please note</b> that, as of now, the median of the final image " +
            "won't be exactly the same as the specified one, and some trial and " +
            "error work is necessary to achieve the desired result.";
    }

    // iterations
    this.iter_NC = new NumericControl (this);
    with (this.iter_NC) {
        label.text = "Iterations:";
        setRange (1, 100);
        slider.setRange (0, 99);
        //slider.minWidth = 150;
        setPrecision (0);
        setValue (user_data.iter);
        toolTip = "Number of HistogramTransform passes."
        onValueUpdated = function (value) {
           user_data.iter = value;
        }
    }

    // median
    this.median_NC = new NumericControl (this);
    with (this.median_NC) {
        label.text = "Target median:";
        setRange (0.001, 0.2);
        slider.setRange (0, 1000);
        slider.minWidth = 400;
        setPrecision (3);
        setValue (user_data.target_median);
        toolTip = "Desired median of the resulting image."
        onValueUpdated = function (value) {
            user_data.target_median = value;
        }
    }

    // buttons
    this.ok_Button = new PushButton (this);
    this.ok_Button.text = " OK ";
    this.ok_Button.onClick = function() { this.dialog.ok(); };

    this.cancel_Button = new PushButton (this);
    this.cancel_Button.text = " Cancel ";
    this.cancel_Button.onClick = function() { this.dialog.cancel(); };

    this.buttons_Sizer = new HorizontalSizer;
    this.buttons_Sizer.spacing = 4;
    this.buttons_Sizer.addStretch();
    this.buttons_Sizer.add (this.ok_Button);
    this.buttons_Sizer.add (this.cancel_Button);

    // pack everything
    this.sizer = new VerticalSizer;
    with (this.sizer) {
        margin = 6;
        spacing = 6;
        add (this.helpLabel);
        addSpacing (4);
        add (this.iter_NC);
        add (this.median_NC);
        add (this.buttons_Sizer);
    }

    this.windowTitle = "MaskedStretchTransform v" + VERSION;
    this.adjustToContents();
}
mst_dialog.prototype = new Dialog;
var dialog = new mst_dialog;

function load_settings() {
    var temp;

    temp = Settings.read ("mst_iter", DataType_UInt8);
    if (Settings.lastReadOK) {
        console.writeln ("Couldn't read setting 'mst_iter'");
        user_data.iter = temp;
    }

    temp = Settings.read ("mst_target_median", DataType_Float);
    if (Settings.lastReadOK) {
        console.writeln ("Couldn't read setting 'mst_target_median'");
        user_data.target_median = temp;
    }
}

function save_settings() {
    Settings.write ("mst_iter", DataType_UInt8, user_data.iter);
    Settings.write ("mst_target_median", DataType_Float, user_data.target_median);
}

function main() {
    console.hide();
    load_settings();
   
    if (!dialog.execute())
        return;

    save_settings();
    console.show();
    console.abortEnabled = true;

    var aw = ImageWindow.activeWindow;

    if (aw.isNull)
        throw Error ("No active image window.");
    if (user_data.iter < 1)
        throw Error ("Too few iterations.");

    engine.v = aw.mainView;
    engine.build_HT();
    engine.stretch (aw);
}

main()


Suerte!
Carlos Sonnenstein

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Implementación preliminar de auto-star-profile-transform.js
« Reply #26 on: 2007 September 16 02:43:20 »
Quote from: "Maxi"
Este scrip, para poderlo probar, hay que meter todo este codigo en algún sitio o ya viene implementado


Hay que meterlo por ahí:

 - Abrir alguna imagen en PixInsight.
 - Abrir el Script Editor.
 - Pulsar Ctrl-N para crear un nuevo archivo.
 - Copiar el texto del script desde esta página.
 - Pegarlo en el Script Editor.
 - Pulsar F9 para ejecutarlo. Al hacerlo, te pedirá que guardes el archivo en algún sitio. Busca alguna carpeta donde guardarlo o crea una nueva para estas cosas.
 - A disfrutar!

A partir de este momento, obviamente, no hay que hacer todos estos pasos puesto que ya tienes el programa guardado en tu disco duro. La segunda y siguientes veces basta con:

 - Abrir alguna imagen. Lógico ;).
 - Ir al menú Script > Execute script file.
 - Buscar y seleccionar el script que quieras.
 - Disfrutar :).

Estoy mirando para que aparezca en la sección de "Feature Scripts" pero así a bote pronto no consigo nada. Es algo secundario de todas formas.
--
 David Serrano

Offline Maxi

  • PixInsight Addict
  • ***
  • Posts: 180
  • Barcelona / España - Spain
    • http://www.astromodelismo.es/index.htm
Implementación preliminar de auto-star-profile-transform.js
« Reply #27 on: 2007 September 16 04:37:52 »
Gracias chicos, lo probare y si puedo os pondre lo que haya conseguido

Saludos

Offline Maxi

  • PixInsight Addict
  • ***
  • Posts: 180
  • Barcelona / España - Spain
    • http://www.astromodelismo.es/index.htm
Implementación preliminar de auto-star-profile-transform.js
« Reply #28 on: 2007 September 16 09:08:02 »
Lo he puesto y se ve que da error en alguna de las lineas.



En todo caso me esperare, a la proxima revisión del programa, en la cual supongo que lo pondreis en la lista ya de sript  :wink:

Saludos

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Implementación preliminar de auto-star-profile-transform.js
« Reply #29 on: 2007 September 16 09:20:54 »
Quote from: "Maxi"
Lo he puesto y se ve que da error en alguna de las lineas.


Me huele a que no tienes la última versión de PixInsight. La última es la 01.00.42.325rc7, anunciada aquí. Si no la tienes, instálatela y prueba otra vez. Si ya la tienes.... hmmm....
--
 David Serrano