Starnet++ et Siril

Par Fred Denjean

Ce tutoriel a pour but de présenter un script python permettant d’interfacer Starnet++ et Siril. Cet outil répond aux besoins des utilisateurs de pouvoir manipuler des images issues de starnet++ avec Siril et surtout Pixel Math.

Pourquoi ce script

Les images issues du prétraitement Siril sont au format standard FITS/32bit. Or, les images utilisables par Starnet++ doivent être au format TIFF/16bit. Il faut donc les convertir. De même, les images en sortie de Starnet++ sont en TIFF/16bit. Si l’on veut bénéficier de la précision de calcul de Siril, il est nécéssaire de les convertir en FITS/32bit. Ce format est aussi le seul supporté par l’outil PixelMath de Siril.

Un script?

Le but est dont d’utiliser ici un script écrit en python (que chacun pourra adapter), et basé sur l’écosystème Siril. Pour cela, il faudra au préalable:

Le script python devra alors etre placé dans ce repertoire obligatoirement, juste à coté de l’executable starnet++.exe.

Emplacement du script

Emplacement du script

Que fait ce script?

  • Il va transformer le(s) fichier(s) FITS/32 et TIFF/16bit
  • Il va lancer Starnet++
  • Il va re-transformer le fichier resultat en FITS/32
  • Il va mettre à jour le champ FILTER (FITS header) des fichiers générés pour les rendre compatibles avec PixelMath

Le(s) fichier(s) devront etre “glissés” sur le script Python comme le montre la vidéo.

Les fichiers d’entrée

  • Le mieux est d’utiliser des fichiers dont l’histogramme a déjà été étiré.
  • Il peut s’agir d’un fichier mono (R, G ou B) issu d’un split ou de fichier Ha et/ou OIII issu d’un extract.
  • Il peut s’agir d’un fichier RGB (3 couches donc).
Exemple de fichiers en entrée

Exemple de fichiers en entrée

Les fichiers de sortie

En sortie du script, 2 possiblités:

  • Si le fichier d’entrée était en mono, seul le fichier myfile_s.fits sera généré. _spour “starless” …
  • Si le fichier d’entrée était en RGB, en plus du fichier myfile_s.fits, sera aussi généré le fichier myfile_stars.fits, le masque d’étoiles.
Exemple de fichiers en sortie correspondants

Exemple de fichiers en sortie correspondants

Et PixelMath alors?

L’outil PixelMath recemment introduit dans Siril permet de gérér les images à manipuer grâce à un tri facilité par le champ FILTER du header FITS.

Ce script python reste dans cette optique et met à jour ce champ FILTER. Ainsi: -le fichier starless, dont le nom est du type myfile_s.fits, aura un champ du type FILTER = CLS_sls (si CLS était la valeur d’origine…). -le masque d’étoiles, dont le nom est du type myfile_stars.fits, aura un champ du type FILTER = CLS_str (si CLS était la valeur d’origine…).

Mieux vaut un exemple

Ici, il s’agit d’un mélange d’images mono (R.fits, G.fits, B.fits) et d’une image RGB (resultat2-CLS.fits) réalisée avec un filtre CLS (et donc FILTER = CLS).

Ces 4 images snt glissées simultanément sur le script, et aprés plusieurs minutes de calcul, on voit les fichiers résultants.

Puis, en ouvrant Siril et PixelMath, on peut se rendre compte de l’efficacité du tri des images selon les valeurs de FILTER mises à jour. Cet effet se voit sur les images mono, puis sur les images RGB.

Le script python

Copiez le code suivant et sauvez le fichier sous le nom AutoStarnetFITS.py (par exemple).

import subprocess
import sys
import os
from PIL import Image
from pysiril.siril import Siril
from pysiril.addons import Addons
from pysiril.wrapper import Wrapper
import pathlib
from astropy.io import fits


