Author Topic: How to act on a set of images in a single operation | Cómo actuar sobre un conjunto de imágenes en una única operación  (Read 38414 times)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
[Versión en Español al final]

Suppose you have generated a good bunch of working images, and you no longer need them. For example, you may have several background models generated with the DBE tool:

myImage_background
myImage_background1
myImage_background2
myImage_background3
...


and so on. It may be nasty having to close all of them by clicking their 'X' buttons, or by selecting File > Close for each one. Wouldn't it be nice being able to close all of them in a single and quick operation?

Of course, and as long as the images can be characterized by common parts it their identifiers (patterns), they can be closed very easily using PixInsight's console. Following the example above, we can enter this command on the Processing Console window:

Code: [Select]
close *background*

press Enter, and job done! note that this will close only those images whose identifiers include the word "background". For example:

backgroundTest
the_background


would be closed. However, since identifiers are case-sensitive in PixInsight, these wouldn't be closed:

TheBackground
myBackground


In a similar way, this is equivalent to the File > Close All command:

Code: [Select]
close *

Of course, close is just one command available on PixInsight's command line, but there are many more that you can use to speed up and simplify your workflow. Let's say that you want to convert all open images to the 32-bit floating point format:

Code: [Select]
f32 *

or rotate a set of images 90 degrees counter-clockwise:

Code: [Select]
r90 *_test

In the example above, only images whose identifiers end with "_test", as "the_test", "one_test", "nebula_test", and so on, would be rotated.

Who said that command lines are dead? Not in PixInsight!  8)




=====================================================================




Imagina que has generado un buen puñado de imágenes de trabajo, y ya no las necesitas. Por ejemplo, podrías haber generado varios modelos del fondo con la herramienta DBE:

myImage_background
myImage_background1
myImage_background2
myImage_background3
...


y puede que muchas más parecidas. Puede resultar tedioso tener que cerrarlas todas haciendo clic en sus botones 'X', o seleccionando File > Close para cada una de ellas. ¿No sería genial poder cerrarlas todas en una única operación sencilla?

Claro que sí, y de hecho, si podemos caracterizar las imágenes mediante partes en común en sus identificadores (patrones), las podemos cerrar muy fácilmente usando la consola de PixInsight. Continuando con el ejemplo de arriba, podemos introducir este comando en la ventana Processing Console:

Code: [Select]
close *background*

pulsar Intro, y ¡ya está! Tened en cuenta que esta orden cerrará sólo las imágenes cuyos identificadores contengan la palabra "background". Por ejemplo:

backgroundTest
the_background


se cerrarían. Sin embargo, como PixInsight diferencia entre mayúsculas y minúsculas en los identificadores de imagen, éstas no se cerrarían:

TheBackground
myBackground


De forma similar, esto es equivalente a la opción File > Close All del menú:

Code: [Select]
close *

Por supuesto, close es sólo uno de los comandos disponibles en la línea de comandos de PixInsight, pero hay muchos más que podéis usar para acelerar y simplificar vuestro trabajo. Digamos que queremos convertir todas las imágenes que tengamos abiertas al formato de punto flotante en 32 bits:

Code: [Select]
f32 *

o girar un conjunto de imágenes 90 grados en el sentido contrario a las agujas del reloj:

Code: [Select]
r90 *_test

En el ejemplo anterior, sólo las imágenes cuyos identificadores terminen con "_test", como "the_test", "one_test", "nebula_test", etc., serían giradas.

¿Quién dijo que las líneas de comandos estaban muertas? ¡No en PixInsight!  8)
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline ManoloL

  • PixInsight Addict
  • ***
  • Posts: 220
Hola Juan:

Me recuerda los "felices"  tiempos del MSDOS, donde uno sabía lo que estaba haciendo.
Desde que llego el Windows ya uno no sabe lo que la criatura hará.
Yo a consecuencia de esto abandoné la poca programación que era capaz de realizar. No fui capaz de reconvertirme.

Saludos.
Saludos.

Manolo L.

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Quote
Me recuerda los "felices" tiempos del MSDOS


