Author Topic: Script de neutralizacion de background  (Read 18974 times)

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« on: 2008 August 19 10:45:15 »
Hola,

estamos haciendo unos scriptillos para facilitarnos un poco los procesados  :D si, andamos un poco baguetes y aburridos  :lol:  :lol:  :lol: Bien, el tema es que tenemos montado un script que basicamente implementa el metodo de neutralizacion de backround que explica Juan en el tutorial de las deconvoluciones. El tema es que de momento tenemos un metodo muy cutre para definir el centroide del preview a partir del cual se evaluan las estadisiticas, basicamente se le da las coordenadas al script   :lol:  :lol:  :lol: chapuzero, si, a partir de alli todo es automatico.
Hay alguna manera de que un usuario con el raton marque una zona de la imagen y des del script se pueda "coger" esas coordenadas. La verdad es que facilitaria el uso del script y de existir esta funcionalidad, seria sencillo ampliar el numero de previews a generar para asi hacer una neutralizacion mas exacta.

Pues eso, gracias

Oriol&Ivette

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Script de neutralizacion de background
« Reply #1 on: 2008 August 22 03:30:42 »
Hola

En primer lugar, he de decir que me encanta comprobar que estáis empezando a hacer cosas con las herramientas de desarrollo de PixInsight. Bienvenidos, y tened cuidado conmigo porque os intentaré liar para haceros trabajar todo lo posible. Puedo llegar a ser muy pesado en este sentido; estáis avisados ;)

Quote
Hay alguna manera de que un usuario con el raton marque una zona de la imagen y des del script se pueda "coger" esas coordenadas.


No desde un script. El runtime de JavaScript incluido en PixInsight Core no proporciona herramientas para la interacción directa del usuario con las ventanas de imagen y las vistas. Para hacer esto, tenéis básicamente dos caminos:

- Escribir un módulo en C++, utilizando la PCL y las herramientas de desarrollo que ésta incluye. Para hacer lo que queréis, tendríais que escribir una interfaz dinámica, como por ejemplo DynamicCrop (cuyo código fuente completo lo tenéis en la distribución estándar de PCL).

- Utilizar un control especializado dentro de la ventana de diálogo de un script, donde podríais dibujar una imagen seleccionada y permitir que el usuario definiera posiciones y zonas rectangulares mediante el cursor del ratón.

Ambos caminos son igualmente válidos. El primero os permitiría construir un proceso con vida propia dentro del universo de PixInsight, pero la cantidad de trabajo requerida es mayor y supone un esfuerzo extra si es vuestro primer módulo, al tratarse de un proceso dinámico. Mi recomendación es que no se empiece escribiendo un proceso dinámico, sino uno estático (sin interacción con el usuario en las ventanas de imagen).

La segunda opción es perfectamente realizable y puede llegar a ser tremendamente eficiente. El objeto ScrollBox de JavaScript os permite construir una vista personalizada de cualquier imagen, incluyendo una imagen perteneciente a una vista (View) en una ventana (ImageWindow). ScrollBox.viewport os proporciona un canvas navegable (mediante barras de scroll) donde podéis dibujar cualquier cosa reimplementando el método Control.onPaint.

Resumiendo y estructurando la cosa, tenemos los siguientes elementos de interés:

ScrollBox
Es un control especializado para contener a otro control (llamado viewport) que puede ser navegable mediante barras de desplazamiento (scroll bars). Es relativamente sencillo implementar navegación mediante click & drag con el ratón, así como la posibilidad de hacer vistas ampliadas (zoom arbitrario).

ScrollBox.viewport
El viewport es un objeto de tipo Control. En él se puede dibujar e interactuar con el usuario.

Control.onMouseMove
Control.onMousePress
Control.onMouseRelease
Control.onMouseDoubleClick

Estos gestores de eventos (event handlers) os permiten implementar una completa interacción del usuario con ScrollBox.viewport.

Control.onPaint
Este gestor de eventos es llamado automáticamente cada vez que se necesita redibujar el control, o una parte del mismo. Reimplementarlo es muy fácil y os permite dibujar cualquier imagen.

Graphics
Este objeto os proporciona todo lo que necesitéis para dibujar, incluyendo por supuesto imágenes de todo tipo y gráficos vectoriales. Lo podéis usar libremente dentro de Control.onPaint.

Espero haberos orientado un poco en la dirección correcta. Aquí estoy para ayudaros en lo que podáis necesitar. Ánimo que el proyecto es muy interesante.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #2 on: 2008 August 22 04:09:41 »
Juan muchas gracias  :D iremos por la segunda opcion! bueno lo intentaremos  :lol:  :lol:  :lol: hay alguna web de documentracion de JavaScript algo que de una pequeña descripcion de los metodos de los objetos a los que tenemos acceso (no de la parte de PI, ya se entiende  :roll: )

