Syril et PySiril : étude de performance

Résumons : il y a donc 5 manières de faire exécuter une séquence de commandes sous Siril :

  1. Exécuter les commandes via la souris et les fonctions graphiques présentées
  2. Exécuter les commandes en mode « ligne de commande »
  3. Exécuter les commandes incluses via un script (fichier texte avec commandes)
  4. Exécuter les commandes sous Python en mode « ligne de commande »
  5. Exécuter les commandes sous Python en mode « appel wrapper » (objet)

Comme c’est l’automatisation qui m’intéresse, on va se focaliser sur les deux derniers modes, mais en validant que les actions précédemment exécutées en mode « graphique » s’exécutent correctement en mode programmé.

Il va falloir tester les avantages inconvénients de chaque mode dans des cas pratiques…

Pré-traitement des images

Il existe des scripts standard (tel que « OSC_Preprocessing »), fort utilisé par ceux qui prétraite les images déposées dans des sub-dirs dédiées…

Comme mon utilisation est fort axée « Evscope » actuellement, j’aimerai bien l’adapter à mes besoins… Mais il faut d’abord comprendre !

Exemple pratique : je dispose d’une sub-dir contenant 3 bias (offset) et 3 dark issu d’un APN (format .cr2). Je désire obtenir un master bias.
Quelles sont les actions à faire ?

Master bias

  • convertir les images vers fits
  • les empiler en mode rejet, sans normalisation

En mode « graphique »

Les commandes sont activées via des actions de type « pointer/cliquer », avec des séquences qui sont déterminées par le but à atteindre…
Voici le log des opérations pour la création du master bias (deux commandes : conversion et empilement)