Era divertido, sí. Todo era muchísimo más sencillo, aunque entonces no éramos conscientes. Hay muchas cosas que se echan de menos de cuando usábamos disquetes de 5 1/4, de cuando un disco de 100 MB era casi infinito, de la INT 21h y la INT 10h, ... :) Bueno, me callo, que parezco el abuelo cebolleta :lol:
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Quote from: "Juan Conejero"
Code: [Select]
close *


Ayer probé "save all", y en la ayuda de save no vi nada de esta clase de globbing (lo sabía de antemano, pero ayer no me acordaba). Estaría bien una mención aunque fuera así de pasada sin necesidad de profundizar, y aunque eso implicara repetir la misma historia en la ayuda de cada comando. En estas cosas pienso que es mejor repetir que omitir!
--
 David Serrano

Offline avastro

  • PixInsight Addict
  • ***
  • Posts: 181
    • http://astrosurf.com/avastro/
Hola,
Muy interessante estas liñas de comando para agilizar el processo, no lo conocia.

Antoine
Antoine
Lentin Observatory
http://www.astrosurf.com/avastro/

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
No, "save all" no está implementado. El comando save sólo guarda una imagen en cada invocación, o sea que no es posible hacer algo como "save *" porque no acepta listas de imágenes.

La verdad es que lo de "save all" es una muy buena idea, y no me explico cómo no se me ocurrió cuando escribí este comando... sería Lunes  :lol:
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Bueno, pero no vayas a implementar "save all", mejor "save *", que es más consistente! (y flexible además).
--
 David Serrano

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Quote
mejor "save *", que es más consistente! (y flexible además).


Cierto. La verdad es que quiero darle un buen impulso a la línea de comandos, que la tengo bastante abandonada (ya se sabe, tanto eye candy y eso...  :lol: ). Quiero añadir bastantes comandos nuevos e implementar funcionalidad en línea de comandos para muchos más procesos. ¡Se agradecen sugerencias!
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Quote from: "Juan Conejero"
¡Se agradecen sugerencias!


Para mí hay una sugerencia obvia, que probablemente ya hayas pensado:

Code: [Select]
./PixInsight script.scp image*.jpg

O sea, poder crear un script con comandos de estos (como el startup.scp) y pasárselo a Pixi de forma que lo ejecute sobre las imágenes especificadas. Esto en Unix tiene una ventaja directa, y es que el script a partir de ese momento puede tener shebang y ser ejecutable directamente:

Code: [Select]
$ cat > script.scp
#!/usr/bin/PixInsight

blah blah blah
^D
$ chmod 755 script.scp
$ ./script.scp image*.jpg


A partir de ahí, un interface para llamar a scripts JS desde la consola y así también se podría acceder a los JS desde la línea de comando de Unix, no sólo a los procesos PCL nativos.

Veo dos problemas principales: uno es el path al ejecutable, que tiene que ir a piñón en el script. Otro es que actualmente no se reconoce el carácter '#' como comentario, sino como otra cosa (pero se podría hacer una excepción para la primera línea del script, en plan de ignorarla si no es una directiva válida).
--
 David Serrano

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Esto es más que interesante. Es la lexe. Gracias gracias :)

Respecto del # una pregunta: ¿Funciona igual si ponemos dos seguidas en la primera línea, o sea ##? Lo digo porque de esta forma estaría solucionado. Bastaría con que la secuencia ## al principio de una línea fuera interpretada como //.

Si no, pues tampoco es ningún problema hacer la excepción de que # no se interprete como una directiva de preprocesador si está en la primera línea (no vacía) del script, sino como un comentario.

Respecto del path al ejecutable de PI, no veo mayor problema. Al fin y al cabo, eso pasa también con #!/bin/bash por ejemplo. No cuesta nada crear un enlace simbólico al ejecutable de PI en /bin o /usr/bin, por ejemplo, con lo cual asunto resuelto.

Por lo demás, no veo mayores problemas. La única modificación "importante" es que cuando PI encuentra un .scp o un .js en la línea de comandos lo que hace ahora es cargarlo en Script Editor. Habría que cambiar eso para que lo ejecutara directamente. Por otra parte, me parece bastante más lógico que sea así.

El tema de las imágenes es más complicado, pero tampoco mucho. Al invocar PI indirectamente de la forma que dices:

Code: [Select]
./script.scp *.jpg

o directamente, que es lo mismo:

Code: [Select]
./PixInsight script.scp *.jpg

va a ocurrir lo siguiente:

- PI se va a inicializar de la manera habitual, va a cargar los módulos y a desplegar toda la interfaz gráfica.

- PI va a cargar todas las imágenes *.jpg y las va a colocar en ventanas, de la forma habitual.

- Después va a ejecutar el script script.scp

Esto significa que no va a existir una relación directa entre las imágenes especificadas en línea de comandos y el script. El script tendría que hacer algo como:

Code: [Select]
var myImages = ImageWindow.wndows;

nada más empezar, para saber qué imágenes están abiertas, y procesarlas.

Entonces falta algo para que este tinglado funcione como se espera, ¿no? Porque cuando el script termine, PI seguirá abierto normalmente. Esto no es lo que se supone que tendría que pasar.

Podríamos añadir un método al PJSR (no sé muy bien dónde) para que un script pueda terminar la ejecución de PI. Por supuesto, esto no sirve:

Code: [Select]
Console.execute( "exit" );

porque requiere permisos para ejecutar comandos desde un script, lo cual es un problema de seguridad (por defecto está desactivado).

Hmmm, esto tiene muy buena pinta. ¿Cómo lo ves?
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Quote from: "Juan Conejero"
Respecto del # una pregunta: ¿Funciona igual si ponemos dos seguidas en la primera línea, o sea ##?


No. Cuando ejecutas un script, es el núcleo quien mira si empieza por "#!" y, de ser así, ejecuta lo que haya a continuación y le pasa como parámetros el nombre del script que estamos ejecutando y los parámetros que nosotros hayamos puesto. Esto es del núcleo:

Code: [Select]
static int load_script( [...] )
{
    [...]

    if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang))
        return -ENOEXEC;




Quote from: "Juan Conejero"
Si no, pues tampoco es ningún problema hacer la excepción de que # no se interprete como una directiva de preprocesador si está en la primera línea (no vacía) del script, sino como un comentario.


Confirmo lo de "no vacía". Pensé que el núcleo miraba los dos primeros bytes absolutos del archivo, pero una prueba rápida me confirma que no es así y que es lo suficientemente listo como para saltarse líneas en blanco al principio. Bienvenidos al siglo 0x15 ;)


Quote from: "Juan Conejero"
Respecto del path al ejecutable de PI, no veo mayor problema. Al fin y al cabo, eso pasa también con #!/bin/bash por ejemplo. No cuesta nada crear un enlace simbólico al ejecutable de PI en /bin o /usr/bin, por ejemplo, con lo cual asunto resuelto.


Ya hombre, pero eso complica la instalación, que ahora mismo se efectúa totalmente como usuario.


Con respecto al workflow en general, mi idea era que no se lanzara el interface gráfico en absoluto (o como máximo, una barra de progreso o algo así, ya que esto tiene potencial para durar bastante tiempo) y que al acabar el script, las imágenes aparecieran mágicamente modificadas en el filesystem (ya sea sobreescritas o con copia).

Me confunde esto:

Quote from: "Juan Conejero"
El script tendría que hacer algo como:

Code: [Select]
var myImages = ImageWindow.wndows;

nada más empezar, para saber qué imágenes están abiertas, y procesarlas.


Pero eso es sintaxis JS, no de consola ¿verdad? En consola habría que habilitar un mínimo parsing de comandos, o simplemente planchar todo en el típico ARGV y que cada script hiciera su propio parsing (hmmm... código reutilizable == bibliotecas... ;)). Sobre JS hablo más abajo.


Quote from: "Juan Conejero"
Entonces falta algo para que este tinglado funcione como se espera, ¿no? Porque cuando el script termine, PI seguirá abierto normalmente. Esto no es lo que se supone que tendría que pasar.


Claro. Pixi tendría que saber que se está ejecutando "en modo batch" y salir cuando el script terminase. O cuando el usuario hiciera click en algún botón "Cancel" que aparecería junto a la barra de progreso.


Quote from: "Juan Conejero"
Podríamos añadir un método al PJSR (no sé muy bien dónde) para que un script pueda terminar la ejecución de PI. Por supuesto, esto no sirve:

Code: [Select]
Console.execute( "exit" );

porque requiere permisos para ejecutar comandos desde un script, lo cual es un problema de seguridad (por defecto está desactivado).


Mi idea era que los scripts JS apenas fueran diferenciables de los procesos PCL, al menos desde el punto de vista de los scripts de consola. Así pues, dado que la ayuda de (por ejemplo) ACDNR es así:

Code: [Select]
Usage: ACDNR [<arg_list>] [<view_list>]

Argument suffix selects parameter set: L=luminance, C=chrominance.

When no suffix is used, arguments apply to both luminance and chrominance,
as applicable.

-L[+|-] | -applyL[+|-]
<blah blah blah>


la ayuda de un script JS podría ser similar:

Code: [Select]
Usage: MST.js [<arg_list>] [<view_list>]

<contenido de #feature-info, por ejemplo>

<parámetros blah blah>


y el script JS no se tiene que preocupar de cerrar Pixi, de la misma forma que ACDNR tampoco lo hace. Lo que sí añadiría al motor de JS es un "entry point", que sería la función que se ejecuta por defecto cuando se le llama desde la consola. Podría ser el obvio "main". Habrá que modificar los scripts existentes para que acepten como parámetros de main las imágenes sobre las que trabajar, en lugar de ir a ImageWindow a buscarlas. Esto me huele que no te va a encajar bien con la filosofía de Pixi ;).

Y, totalmente aparte de toda esta conversación, yo cambiaría la sintaxis '!grep' por 'system (grep)' y eliminaría el bang. Es lo mismo que el "save all", por consistencia nada más, y también porque es mucho más díficil ejecutar comandos por error usando system que con un simple bang.
--
 David Serrano

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Todo esto necesita una buena digestión por mi parte. Espera, que voy a por Almax... :lol:

Cuando la primera línea no vacía de un script, descartando todos los caracteres trimables a la izquierda, empiece por la secuencia #! PI la ignorará completamente.

Quote
Con respecto al workflow en general, mi idea era que no se lanzara el interface gráfico en absoluto


Correcto. Pero yo lo dejaría como una opción; es decir, añadiría un parámetro que permitiera forzar la entrada del GUI, o tal vez incluso invocable desde .scp. Sólo porque así lo hacemos más flexible. Por la misma razón, también añadiría un método a PJSR para que un script JS pueda forzar la entrada del GUI.

Una cosa al margen. En realidad, todo el GUI se va a generar igual que en ejecución normal, sólo que la ventana principal de la aplicación no va a ser visible. En una aplicación como PI, el GUI está demasiado imbricado con todo y por todas partes; hay muchas cosas que dependen directamente de elementos de la interfaz, que tienen que existir y funcionar.

Todo esto puede dar problemas múltiples y en múltiples momentos. ¿No es maravilloso?  8)

Quote
y que al acabar el script, las imágenes aparecieran mágicamente modificadas en el filesystem (ya sea sobreescritas o con copia).


Ufff. Eso es complejo/difícil/peligroso/<añada_usted_algo_chungo>. Eso hay que pensarlo muy bien, y certamente rompe con muchos esquemas existentes. Hala, a darle al coco...

Quote
Me confunde esto:


Sí, claro, me dejé llevar por la emoción :) Habría que añadir cosas similares a .scp, o una interfaz con argc/argv como tú decías (mira que eres clásico, tío ;) ).

Quote
Mi idea era que los scripts JS apenas fueran diferenciables de los procesos PCL, al menos desde el punto de vista de los scripts de consola.


Se puede implementar mediante más directivas del tipo #feature. Podría ser un grupo de directivas #batch por ejemplo.

Quote
Habrá que modificar los scripts existentes para que acepten como parámetros de main las imágenes sobre las que trabajar, en lugar de ir a ImageWindow a buscarlas. Esto me huele que no te va a encajar bien con la filosofía de Pixi


No te preocupes por eso :) Yo soy muy borde (con b) con mi propio código...

Quote
yo cambiaría la sintaxis '!grep' por 'system (grep)' y eliminaría el bang.