Gracias por adelantado

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Script de neutralizacion de background
« Reply #3 on: 2008 September 09 08:38:12 »
Quote from: "OriolLehmkuhl"
hay alguna web de documentracion de JavaScript algo que de una pequeña descripcion de los metodos de los objetos a los que tenemos acceso (no de la parte de PI, ya se entiende  :roll: )


Así de memoria creo que no se usa ningún objeto que no sea del Pixi. Posiblemente el motor de javascript ni siquiera define ningún objeto por defecto, y estos tienen que venir definidos por el entorno en que el motor se ejecuta (Pixi en nuestro caso, o un navegador web en el resto del mundo).

Si no recuerdo mal, en la PCL hay documentación sobre los objetos accesibles en Pixi (generada con doxygen). Está orientada a C++, pero como el tipo de los argumentos tiene que ser compatible y las funciones hacen lo mismo (obviamente xD), es bastante apropiada.

Acerca de tu pregunta en concreto, dos cosas:

- No me parece muy apropiado que el usuario especifique un único píxel para hacer la correción, puesto que debido al ruido este píxel puede tener una ligera dominante de algún color, y eso te arruinará la neutralización. Mejor usar un pequeño rectángulo de píxels para determinar el color de fondo. El tamaño de este rectángulo puede ser, por ejemplo, el seleccionado por el usuario en ReadoutOptions (en el diálogo se llama "Probe size in pixels", y diría que la propiedad que da este valor es .size).

- Yo intentaría buscar un área del cielo vacía de forma programática, no manual. El algoritmo sería básicamente así:

    1.- Determinar la mediana de la imagen.
    2.- Dividir la imagen en 4 partes iguales.
    3.- Determinar la mediana de cada una de las partes.
    4.- Quedarse con la parte que tiene la mediana más aproximada a la global, y descartar las otras 3.
    5.- Si esta parte tiene un tamaño suficientemente pequeño (por ejemplo, ReadoutOptions.size ;)), terminar.
    6.- Volver al punto 2, pero usando sólo esta parte en lugar de la imagen entera.


Es decir, una búsqueda binaria en 2 dimensiones 8).

Dicho gráficamente, el punto 2 nos dejaría la imagen dividida así:

Code: [Select]
+---------------+---------------+
|               |               |
|               |               |
|               |               |
|       1       |       2       |
|               |               |
|               |               |
|               |               |
+---------------+---------------+
|               |               |
|               |               |
|               |               |
|        3      |       4       |
|               |               |
|               |               |
|               |               |
+---------------+---------------+


Si la imagen fuera de la cabeza de caballo (por ejemplo, en esta orientación), probablemente el paso 4 nos diría que la parte más apropiada para continuar es la 1. A continuación volveríamos a subdividir:

Code: [Select]
+-------+-------+................
|       |       |               .
|   1   |   2   |               .
|       |       |               .
+-------+-------+               .
|       |       |               .
|   3   |   4   |               .
|       |       |               .
+-------+-------+               .
.                               .
.                               .
.                               .
.                               .
.                               .
.                               .
.                               .
.................................


Y el proceso continuaría durante varias iteraciones (difícilmente más de 13 hoy en día, excepto que el fotógrafo sea Vicent Peris o uno de su especie ;)) hasta llegar a una muestra suficientemente pequeña. Ojito que, dado que la imagen puede no ser perfectamente cuadrada, una de las dimensiones llegará antes que la otra al tamaño necesario.

También se puede dividir no en 4 partes, sino en 9 o 16 o en general N^2. Con esto reducimos el número de iteraciones pero aumentamos el trabajo en cada iteración. Si esto es productivo o no, es algo que dejo como ejercicio para quien le interese ;).
--
 David Serrano

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #4 on: 2008 September 09 23:26:18 »
Quote from: "David Serrano"

No me parece muy apropiado que el usuario especifique un único píxel para hacer la correción, puesto que debido al ruido este píxel puede tener una ligera dominante de algún color, y eso te arruinará la neutralización. Mejor usar un pequeño rectángulo de píxels para determinar el color de fondo. El tamaño de este rectángulo puede ser, por ejemplo, el seleccionado por el usuario en ReadoutOptions (en el diálogo se llama "Probe size in pixels", y diría que la propiedad que da este valor es .size).


Bueno eso es lo que ahora hago, es decir, se hace un rectangulo de unos 10 pixels arrededor del punto que indica el usuario :wink:

Quote from: "David Serrano"

- Yo intentaría buscar un área del cielo vacía de forma programática, no manual. El algoritmo sería básicamente así:

    1.- Determinar la mediana de la imagen.
    2.- Dividir la imagen en 4 partes iguales.
    3.- Determinar la mediana de cada una de las partes.
    4.- Quedarse con la parte que tiene la mediana más aproximada a la global, y descartar las otras 3.
    5.- Si esta parte tiene un tamaño suficientemente pequeño (por ejemplo, ReadoutOptions.size ;)), terminar.
    6.- Volver al punto 2, pero usando sólo esta parte en lugar de la imagen entera.


