Starnet++ et Siril
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:
- installer pysiril, voir https://siril.org/tutorials/pysiril/
- installer astropy, voir https://www.astropy.org/
- Installer PIL
- Télécharger et Dézipper la version Command Line Tool de Starnet++ (https://www.starnetastro.com/download/) dans un repertoire connu.
Le script python devra alors etre placé dans ce repertoire obligatoirement, juste à coté de l’executable starnet++.exe
.

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’unextract
. - Il peut s’agir d’un fichier RGB (3 couches donc).

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é._s
pour “starless” … - Si le fichier d’entrée était en RGB, en plus du fichier
myfile_s.fits
, sera aussi généré le fichiermyfile_stars.fits
, le masque d’étoiles.

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!!!