19:26:10: Définir le répertoire de travail à 'E:\siril\NoiseStudyCanon550D\process'
19:26:39: Conversion : traitement de 3 fichiers …
19:26:40: Décode Canon EOS 550D file (ISO=400, Exposition=1/4000.0 sec)
19:26:40: Motif du Filtre : GBRG
19:26:40: Lecture du fichier RAW : 550D_bias_iso400.CR2, 1 canal(aux), 5202x3464 pixels
19:26:40: Nombre d'images autorisées dans la file d'attente d'écriture : 17 (zéro ou moins = illimité)
19:26:40: Décode Canon EOS 550D file (ISO=100, Exposition=1/4000.0 sec)
19:26:40: Motif du Filtre : GBRG
19:26:40: Fichier FITS enregistré : fichier bias_00003.fit, 1 canal(aux), 5202x3464 pixels
19:26:40: Lecture du fichier RAW : 550D_bias_iso100.CR2, 1 canal(aux), 5202x3464 pixels
19:26:40: Décode Canon EOS 550D file (ISO=200, Exposition=1/4000.0 sec)
19:26:40: Motif du Filtre : GBRG
19:26:40: Lecture du fichier RAW : 550D_bias_iso200.CR2, 1 canal(aux), 5202x3464 pixels
19:26:40: Fichier FITS enregistré : fichier bias_00001.fit, 1 canal(aux), 5202x3464 pixels
19:26:40: Fichier FITS enregistré : fichier bias_00002.fit, 1 canal(aux), 5202x3464 pixels
19:26:40: La conversion a réussi, 3 fichier(s) créé(s) pour 3 fichier(s) d'entrée (3 image(s) convertie(s), 0 échec)
19:26:40: Lecture du fichier FITS : bias_00001.fit, 1 canal(aux), 5202x3464 pixels
19:26:40: Séquence chargée : bias_ (1->3)
19:26:40: Temps d'exécution: 1.13 s.
19:27:54: L'empilement utilise les données d'alignement du canal 0 si elles existent.
19:27:54: Empilement : en cours…
19:27:54: Traitement de toutes les images de la séquence (3)
19:27:54: Utilisation de 6575 Mo maximum pour l'empilement
19:27:54: Nous avons 8 blocs parallèles de taille 433 (+0) pour l'empilement.
19:27:54: Débute l'empilement…
19:27:54: Rejet des pixels dans le canal #0 : 0.000% - 0.000%
19:27:54: Empilement avec rejet fini. 3 images ont été empilées.
19:27:54: Intégration de 3 images :
19:27:54: Combinaison …………… moyenne
19:27:54: Normalisation …………. aucune
19:27:54: Rejet des pixels ………. Test de déviation extrême généralisé de Student
19:27:54: Estimation du bruit (canal : #0) : 3.941 (6.013e-05)
19:27:54: Fichier FITS enregistré : fichier bias_stacked.fit, 1 canal(aux), 5202x3464 pixels
19:27:54: Temps d'exécution: 333.64 ms.

Les statistiques de l’image obtenues (commande stat) :

Canal B&W : Moyenne : 2048.6, Médiane : 2049.0, Sigma : 4.0, AvgDev : 3.1, Min : 1989.0, Max : 3537.0

Deux remarques importantes :
– la conversion de RAW > fits s’effectue ici avec une grille Bayer de type « GBRG », ce qui est le mode par défaut (pour RAW) définis dans les « préférences » de Siril…
– en finale, trois bias_nnnnnn, un bias_stacked.fit et un bias.seq sont produits

En mode « ligne de commande »

On parle ici de l’utilisation de la commande « convert » et « stack »…
En considérant que la sub-dir est déjà « pointée » au niveau Siril, il suffit de les exécuter :

cd ../bias
20:47:08: Exécution de la commande : cd
20:47:08: Définir le répertoire de travail à 'E:\siril\NoiseStudyCanon550D\bias'
convert bias -out=../process
21:21:24: Exécution de la commande : convert
21:21:24: Conversion : traitement de 3 fichiers …
21:21:24: Décode Canon EOS 550D file (ISO=200, Exposition=1/4000.0 sec)
21:21:24: Motif du Filtre : GBRG
21:21:24: Lecture du fichier RAW : 550D_bias_iso200.CR2, 1 canal(aux), 5202x3464 pixels
21:21:24: Nombre d'images autorisées dans la file d'attente d'écriture : 17 (zéro ou moins = illimité)
21:21:24: Décode Canon EOS 550D file (ISO=400, Exposition=1/4000.0 sec)
21:21:24: Motif du Filtre : GBRG
21:21:24: Fichier FITS enregistré : fichier ../process\bias_00002.fit, 1 canal(aux), 5202x3464 pixels
21:21:24: Lecture du fichier RAW : 550D_bias_iso400.CR2, 1 canal(aux), 5202x3464 pixels
21:21:24: Décode Canon EOS 550D file (ISO=100, Exposition=1/4000.0 sec)
21:21:24: Motif du Filtre : GBRG
21:21:24: Lecture du fichier RAW : 550D_bias_iso100.CR2, 1 canal(aux), 5202x3464 pixels
21:21:24: Fichier FITS enregistré : fichier ../process\bias_00003.fit, 1 canal(aux), 5202x3464 pixels
21:21:24: Fichier FITS enregistré : fichier ../process\bias_00001.fit, 1 canal(aux), 5202x3464 pixels
21:21:25: La conversion a réussi, 3 fichier(s) créé(s) pour 3 fichier(s) d'entrée (3 image(s) convertie(s), 0 échec)
21:21:25: Aucune séquence trouvée, vérifiez le répertoire de travail ou modifiez l'extension FITS dans les paramètres (actuellement .fit)
21:21:25: Temps d'exécution: 716.93 ms.

Puis

cd ../process
21:33:43: Exécution de la commande : cd
21:33:43: Définir le répertoire de travail à 'E:\siril\NoiseStudyCanon550D\process'

stack bias rej 3 3 -nonorm
21:34:32: Exécution de la commande : stack
21:34:32: Empile la séquence bias_
21:34:32: Traitement de toutes les images de la séquence (3)
21:34:32: Utilisation de 6763 Mo maximum pour l'empilement
21:34:32: Nous avons 8 blocs parallèles de taille 433 (+0) pour l'empilement.
21:34:32: Débute l'empilement…
21:34:32: Rejet des pixels dans le canal #0 : 0.000% - 0.000%
21:34:32: Empilement avec rejet fini. 3 images ont été empilées.
21:34:32: Intégration de 3 images :
21:34:32: Combinaison …………… moyenne
21:34:32: Normalisation …………. aucune
21:34:32: Rejet des pixels ………. Winsorized Sigma Clipping
21:34:32: Paramètres de rejet ……. bas=3.000 haut=3.000
21:34:32: Estimation du bruit (canal : #0) : 3.941 (6.013e-05)
21:34:33: Fichier FITS enregistré : fichier bias_stacked.fit, 1 canal(aux), 5202x3464 pixels
21:34:33: Séquence empilée avec succès.
21:34:33: Temps d'exécution: 900.68 ms.

Et on arrive au même résultat
Canal B&W : Moyenne : 2048.6, Médiane : 2049.0, Sigma : 4.0, AvgDev : 3.1, Min : 1989.0, Max : 3537.0

En mode « Python »

Il y a deux méthodes pour faire exécuter les commandes depuis PySiril :

SYNTAXE 1 : via l’exécution d’une commande « comme tapée via la ligne de commande« 

ex : app.Execute(“convert basename [-debayer] [-start=index] [-out=] [-fitseq] [-ser]”)

Dans ce mode, la syntaxe (et le mode fonctionnement interne) des commandes est celle publiée dans la documentation officielle

SYNTAXE 2 : via l’implémentation des commandes dans une instance de PySiril, et une autre expression des paramètres.
ex : status=app.convert(basename,[debayer=True] [start=index] [out=filename] [fitseq=True] [ser=True])

La documentation disponible étant parcellaire, j’ai extrait la documentation des fonctions disponibles

Mais lors de l’appel, on remarque des différences de paramètres…
Commençons par construire une fonction « de base » de traitement d’images bias et voyons l’exécution dans les deux modes…

Syntaxe 1 : via commande Siril standard (ou execute)
def master_bias_execute(bias_dir, process_dir,
                bias_name='bias', slow='3',shigh='3',norm='-nonorm',stacktype='rej'):
    app.Execute("cd " + bias_dir)
    app.Execute("convert " + bias_name + " -out=" + process_dir)
    app.Execute("cd " + process_dir)
    app.Execute("stack "+ bias_name 
                + " " + stacktype 
                + " " + slow 
                + " " + shigh 
                + " " + norm)
Syntaxe 2 : via commande cmd.
def master_bias_cmd(bias_dir, process_dir, 
                bias_name='bias', slow=3,shigh=3,norm='no',stacktype='rej'):
    #Stack for bias with rejection sigma(3.3) and no normalisation
    #result stored in current process dir, name = bias_stacked
    cmd.cd(bias_dir )
    #Convert any present image to fits
    cmd.convert( bias_name, out=process_dir, 
                debayer=false, start=1, fitseq=False)
    cmd.cd( process_dir )
    cmd.stack( bias_name, type=stacktype, 
              sigma_low=slow, sigma_high=shigh, norm=norm)

Pour rendre la fonction universelle, je préfère laisser la possibilité à chacun de nommer « ses » images. Par défaut, cela sera « bias » (influence littérature anglaise) et lors de l’appel, on peut aisément modifier le nom pour ses besoins.

De même tous les paramètres d’empilement sont accessibles.
Ici, cela n’a pas beaucoup d’influence, mais dans les autres cas, on pourra largement utiliser cette possibilité.

Mise en pratique

# -*- coding: utf-8 -*-
"""
Created on Sun Apr  3 23:08:28 2022

@author: TTFonWeb
"""
import sys
import os

from pysiril.siril   import *
from pysiril.wrapper import *

#Define basic standard functions with variable origin

#build bias files, base function
def master_bias_cmd(bias_dir, process_dir, 
                bias_name='bias', slow=3,shigh=3,norm='no',stacktype='rej'):
    #Stack for bias with rejection sigma(3.3) and no normalisation
    #result stored in current process dir, name = bias_stacked
    cmd.cd(bias_dir )
    #Convert any present image to fits
    cmd.convert( bias_name, out=process_dir, 
                debayer=false, start=1, fitseq=False)
    cmd.cd( process_dir )
    cmd.stack( bias_name, type=stacktype, 
              sigma_low=slow, sigma_high=shigh, norm=norm)

def master_bias_execute(bias_dir, process_dir,
                bias_name='bias', slow='3',shigh='3',norm='-nonorm',stacktype='rej'):
    app.Execute("cd " + bias_dir)
    app.Execute("convert " + bias_name + " -out=" + process_dir)
    app.Execute("cd " + process_dir)
    app.Execute("stack "+ bias_name 
                + " " + stacktype 
                + " " + slow 
                + " " + shigh 
                + " " + norm)
    
# ============================================================================== 
# init call to Siril
app=Siril()       

try:
    cmd=Wrapper(app)    #open wrapper
    app.Open()          #open Siril

    #Set preferences
    workdir  = "E:\\siril\\NoiseStudyCanon550D"
    processdir = workdir + '\\process'
    
    if not os.path.isdir(workdir):
        print('The directory : '+ work_dir + ' is not present')
    else:
        if not os.path.isdir(processdir):
            print('The directory : '+ processdir + ' is not present. Creating a new one..')
            os.mkdir(processdir)
        
        cmd.set16bits()
        cmd.setext('fit')
    
        #Prepare master frames
        #master_bias_cmd(workdir+ '\\Bias' ,processdir)
        master_bias_execute(workdir+ '\\Bias' ,processdir)
    
except Exception as e :
    print("\n**** ERROR *** " +  str(e) + "\n" )    

#Close Siril, delete Siril instance
app.Close()
del app

Via l’usage de commentaires, on va déclencher les commandes en deux temps. Une fois lancé, les messages générés par les fonctions de Pysiril permettent de suivre le processus…

Exécution en mode « execute »…

WARNING: pysiril utilise par défaut:C:/Program Files/SiriL/bin/siril.exe
INFO : VERSION siril 1.0.0 :
INFO : Siril est compatible avec pySiril
INFO : Initialisation pySiril V0.0.12 : OK
INFO : Première étape: Démarrage 'Siril -p' ….
INFO : ThreadSiril est démarré
INFO : run : C:/Program Files/SiriL/bin/siril.exe -p
INFO : attendre:
7s
INFO : Seconde étape: Démarrage pipe reader ….
INFO : ThreadReader est démarré
INFO : Troisième étape: Démarrage pipe writer ….
INFO : PipeWriter est démarré
INFO : Open()
set16bits
: log: Exécution de la commande : set16bits
: log: Le mode de traitement d'image 16 bits par canal est activé
[status: success]
setext fit
: log: Exécution de la commande : setext
[status: success]
cd E:\siril\NoiseStudyCanon550D\Bias
: log: Exécution de la commande : cd
: log: Définir le répertoire de travail à 'E:\siril\NoiseStudyCanon550D\Bias'
[status: success]
convert bias -out=E:\siril\NoiseStudyCanon550D\process
: log: Exécution de la commande : convert
: log: Conversion : traitement de 3 fichiers …
: log: Décode Canon EOS 550D file (ISO=100, Exposition=1/4000.0 sec)
: log: Motif du Filtre : GBRG
: log: Lecture du fichier RAW : 550D_bias_iso100.CR2, 1 canal(aux), 5202x3464 pixels
: log: Nombre d'images autorisées dans la file d'attente d'écriture : 17 (zéro ou moins = illimité)
: log: Décode Canon EOS 550D file (ISO=400, Exposition=1/4000.0 sec)
: log: Motif du Filtre : GBRG
: log: Décode Canon EOS 550D file (ISO=200, Exposition=1/4000.0 sec)
: log: Motif du Filtre : GBRG
: log: Lecture du fichier RAW : 550D_bias_iso400.CR2, 1 canal(aux), 5202x3464 pixels
: log: Lecture du fichier RAW : 550D_bias_iso200.CR2, 1 canal(aux), 5202x3464 pixels
: log: Fichier FITS enregistré : fichier E:\siril\NoiseStudyCanon550D\process\bias_00001.fit, 1 canal(aux), 5202x3464 pixels
: log: Fichier FITS enregistré : fichier E:\siril\NoiseStudyCanon550D\process\bias_00003.fit, 1 canal(aux), 5202x3464 pixels
: log: Fichier FITS enregistré : fichier E:\siril\NoiseStudyCanon550D\process\bias_00002.fit, 1 canal(aux), 5202x3464 pixels
: log: La conversion a réussi, 3 fichier(s) créé(s) pour 3 fichier(s) d'entrée (3 image(s) convertie(s), 0 échec)
[status: success]
cd E:\siril\NoiseStudyCanon550D\process
: log: Exécution de la commande : cd
: log: Définir le répertoire de travail à 'E:\siril\NoiseStudyCanon550D\process'
[status: success]
stack bias rej 3 3 -nonorm
: log: Exécution de la commande : stack
: log: Empile la séquence bias_
: log: Traitement de toutes les images de la séquence (3)
: log: Utilisation de 6359 Mo maximum pour l'empilement
: log: Nous avons 8 blocs parallèles de taille 433 (+0) pour l'empilement.
: log: Débute l'empilement…
: prog
: ress: 54.01%
: prog
: ress: 88.63%
: log: Rejet des pixels dans le canal #0 : 0.000% - 0.000%
: log: Empilement avec rejet fini. 3 images ont été empilées.
: log: Intégration de 3 images :
: log: Combinaison …………… moyenne
: log: Normalisation …………. aucune
: log: Rejet des pixels ………. Winsorized Sigma Clipping
: log: Paramètres de rejet ……. bas=3.000 haut=3.000
: log: Estimation du bruit (canal : #0) : 3.941 (6.013e-05)
: log: Fichier FITS enregistré : fichier bias_stacked.fit, 1 canal(aux), 5202x3464 pixels
: log: Séquence empilée avec succès.
: log: Temps d'exécution: 473.88 ms.
[status: success]
INFO : Arrêt ThreadReader …
INFO : Arrêt PipeWriter …
INFO : ThreadReader est abandonné
INFO : ThreadReader est arrêté
INFO : ThreadSiril est arrêté
INFO : PipeWriter est arrêté
INFO : Close()
Stopping Trace …
Trace is stopped

Les statistiques de l’image sont identiques au mode « ligne »
Canal B&W : Moyenne : 2048.6, Médiane : 2049.0, Sigma : 4.0, AvgDev : 3.1, Min : 1989.0, Max : 3537.0

Maintenant, en mode « cmd »

WARNING: pysiril utilise par défaut:C:/Program Files/SiriL/bin/siril.exe
INFO : VERSION siril 1.0.0 :
INFO : Siril est compatible avec pySiril
INFO : Initialisation pySiril V0.0.12 : OK
INFO : Première étape: Démarrage 'Siril -p' ….
INFO : ThreadSiril est démarré
INFO : run : C:/Program Files/SiriL/bin/siril.exe -p
INFO : attendre:
7s
INFO : Seconde étape: Démarrage pipe reader ….
INFO : ThreadReader est démarré
INFO : Troisième étape: Démarrage pipe writer ….
INFO : PipeWriter est démarré
INFO : Open()
set16bits
: log: Exécution de la commande : set16bits
: log: Le mode de traitement d'image 16 bits par canal est activé
[status: success]
setext fit
: log: Exécution de la commande : setext
[status: success]
cd 'E:/siril/NoiseStudyCanon550D/Bias'
: log: Exécution de la commande : cd
: log: Définir le répertoire de travail à 'E:/siril/NoiseStudyCanon550D/Bias'
[status: success]
convert bias -start=1 -out=E:/siril/NoiseStudyCanon550D/process
: log: Exécution de la commande : convert
: log: Conversion : traitement de 3 fichiers …
: log: Décode Canon EOS 550D file (ISO=400, Exposition=1/4000.0 sec)
: log: Motif du Filtre : GBRG
: log: Lecture du fichier RAW : 550D_bias_iso400.CR2, 1 canal(aux), 5202x3464 pixels
: log: Nombre d'images autorisées dans la file d'attente d'écriture : 17 (zéro ou moins = illimité)
: log: Décode Canon EOS 550D file (ISO=100, Exposition=1/4000.0 sec)
: log: Motif du Filtre : GBRG
: log: Lecture du fichier RAW : 550D_bias_iso100.CR2, 1 canal(aux), 5202x3464 pixels
: log: Décode Canon EOS 550D file (ISO=200, Exposition=1/4000.0 sec)
: log: Motif du Filtre : GBRG
: log: Lecture du fichier RAW : 550D_bias_iso200.CR2, 1 canal(aux), 5202x3464 pixels
: log: Fichier FITS enregistré : fichier E:/siril/NoiseStudyCanon550D/process\bias_00003.fit, 1 canal(aux), 5202x3464 pixels
: log: Fichier FITS enregistré : fichier E:/siril/NoiseStudyCanon550D/process\bias_00001.fit, 1 canal(aux), 5202x3464 pixels
: log: Fichier FITS enregistré : fichier E:/siril/NoiseStudyCanon550D/process\bias_00002.fit, 1 canal(aux), 5202x3464 pixels
: log: La conversion a réussi,
: 3 fichier(s) créé(s) pour 3 fichier(s) d'entrée (3 image(s) convertie(s), 0 échec)
[status: success]
cd 'E:/siril/NoiseStudyCanon550D/process'
: log: Exécution de la commande : cd
: log: Définir le répertoire de travail à 'E:/siril/NoiseStudyCanon550D/process'
[status: success]
stack bias rej 3 3 -nonorm
: log: Exécution de la commande : stack
: log: Empile la séquence bias_
: log: Traitement de toutes les images de la séquence (3)
: log: Utilisation de 6588 Mo maximum pour l'empilement
: log: Nous avons 8 blocs parallèles de taille 433 (+0) pour l'empilement.
: log: Débute l'empilement…
: 17.54%
: prog
: ress: 48.47%
: prog
: ress: 83.55%
: log: Rejet des pixels dans le canal #0 : 0.000% - 0.000%
: log: Empilement avec rejet fini. 3 images ont été empilées.
: log: Intégration de 3 images :
: log: Combinaison …………… moyenne
: log: Normalisation …………. aucune
: log: Rejet des pixels ………. Winsorized Sigma Clipping
: log: Paramètres de rejet ……. bas=3.000 haut=3.000
: log: Estimation du bruit (canal : #0) : 3.941 (6.013e-05)
: log: Fichier FITS enregistré : fichier bias_stacked.fit, 1 canal(aux), 5202x3464 pixels
: log: Séquence empilée avec succès.
: log: Temps d'exécution: 479.93 ms.
[status: success]
INFO : Arrêt ThreadReader …
INFO : Arrêt PipeWriter …
INFO : ThreadReader est abandonné
INFO : ThreadReader est arrêté
INFO : ThreadSiril est arrêté
INFO : PipeWriter est arrêté
INFO : Close()
Stopping Trace …
Trace is stopped

Mission remplie : dans les 4 cas, l’image bias finale est identique

Mais un seul aspect est fort variable : le temps d’exécution !

Mode graphique : 1130 ms + 333.64 ms = 1463.64 ms
Mode ligne : 716.93 ms. + 900.68 ms = 1617.61 ms
Mode python « execute » : 473.88 ms
Mode python « cmd » : 479.93 ms

Conclusion : le mode « Python » est de l’ordre de 4x plus rapide que les autres modes. Et donc : fort intéressant pour le traitement des images en poses courtes.