Es decir, una búsqueda binaria en 2 dimensiones 8).


me encanta   8) no lo habia pensado, y en mi trabajo manejo algoritmos de busqueda de puntos en un dominos irregular (malla no estructurada) parecidos  :oops: gracias, seguro que lo intento programar  :D

Muchas gracias por tus ideas y tu tiempo David  :wink:

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #5 on: 2008 September 12 12:31:48 »
Hola a todos,

bueno hoy ha habido un poco de tiempo para provar el algoritmo de David, el tema funciona cuando el objeto de cielo profundo no ocupa mucho espacio en la imagen, por ejemplo en la siguiente imagen de la m51 (la izquierda es la original y la derecha es la corregida por el script) :



pero cuando hay nebulosas extensas que ocupan todo el dominio el algoritmo falla. El problema es que la media de referencia (la de toda la imagen) esta afectada por la nebulosa, asi que se termina seleccionando una area llena de nebulosa , mirar un ejemplo (la crecent, izquierda original y derecha corregida(por decir algo  :lol:  :lol: )):



A alguien se le ocurre alguna idea  :roll: ?, bueno siempre se podria dejar que el usuario marque el punto de referencia si quiere para casos dificiles como el que indicamos...

Dejamos el script por aqui ya que en algunos casos ya parece util:

Code: [Select]


/*
 * Simple script to carry out a background neutralization
 *
 * main algorithm based on :
 *
 * 1- Juan Conejero tutorial: http://pixinsight.com/examples/deconvolution/Gemini-NGC5189/en.html
 * 2- David Serrano divide and conquer algorithm: http://pixinsight.com/forum/viewtopic.php?p=3830&sid=963f60338e12cfdddce474be90962540#3830
 * */

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