Yo pondría system como opción, aparte de bang. El bang me gusta (y system también).
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Quote from: "Juan Conejero"
Cuando la primera línea no vacía de un script, descartando todos los caracteres trimables a la izquierda, empiece por la secuencia #! PI la ignorará completamente.


Bueno, rectificar es de sabios, dicen. Realmente antes lo dije mal adrede para que ahora me pueda autoproclamar sabio xD. Antes hice la prueba con un script de shell, y el núcleo funcionó como yo esperaba, lo que me indujo a pensar que el núcleo era sabio y listo y que habíamos entrado por fin en el siglo 0x15. No es así, ahora he probado con un script de Perl y es sencillo: el núcleo mira los dos primeros bytes absolutos del archivo. Si consigue parsear un intérprete, lo llama y listos. De lo contrario, llama a /bin/sh (por eso me funcionó en la primera prueba). Por tanto, si PixInsight se ejecuta y ve un script es que el núcleo ha detectado bien un intérprete, y el script empieza por '#!' sin nada más antes.


Quote from: "Juan Conejero"
Quote
Con respecto al workflow en general, mi idea era que no se lanzara el interface gráfico en absoluto


Correcto. Pero yo lo dejaría como una opción


Sí, yo también lo pensaba. Siempre opciones :^).


Quote from: "Juan Conejero"
Una cosa al margen. En realidad, todo el GUI se va a generar igual que en ejecución normal, sólo que la ventana principal de la aplicación no va a ser visible. [...] Todo esto puede dar problemas múltiples y en múltiples momentos. ¿No es maravilloso?  8)


Lo de "se genera pero no es visible" también era evidente. Pero eso de que pueda dar errores sólo porque el GUI no se ve... hmmm... no me dice mucho a favor de Qt o de lo que sea. Y no te veas tentado por la chapucilla de "Bueno, pues dibujo la ventana en las coordenadas 1e5 x 1e5 y listos" porque algunos sistemas "avanzados" permiten configurar una opción según la cual nunca se mostrarán ventanas fuera del escritorio visible ;).


Quote from: "Juan Conejero"
Quote
y que al acabar el script, las imágenes aparecieran mágicamente modificadas en el filesystem (ya sea sobreescritas o con copia).


Ufff. Eso es complejo/difícil/peligroso/<añada_usted_algo_chungo>. Eso hay que pensarlo muy bien, y certamente rompe con muchos esquemas existentes. Hala, a darle al coco...


No veo el peligro, quizá no nos hemos entendido. Yo me refería a que "al acabar el script de consola, las imágenes aparecen desde el punto de vista del usuario mágicamente modificadas en el filesystem". El script de consola recibe las imágenes como sea, llama a los procesos PCL y JS que crea convenientes y al final ejecutaría una serie de comandos 'save' para guardar los resultados. No es más peligroso que un usuario que hace un shell script por su cuenta; obviamente él no va a hacer un 'rm -rf *'.

Y si un usuario ejecuta ciegamente un script de consola que ha recibido por correo, merece el mismo premio que si ejecuta ciegamente un shell script que ha recibido por correo.

Inciso, quizá ya un poco offtopic en este hilo: estos archivos .scp funcionarían prácticamente como un .psm pero con más flexibilidad. Propongo también que sea posible './PixInsight foobar.psm *.jpg'. O también con una sintaxis más explícita en ambos casos: './PixInsight --run [ file.scp | file.psm ] images*.jpg'.
--
 David Serrano

Offline Nocturnal

  • PixInsight Jedi Council Member
  • *******
  • Posts: 2727
    • http://www.carpephoton.com
Well the beginning of the thread was interesting.
Best,

    Sander
---
Edge HD 1100
QHY-8 for imaging, IMG0H mono for guiding, video cameras for occulations
ASI224, QHY5L-IIc
HyperStar3
WO-M110ED+FR-III/TRF-2008
Takahashi EM-400
PIxInsight, DeepSkyStacker, PHD, Nebulosity

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Quote from: "Nocturnal"
Well the beginning of the thread was interesting.


Just a matter of perception... for me, the end of the thread is interesting! xD.

It's some brain dumping about possible new features of PixInsight regarding automation via the ProcessingConsole.
--
 David Serrano