def Run(*args, trailer= '_s', stride= '256', keep_open=True ):   
  
    #preparing pysiril
    workdir = os.getcwd()
    print('Starting PySiril')
    app = Siril()
    AO = Addons(app)
    cmd = Wrapper(app)
    app.tr.Configure(False,False,True,True)
    app.MuteSiril(True)
    app.Open()
    print('Starting Siril')
        
    for file_in in args:
        print('\nFile to process :', str(file_in))
        #Get attributes (name and extension) of the input file
        filename, inputfile_extension=os.path.splitext(file_in)
        
        if inputfile_extension!='.fits' and inputfile_extension!='.fit': 
            print ('ABORTED: Not a FIT/FITS file')
            return
    
        #Get the FILTER value of the FITS header
        hdul = fits.open(file_in, mode='update')
        try:
            fltr0=hdul[0].header['FILTER']        
        except Exception as e :
            print("\n******* " +  str(e) + "in "+ str(file_in))
            print("*******  Creating the missing field... " + "\n" )
            hdr= hdul[0].header
            hdr.insert('DATE', ('FILTER', '   '))
            hdul.flush()
            fltr0=hdul[0].header['FILTER']
        print("FILTER = " +  str(fltr0) + "\n" )
        hdul.close(output_verify='fix')
        
        #Set pysiril
        app.Execute('setext {:s}'.format(inputfile_extension))
        app.Execute('cd {:s}'.format(workdir))

        # Open the original input 32b FITS file
        # convert it into 16b and save as TIF file with the same name
        cmd.load(filename)          
        cmd.set16bits
        cmd.savetif(filename)

        #Define the 16b version of the initial file, used as input for Starnet++
        filename_tif = filename + '.tif'   
    
        #Get attributes (name and extension) of the last file
        fileroot, file_extension=os.path.splitext(filename_tif)
    
        #Define the output file of Starnet++
        outputfile_extension=".tif"
        outputfilename=filename+trailer+outputfile_extension
        
        
        #String Compatibility test
        if ' ' in filename_tif:
            print ('FAILURE: No space allowed in file name or file path')
            return

            
        #Define image mode
        im = Image.open(filename_tif)
        imode=im.mode
        im.close()
        need_stars = True
        if imode=='I;16': 
            need_stars = False
        
##Few results of "mode" method according to file format input
##          color   Mono
##fits 32     F       F
##fits 16     F       F
##fits 16u    F       F
##fits 8      F       F
##Tif 32      /       F
##Tif 16      RGB     I;16  (the only file format unsable by Starnet)
##Tif 8       RGB     L


        #Compatibility test
        if ((imode=='I;16' or imode=='RGB') and file_extension=='.tif') :
            #set argument for Starnet++
            args= "starnet++.exe " + filename_tif +" "+ outputfilename + " " + stride
            print ('Starnet++ is running... ')
            subprocess.call(args, shell=True)
        else: 
            print ('Not a TIF/16bit file')
            return
    
        #Convert the result starless file into a 32b version 
        starless_filename = fileroot + '_s'
        cmd.load(starless_filename)             #Load bla_s.tif
        cmd.set32bits
        cmd.fmul('1.0')
        cmd.save(starless_filename)             #Save bla_s.fits
    
        #Creation of the Stars.fits
        if need_stars == True:
            folder,_=os.path.split(starless_filename)
            #stars=folder+"\\" + fileroot + "_stars.fits"
            stars=filename+"_stars"
            cmd.load(file_in)                 #Load bla.FITS, stars+neb
            cmd.isub(starless_filename)             #substract starless version
            cmd.save(stars)                         #save stars.FITS

        #Deletion of TIF temp files  
        tokill=starless_filename + '.tif'         
        os.remove(tokill)                       #Remove bla_s.tif  
        os.remove(filename_tif)                 #Remove bla.tif 
    
        ########################################
        ########################################
        #Set the FILTER value in the FITS header
        # At first, for the Starless file
        sl_name=starless_filename+'.fits'
        #print ('starless file2: ', sl_name)
        hdul = fits.open(sl_name, mode='update')
    
        try:
            fltr=hdul[0].header['FILTER']        
        except Exception as e :
            print("******* " +  str(e) + "in "+ str(sl_name))
            print("******* " +  " Creating the missing field... ")
            hdr= hdul[0].header
            hdr.insert('DATE', ('FILTER', ' '))
            hdul.flush()
            fltr=fltr0
    
        hdr = hdul[0].header
        newfltr= str(fltr)+'_sls' 
        hdr['FILTER'] = newfltr
        hdul.close(output_verify='fix')
    
        ########################################    
        # ...and then for the Stars file    
        if need_stars == True:
            stars=stars+'.fits'
            #print ('stars file2: ', stars)
            hdul = fits.open(stars, mode='update')
    
            try:
                fltr=hdul[0].header['FILTER']        
            except Exception as e :
                print("******* " +  str(e) + "in "+ str(stars))
                print("******* " +  " Creating the missing field... ")
                hdr= hdul[0].header
                hdr.insert('DATE', ('FILTER', ' '))
                hdul.flush()
                fltr=fltr0
      
            hdr = hdul[0].header
            newfltr= str(fltr)+'_str' 
            hdr['FILTER'] = newfltr
            hdul.close(output_verify='fix')
        ########################################  
   
    app.Close()
    del app
    print ('Stop')

if __name__ == "__main__":
    Run(*sys.argv[1:])

A vous de jouer maintenant!!!