function doBn(window, point) {

    var view = window.mainView;
    var rect  = new Rect;

    rect.width  = 10;
    rect.height = 10;

    rect.moveTo(point);
    window.createPreview(rect,"bp");

    var b = new ImageWindow( window.previewById("bp").image.width,
                             window.previewById("bp").image.height,
                             window.previewById("bp").image.numberOfChannels,
                             window.bitsPerSample,
                             window.isFloatSample,
                             window.previewById("bp").image.colorSpace != ColorSpace_Gray,
                             "b" );
    var bView = b.mainView;

    bView.beginProcess(UndoFlag_NoSwapFile);

    bView.image.apply(window.previewById("bp").image);

    var stats = new ImageStatistics;

    bView.image.selectedChannel = 0;
    stats.generate(bView.image);
    var medR = stats.median;

    bView.image.selectedChannel = 1;
    stats.generate(bView.image);
    var medG = stats.median;


    bView.image.selectedChannel = 2;
    stats.generate(bView.image);
    var medB = stats.median;

    var bn  = new PixelMath;

    var id = bView.id;

    if((medR<=medG) && (medR<=medB)) {
        with (bn) {
            expression  = "$target";
            expression1 = "$target - (Med("+id+") - Med("+id+"[0]))";
            expression2 = "$target - (Med("+id+") - Med("+id+"[0]))";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    } else if (medG<=medB) {
        with (bn) {
            expression  = "$target - (Med("+id+") - Med("+id+"[1]))";
            expression1 = "$target";
            expression2 = "$target - (Med("+id+") - Med("+id+"[1]))";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    } else {
        with (bn) {
            expression  = "$target - (Med("+id+") - Med("+id+"[2]))";
            expression1 = "$target - (Med("+id+") - Med("+id+"[2]))";
            expression2 = "$target";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    }

    bn.executeOn(view);

    b.close();
    window.deletePreview(window.previewById("bp"));

}

function getStats(image,x1,y1,x2,y2) {

    var stats = new ImageStatistics;

    var rect = new Rect;
    rect.width = x2-x1;
    rect.height = y2-y1;
   
    point = new Point(x1 + 0.5*(rect.width), y1 + 0.5*(rect.height));
    rect.moveTo(point);
    image.selectedRect = rect;


    image.selectedChannel = 0;
    stats.generate(image);
    var medR = stats.median;

    image.selectedChannel = 1;
    stats.generate(image);
    var medG = stats.median;


    image.selectedChannel = 2;
    stats.generate(image);
    var medB = stats.median;

    return (1.0/3.0)*(medR+medG+medB);
}

function findPoint(image,ref) {

    var x1 = 0;
    var y1 = 0;
    var x2 = image.width;
    var y2 = image.height;

    var find = false;

    while (!find) {
        var box1 = getStats(image,x1,y1,x2-0.5*(x2-x1),y2-0.5*(y2-y1));
        var box2 = getStats(image,x1-0.5*(x2-x1),y1,x2,y2-0.5*(y2-y1));
        var box3 = getStats(image,x1,y1-0.5*(x2-x1),x2-0.5*(x2-x1),y2);
        var box4 = getStats(image,x1-0.5*(x2-x1),y2-0.5*(y2-y1),x2,y2);
        var ref1 = Math.abs(ref-box1);
        var ref2 = Math.abs(ref-box2);
        var ref3 = Math.abs(ref-box3);
        var ref4 = Math.abs(ref-box4);

        if((ref1<ref2)&&(ref1<ref3)&&(ref1<ref4)) {
               x1 = x1;
               x2 = x2-0.5*(x2-x1);
               y1 = y1;
               y2 = y2-0.5*(y2-y1);
        }else if ((ref2<ref1)&&(ref2<ref3)&&(ref2<ref4)) {
               x1 = x2-0.5*(x2-x1);
               x2 = x1;
               y1 = y1;
               y2 = y2-0.5*(y2-y1);
        }else if ((ref3<ref1)&&(ref3<ref2)&&(ref3<ref4)) {
               x1 = x1;
               x2 = x2-0.5*(x2-x1);
               y1 = y2-0.5*(y2-y1);
               y2 = y1;
        } else {
               x1 = x2-0.5*(x2-x1);
               x2 = x2;
               y1 = y2-0.5*(y2-y1);
               y2 = y2;
        }

        if(Math.abs(x2-x1)<=10) find = true;
    }

    return new Point(x2-0.5*(x2-x1),y2-0.5*(y2-y1));
}

function main() {
    console.hide();

    var window = ImageWindow.activeWindow;

    if ( window.isNull )
        throw Error( "There is no active image window!" );

    var view = window.mainView;
    var value = getStats(view.image,0,0,view.image.width,view.image.height);

    console.writeln(" gloval media ",value);

    var point = findPoint(view.image,value);

    doBn(window,point);
}

main();



el codigo es altamente experimental  :lol:  :lol:  :lol: asi que no asumimos los desastres que genere  :wink:

Bueno un saludo a todos

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Script de neutralizacion de background
« Reply #6 on: 2008 September 12 14:11:58 »
Quote from: "OriolLehmkuhl"
pero cuando hay nebulosas extensas que ocupan todo el dominio el algoritmo falla. El problema es que la media de referencia (la de toda la imagen) esta afectada por la nebulosa, asi que se termina seleccionando una area llena de nebulosa


Sí, esto es un problema importante. Yo tenía mi propio script para neutralizar el fondo (funcionaba emulando DBE y llamando a ChannelMatch) y los resultados cuando un objeto ocupa gran parte de la imagen tampoco son satisfactorios. Pero consuela saber que las muestras que DBE pone por defecto también hay que tunearlas ;).


Quote from: "OriolLehmkuhl"
Code: [Select]
rect.moveTo(point);


Ojo que, según mis pruebas, esto no centra el rectángulo en el punto especificado, sino que sitúa en ese punto la esquina superior izquierda del rectángulo. Test code:

Code: [Select]
var rect = new Rect (900, 900);
rect.moveTo (20,20);
ImageWindow.activeWindow.createPreview (rect, "foobar");


Esto provoca que, en getStats(), sitúes el rectángulo de forma que sólo tengas en cuenta el cuadrante inferior derecho de la imagen, quedando la mayoría del rectángulo fuera de ésta. En doBn(), creas un preview en el sitio equivocado.


---


Pena penita que no se puedan hacer monadas como:

Code: [Select]
ImageWindow.activeWindow.createPreview (
    new Rect (900,900).moveTo (20, 20),
    "foobar"
);


;)
--
 David Serrano

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #7 on: 2008 September 12 14:57:33 »
Quote from: "David Serrano"


Ojo que, según mis pruebas, esto no centra el rectángulo en el punto especificado, sino que sitúa en ese punto la esquina superior izquierda del rectángulo. Test code:

Code: [Select]
var rect = new Rect (900, 900);
rect.moveTo (20,20);
ImageWindow.activeWindow.createPreview (rect, "foobar");


Esto provoca que, en getStats(), sitúes el rectángulo de forma que sólo tengas en cuenta el cuadrante inferior derecho de la imagen, quedando la mayoría del rectángulo fuera de ésta. En doBn(), creas un preview en el sitio equivocado.


vaya pues si  :( yo interprete que con esta orden se situaba el centroide del rectangulo en el punto  :roll: tendre que modificar esto ya que esta claro que el script no hace exactamente lo que queriamos  :evil:  :evil: gracias David  :wink:

Despues ponemos la modificacion  :D

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #8 on: 2008 September 12 15:35:40 »
Hola,

pues hemos solucionado el tema que nos ha comentado David  :wink: Aqui esta la nueva version:

Code: [Select]

/*
 * Simple script to carry out a background neutralization
 *
 * main algorithm based on :
 *
 * 1- Juan Conejero tutorial: http://pixinsight.com/examples/deconvolution/Gemini-NGC5189/en.html
 * 2- David Serrano divide and conquer algorithm: http://pixinsight.com/forum/viewtopic.php?p=3830&sid=963f60338e12cfdddce474be90962540#3830
 * */

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

function doBn(window, point) {

    var view = window.mainView;
    var rect  = new Rect;

    rect.width  = 10;
    rect.height = 10;

    rect.moveTo(point);
    window.createPreview(rect,"bp");

    var b = new ImageWindow( window.previewById("bp").image.width,
                             window.previewById("bp").image.height,
                             window.previewById("bp").image.numberOfChannels,
                             window.bitsPerSample,
                             window.isFloatSample,
                             window.previewById("bp").image.colorSpace != ColorSpace_Gray,
                             "b" );
    var bView = b.mainView;

    bView.beginProcess(UndoFlag_NoSwapFile);

    bView.image.apply(window.previewById("bp").image);

    var stats = new ImageStatistics;

    bView.image.selectedChannel = 0;
    stats.generate(bView.image);
    var medR = stats.median;

    bView.image.selectedChannel = 1;
    stats.generate(bView.image);
    var medG = stats.median;


    bView.image.selectedChannel = 2;
    stats.generate(bView.image);
    var medB = stats.median;

    var bn  = new PixelMath;

    var id = bView.id;

    if((medR<=medG) && (medR<=medB)) {
        with (bn) {
            expression  = "$target";
            expression1 = "$target - (Med("+id+") - Med("+id+"[0]))";
            expression2 = "$target - (Med("+id+") - Med("+id+"[0]))";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    } else if (medG<=medB) {
        with (bn) {
            expression  = "$target - (Med("+id+") - Med("+id+"[1]))";
            expression1 = "$target";
            expression2 = "$target - (Med("+id+") - Med("+id+"[1]))";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    } else {
        with (bn) {
            expression  = "$target - (Med("+id+") - Med("+id+"[2]))";
            expression1 = "$target - (Med("+id+") - Med("+id+"[2]))";
            expression2 = "$target";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    }

    bn.executeOn(view);

    b.close();
    window.deletePreview(window.previewById("bp"));

}

function getStats(image,x1,y1,x2,y2) {

    var stats = new ImageStatistics;

    var rect = new Rect;
    rect.width = x2-x1;
    rect.height = y2-y1;
   
    point = new Point(x1, y1);
    rect.moveTo(point);
    image.selectedRect = rect;


    image.selectedChannel = 0;
    stats.generate(image);
    var medR = stats.median;

    image.selectedChannel = 1;
    stats.generate(image);
    var medG = stats.median;


    image.selectedChannel = 2;
    stats.generate(image);
    var medB = stats.median;

    return (1.0/3.0)*(medR+medG+medB);
}

function findPoint(image,ref) {

    var x1 = 0;
    var y1 = 0;
    var x2 = image.width;
    var y2 = image.height;

    var find = false;

    while (!find) {
        var box1 = getStats(image,x1,y1,x2-0.5*(x2-x1),y2-0.5*(y2-y1));
        var box2 = getStats(image,x2-0.5*(x2-x1),y1,x2,y2-0.5*(y2-y1));
        var box3 = getStats(image,x1,y2-0.5*(x2-x1),x2-0.5*(x2-x1),y2);
        var box4 = getStats(image,x2-0.5*(x2-x1),y2-0.5*(y2-y1),x2,y2);
        var ref1 = Math.abs(ref-box1);
        var ref2 = Math.abs(ref-box2);
        var ref3 = Math.abs(ref-box3);
        var ref4 = Math.abs(ref-box4);

        if((ref1<ref2)&&(ref1<ref3)&&(ref1<ref4)) {
               x1 = x1;
               x2 = x2-0.5*(x2-x1);
               y1 = y1;
               y2 = y2-0.5*(y2-y1);
        }else if ((ref2<ref1)&&(ref2<ref3)&&(ref2<ref4)) {
               x1 = x2-0.5*(x2-x1);
               x2 = x1;
               y1 = y1;
               y2 = y2-0.5*(y2-y1);
        }else if ((ref3<ref1)&&(ref3<ref2)&&(ref3<ref4)) {
               x1 = x1;
               x2 = x2-0.5*(x2-x1);
               y1 = y2-0.5*(y2-y1);
               y2 = y1;
        } else {
               x1 = x2-0.5*(x2-x1);
               x2 = x2;
               y1 = y2-0.5*(y2-y1);
               y2 = y2;
        }

        if(Math.abs(x2-x1)<=10) find = true;
    }

    return new Point(x1,y1);
}

function main() {
    console.hide();

    var window = ImageWindow.activeWindow;

    if ( window.isNull )
        throw Error( "There is no active image window!" );

    var view = window.mainView;
    var value = getStats(view.image,0,0,view.image.width,view.image.height);

    console.writeln(" gloval media ",value);

    var point = findPoint(view.image,value);

    doBn(window,point);
}

main();



Haremos algun dialogo para poder controlar el algoritmo, almenos que si no funciona el algoritmo automatico que el usuario pueda decidir que es cielo  :?

Gracias por la ayuda  :wink:

Editamos:

bueno la verdad es que funciona razonable incluso con nebulosas medianas :



bueno toca hacer el dialogo y que cada cual use e metodo que quiera  :lol:  :lol:  :lol:

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #9 on: 2008 September 13 11:47:45 »
Hola,

pues tenemos una version con dialogo  :D ahora se puede usar el metodo automatico, o definir previamente un preview para que el script neutralice el background. El modo automatico es sencillo:



Abrimos el script y ya es el que viene por defecto, en principio si no hay objetos que desvirtuen las medias es bastante efectivo, por ejemplo en esta M51 el resultado es el siguiente:



Si estamos en un caso dificil, como este corazon en falso rgb, pues es mas seguro usar el modo manual (tendreis que selecionar cual es vuestro preview de referencia en uno de los comboBox, el preview se tendra que definir antes de ejecutar el script) :



una vez seleccionado el algortmo que se aplica es directemente el que propuso Juan en el tutorial de la deconvolucion, el resultado es:



Bueno, como siempre dejamos el codigo para la gente que le sea de utilidad  :)

Code: [Select]


/*
 * Simple script to carry out a background neutralization
 *
 * main algorithm based on :
 *
 * 1- Juan Conejero tutorial: http://pixinsight.com/examples/deconvolution/Gemini-NGC5189/en.html
 * 2- David Serrano divide and conquer algorithm: http://pixinsight.com/forum/viewtopic.php?p=3830&sid=963f60338e12cfdddce474be90962540#3830
 * */

#include <pjsr/Sizer.jsh>
#include <pjsr/FrameStyle.jsh>
#include <pjsr/TextAlign.jsh>
#include <pjsr/StdButton.jsh>
#include <pjsr/StdIcon.jsh>
#include <pjsr/UndoFlag.jsh>
#include <pjsr/ColorSpace.jsh>
#include <pjsr/UndoFlag.jsh>

var window = ImageWindow.activeWindow;

var typesOfModes = new Array;

if ( window.isNull )
    throw Error( "There is no active image window!" );

typesOfModes[0] = "Automatic mode"
typesOfModes[1] = "Manual mode"

function BackgroundNeutralizationData()
{
   var window = ImageWindow.activeWindow;

   if ( !window.isNull )
   {
      this.targetView = window.currentView;
      this.typesOfModes = 0;
      this.refView =  window.currentView;
      this.isManual = false;
   }
}

var data = new BackgroundNeutralizationData;

function doBnAuto(point) {

    var view  = data.targetView;
    var rect  = new Rect;

    rect.width  = 10;
    rect.height = 10;

    rect.moveTo(point);
    window.createPreview(rect,"bp");

    var b = new ImageWindow( window.previewById("bp").image.width,
                             window.previewById("bp").image.height,
                             window.previewById("bp").image.numberOfChannels,
                             window.bitsPerSample,
                             window.isFloatSample,
                             window.previewById("bp").image.colorSpace != ColorSpace_Gray,
                             "b" );
    var bView = b.mainView;

    data.refView = window.previewById("bp");

    bView.beginProcess(UndoFlag_NoSwapFile);
    bView.image.apply(data.refView.image);
    doPixelMath(view,bView);
    bView.endProcess();

    b.close();
    window.deletePreview(window.previewById("bp"));
}

function doBnManual() {

    var view  = data.targetView;

    var b = new ImageWindow( data.refView.image.width,
                             data.refView.image.height,
                             data.refView.image.numberOfChannels,
                             window.bitsPerSample,
                             window.isFloatSample,
                             data.refView.image.colorSpace != ColorSpace_Gray,
                             "b" );
    var bView = b.mainView;

    bView.beginProcess(UndoFlag_NoSwapFile);
    doPixelMath(view,bView);
    bView.endProcess();

    b.close();
}

function doPixelMath(view,bView) {

    bView.image.apply(data.refView.image);

    var stats = new ImageStatistics;

    bView.image.selectedChannel = 0;
    stats.generate(bView.image);
    var medR = stats.median;

    bView.image.selectedChannel = 1;
    stats.generate(bView.image);
    var medG = stats.median;


    bView.image.selectedChannel = 2;
    stats.generate(bView.image);
    var medB = stats.median;

    var bn  = new PixelMath;

    var id = bView.id;

    if((medR<=medG) && (medR<=medB)) {
        with (bn) {
            expression  = "$target";
            expression1 = "$target - (Med("+id+") - Med("+id+"[0]))";
            expression2 = "$target - (Med("+id+") - Med("+id+"[0]))";
            useSingleExpression = false;
            variables = "";

            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    } else if (medG<=medB) {
        with (bn) {
            expression  = "$target - (Med("+id+") - Med("+id+"[1]))";
            expression1 = "$target";
            expression2 = "$target - (Med("+id+") - Med("+id+"[1]))";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    } else {
        with (bn) {
            expression  = "$target - (Med("+id+") - Med("+id+"[2]))";
            expression1 = "$target - (Med("+id+") - Med("+id+"[2]))";
            expression2 = "$target";
            useSingleExpression = false;
            variables = "";
            use64BitWorkingImage = false;
            rescale = true;
            rescaleLower = 0.0000000000;
            rescaleUpper = 1.0000000000;
            truncate = true;
            truncateLower = 0.0000000000;
            truncateUpper = 1.0000000000;
            createNewImage = false;
            newImageId = "";
            newImageWidth = 0;
            newImageHeight = 0;
            newImageColorSpace = RGB;
            newImageSampleFormat = SameAsTarget;
        }
    }

    bn.executeOn(view);
}

function getStats(image,x1,y1,x2,y2) {

    var stats = new ImageStatistics;

    var rect = new Rect;
    rect.width = x2-x1;
    rect.height = y2-y1;
   
    point = new Point(x1, y1);
    rect.moveTo(point);
    image.selectedRect = rect;


    image.selectedChannel = 0;
    stats.generate(image);
    var medR = stats.median;

    image.selectedChannel = 1;
    stats.generate(image);
    var medG = stats.median;


    image.selectedChannel = 2;
    stats.generate(image);
    var medB = stats.median;

    return (1.0/3.0)*(medR+medG+medB);
}

function findPoint(image,ref) {

    var x1 = 0;
    var y1 = 0;
    var x2 = image.width;
    var y2 = image.height;

    var find = false;

    while (!find) {
        var box1 = getStats(image,x1,y1,x2-0.5*(x2-x1),y2-0.5*(y2-y1));
        var box2 = getStats(image,x2-0.5*(x2-x1),y1,x2,y2-0.5*(y2-y1));
        var box3 = getStats(image,x1,y2-0.5*(x2-x1),x2-0.5*(x2-x1),y2);
        var box4 = getStats(image,x2-0.5*(x2-x1),y2-0.5*(y2-y1),x2,y2);
        var ref1 = Math.abs(ref-box1);
        var ref2 = Math.abs(ref-box2);
        var ref3 = Math.abs(ref-box3);
        var ref4 = Math.abs(ref-box4);

        if((ref1<ref2)&&(ref1<ref3)&&(ref1<ref4)) {
               x1 = x1;
               x2 = x2-0.5*(x2-x1);
               y1 = y1;
               y2 = y2-0.5*(y2-y1);
        }else if ((ref2<ref1)&&(ref2<ref3)&&(ref2<ref4)) {
               x1 = x2-0.5*(x2-x1);
               x2 = x1;
               y1 = y1;
               y2 = y2-0.5*(y2-y1);
        }else if ((ref3<ref1)&&(ref3<ref2)&&(ref3<ref4)) {
               x1 = x1;
               x2 = x2-0.5*(x2-x1);
               y1 = y2-0.5*(y2-y1);
               y2 = y1;
        } else {
               x1 = x2-0.5*(x2-x1);
               x2 = x2;
               y1 = y2-0.5*(y2-y1);
               y2 = y2;
        }

        if(Math.abs(x2-x1)<=10) find = true;
    }

    return new Point(x1,y1);
}

function doAll() {
    var view  = data.targetView;
    var value = getStats(view.image,0,0,view.image.width,view.image.height);
    var point = findPoint(view.image,value);

    if(data.isManual) doBnManual();
    else              doBnAuto(point);
}


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

   var emWidth = this.font.width( 'M' );
   var labelWidth1 = this.font.width( "Target image:" );

   this.helpLabel = new Label( this );
   this.helpLabel.frameStyle = FrameStyle_Box;
   this.helpLabel.margin = 4;
   this.helpLabel.wordWrapping = true;
   this.helpLabel.useRichText = true;
   this.helpLabel.text = "<b>Background Neutralization</b> - Script to neutralize the background. " +
                         " It can be used automatically or with a preview defined by the user.";

   this.targetImage_Label = new Label( this );
   this.targetImage_Label.text = "Target image:";
   this.targetImage_Label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
   this.targetImage_Label.minWidth = labelWidth1;

   this.targetImage_ViewList = new ViewList( this );
   this.targetImage_ViewList.minWidth = 300;
   this.targetImage_ViewList.getAll(); // include main views as well as previews
   this.targetImage_ViewList.currentView = data.targetView;
   this.targetImage_ViewList.toolTip = "Select the image to perform a wavelet decomposition.";
   this.targetImage_ViewList.onViewSelected = function( view )
   {
      data.targetView = view;
   };

   this.targetImage_Sizer = new HorizontalSizer;
   this.targetImage_Sizer.spacing = 4;
   this.targetImage_Sizer.add( this.targetImage_Label );
   this.targetImage_Sizer.add( this.targetImage_ViewList, 100 );
//////////////////

   this.previewId_Label = new Label( this );
   this.previewId_Label.text = "Reference Image :";
   this.previewId_Label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
   this.previewId_Label.minWidth = labelWidth1;

   this.previewId_ViewList = new ViewList( this );
   this.previewId_ViewList.minWidth = 300;
   this.previewId_ViewList.getAll(); // include main views as well as previews
   this.previewId_ViewList.enabled = data.isManual;
   this.previewId_ViewList.currentView = data.targetView;
   this.previewId_ViewList.toolTip = "Select the image to perform a wavelet decomposition.";
   this.previewId_ViewList.onViewSelected = function( view )
   {
      data.refView = view;
   };

   this.previewId_Sizer = new HorizontalSizer;
   this.previewId_Sizer.spacing = 4;
   this.previewId_Sizer.add( this.previewId_Label );
   this.previewId_Sizer.add( this.previewId_ViewList, 100 );

/////////////////
   this.typesOfModes_Label = new Label( this );
   this.typesOfModes_Label.text = "Mode :";
   this.typesOfModes_Label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
   this.typesOfModes_Label.minWidth = labelWidth1;

   this.typesOfModes_ComboBox = new ComboBox( this );
   for ( var i = 0; i < typesOfModes.length; ++i )
      this.typesOfModes_ComboBox.addItem( typesOfModes[i] );
   this.typesOfModes_ComboBox.currentItem = data.typesOfModes;
   this.typesOfModes_ComboBox.toolTip = "Select a method to perform the background neutralization.";
   this.typesOfModes_ComboBox.onItemSelected = function( index )
   {
      data.typesOfModes = index;
      if(index) data.isManual = true;
      else      data.isManual = false;
      this.dialog.previewId_ViewList.enabled = data.isManual;
   };

   this.typesOfModes_Sizer = new HorizontalSizer;
   this.typesOfModes_Sizer.spacing = 4;
   this.typesOfModes_Sizer.add( this.typesOfModes_Label );
   this.typesOfModes_Sizer.add( this.typesOfModes_ComboBox, 100 );
   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 );

   this.sizer = new VerticalSizer;
   this.sizer.margin = 6;
   this.sizer.spacing = 6;
   this.sizer.add( this.helpLabel );
   this.sizer.addSpacing( 4 );
   this.sizer.add( this.targetImage_Sizer );
   this.sizer.add( this.typesOfModes_Sizer );
   this.sizer.add( this.previewId_Sizer );
   this.sizer.add( this.buttons_Sizer );

   this.windowTitle = "Background Neutralization Script";
   this.adjustToContents();
   this.setFixedSize();
}

BackgroundNeutralizationDialog.prototype = new Dialog;

function main() {
    var dialog = new BackgroundNeutralizationDialog();
    var view = window.mainView;    
    dialog.view = view;
    if ( dialog.execute() ) {
        doAll();
    }
}

main();




Un saludo a todos  :wink:

Offline C. Sonnenstein

  • PixInsight Addict
  • ***
  • Posts: 262
    • http://astrosurf.com/astro35mm
Script de neutralizacion de background
« Reply #10 on: 2008 September 13 13:56:07 »
Quote
dejamos el codigo para la gente que le sea de utilidad
:P
Carlos Sonnenstein

Offline bosch

  • PixInsight Addict
  • ***
  • Posts: 123
Script de neutralizacion de background
« Reply #11 on: 2008 September 13 20:06:16 »
Pues  muchísimas gracias por la immensa currada.

Offline javier_laina

  • Newcomer
  • Posts: 28
    • http://www.javierlaina.es/indexeng.html
Script de neutralizacion de background
« Reply #12 on: 2008 September 14 01:42:07 »
Lo he probado y funciona muy bien.
Gracias.

Offline OriolLehmkuhl

  • PixInsight Addict
  • ***
  • Posts: 177
    • http://www.astrosurf.com/brego-sky
Script de neutralizacion de background
« Reply #13 on: 2008 September 15 05:57:35 »
Nos alegramos mucho que os sea de utilidad  :wink: si creeis que hay algo a mejorar por favor, no dudeis en decirlo, gracias  :)

Un saludo

Offline Jordi Gallego

  • PixInsight Addict
  • ***
  • Posts: 279
Script de neutralizacion de background
« Reply #14 on: 2008 September 15 11:48:11 »
Gracias por el script, lo habeis puesto justo en un momento en el que tenía que hacer varias pruebas de fondo del cielo y me ha venido muy bie!! :wink:

Saludos
Jordi
Jordi Gallego
www.astrophoto.es