Python : callback à paramètre unique et passage d'options

Le besoin m'est venu de la bibliothèque pims permettant de charger séquentiellement des images. Typiquement, on fait

frames = pims.ImageSequence('../sample_data/bulk_water/*.png')

Mais si on veut appliquer une fonction appliquant un pré-traitement, on peut ajouter une callback


from skimage.color import rgb2grey 
def preprocess(im):
    """
    callback prenant une image im
    """
    return rgb2grey(im)

frames = pims.ImageSequence('../sample_data/bulk_water/*.png', process_func=preprocess)

Ce qui a pour effet que les images soient en niveau de gris plutôt qu'en RGB. Maintenant, imaginons que ce soit un seuil que je souhaite appliquer

def preprocess(im):
    threshold = 0.8
    grey_im = rgb2grey(im)
    # selectionne les indices satisfaisant la condition
    idx = grey_im < grey_im.max() * threshold
    # applique une transformation
    grey_im[idx] = 0
    return grey_im

L'exemple fonctionne toujours, mais on a un paramètre threshold définit dans la fonction, ce qui n'est pas très flexible si on veut placer cette fonction dans une petite bibliothèque maison. Je préfèrerais la signature suivante :

def preprocess(im, threshold=0.8):

Je vais donc définir dans ma bibliothèque la fonction suivante :

# Je definie une fonction qui prend une fonction et des arguments optionels
def all_args(func, **params):
    # Je definie une fonction qui prend une image
    def wrapper(im):
        # Je retourne ma fonction func avec les bons arguments
        return func(im, **params)
    # je retourne une fonction
    return wrapper

# Je definie ma fonction comme je le souhaite
def preprocess(im, threshold=0.8):
    grey_im = rgb2grey(im)
    idx = grey_im < grey_im.max() * threshold
    grey_im[idx] = 0
    return grey_im

Ainsi je peux faire dans mon code principal

from mabiblio import all_args, preprocess

mythreshold = .36

# je crée une fonction new_preprocess à partir de preprocess, auquel je cache
# le parametre threshold
new_preprocess = all_args(preprocess, threshold=mythreshold)

frames = pims.ImageSequence('../sample_data/bulk_water/*.png', process_func=new_preprocess)

Ici, je peux donc utiliser la fonction preprocess, de manière compacte, un peu partout dans mes codes, sans me soucier de son détail.

Je crois que je dois cette astuce à Thomas Caswell que je remercie.

Liens utiles de sametmax :

Vus : 1675
Publié par François Boulogne : 46