5.7. Composition d’images#
Les primitives de dessin de la page précédente peignent des marques géométriques sur une image – une ligne, un rectangle, un fragment de texte. Cela couvre la plupart des annotations qu’un algorithme a besoin de rendre visibles, mais pas toutes. Parfois, l’annotation est elle-même une image : une trame de référence capturée à afficher côte à côte avec la trame courante, une miniature d’une capture précédente affichée dans un coin de l’aperçu, un gabarit stocké précédemment visualisé par-dessus une trame en direct pour le calibrage. Le mécanisme permettant de dessiner une image sur une autre est une méthode unique – draw_image() – dotée de suffisamment de paramètres pour gérer la position, la mise à l’échelle, la palette de couleurs et la transparence qu’exige une composition réelle.
5.7.1. L’appel de base#
Dans sa forme la plus simple, draw_image prend une autre Image et une position où la dessiner :
reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)
La destination est img ; la source est reference ; le pixel en haut à gauche de la source se place en (10, 10) de img, et le reste des pixels de la source suit vers la droite et vers le bas à partir de là. Les pixels de la destination que la source recouvre sont écrasés par les pixels correspondants de la source ; les pixels en dehors de l’emprise de la source restent intacts.
Si la source dépasse le bord de la destination, les parties qui débordent sont silencieusement rognées – le même comportement indulgent que set_pixel affiche pour les positions hors plage. Le code applicatif n’a pas à contraindre la position aux dimensions de l’image au préalable ; il peut transmettre la position souhaitée et laisser la méthode gérer le rognage.
5.7.2. Charger un fichier directement#
draw_image accepte un chemin de fichier à la place de l’argument Image et charge le fichier avant de le composer :
img.draw_image("/sdcard/reference.bmp", x=10, y=10)
Cela ressemble à une commodité – une ligne au lieu de deux – et c’en est une, mais la différence va au-delà de la syntaxe. Construire une Image à partir d’un fichier alloue un tampon pour contenir les pixels décodés, et ce tampon subsiste jusqu’à ce que le ramasse-miettes le libère. Transmettre le chemin directement à draw_image permet au module de décoder le fichier dans un tampon temporaire, de composer à partir de celui-ci et de libérer le tampon au retour de l’appel, sans que le code applicatif ait à conserver une référence vers une Image distincte entre les trames.
5.7.3. Mise à l’échelle#
Lorsque la source et la destination ont des tailles différentes – une capture en basse résolution composée sur un canevas en plus haute résolution, ou une miniature qui doit être dimensionnée à une fraction particulière de la trame – deux paramètres d’échelle se chargent de redimensionner la source au moment où elle est dessinée :
img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)
x_scale et y_scale sont des flottants indépendants ; transmettre la même valeur pour les deux applique une mise à l’échelle uniforme, tandis que transmettre des valeurs différentes étire ou rétrécit la source selon un axe. La mise à l’échelle se produit au moment du dessin ; la source reference n’est pas modifiée.
Un masque de bits d’indicateurs d”indication détermine comment la mise à l’échelle interpole réellement entre les pixels. image.BILINEAR produit des résultats plus lisses au prix de davantage de calculs ; image.BICUBIC produit des résultats encore plus lisses et coûte encore davantage ; la valeur par défaut utilise le plus proche voisin, qui est la moins coûteuse et le bon choix lorsque la source est déjà à la résolution en pixels de la destination. Les indicateurs de gestion du rapport d’aspect – SCALE_ASPECT_KEEP, SCALE_ASPECT_EXPAND, SCALE_ASPECT_IGNORE – décident de ce qu’il faut faire lorsque le rapport d’aspect de la source ne correspond pas au rectangle dans lequel elle est dessinée.
5.7.4. Fusion alpha#
Par défaut, draw_image remplace les pixels de destination par les pixels de la source. Lorsque l’objectif est une superposition translucide – de sorte que la destination transparaisse à travers la source – le paramètre alpha contrôle la manière dont les deux sont mélangés. alpha=0 n’affiche que la destination (pas de source) ; alpha=255 est la valeur par défaut et n’affiche que la source (remplacement complet) ; les valeurs intermédiaires mélangent les deux proportionnellement :
img.draw_image(overlay, x=0, y=0, alpha=128)
Un argument distinct alpha_palette est le seul mécanisme d’alpha par pixel du module. Il prend une image GRAYSCALE dont les valeurs sont utilisées comme alpha à la position correspondante dans la source – une carte de chaleur dont l’alpha varie avec son intensité, par exemple. L’alpha doit être fourni sous la forme de cet argument distinct en niveaux de gris ; une image source qui porte son propre canal alpha (un PNG avec transparence, par exemple) ne le transmet pas automatiquement.
5.7.5. ROI source et palette#
Deux paramètres supplémentaires complètent le mécanisme de composition :
roi=(x, y, w, h)restreint la source à un sous-rectangle d’elle-même, de sorte que seul ce rectangle soit composé sur la destination. Utile pour recadrer au sein du même appel, sans préparer d’intermédiaire recadré.color_palettesubstitue la valeur de chaque pixel source au travers d’une table de correspondance avant le dessin – le même mécanisme qu’utilisentto_rainbow()etto_ironbow(), exposé ici pour qu’une superposition puisse être palettisée sur son chemin vers la destination sans passe de conversion distincte.
Les deux se composent avec tout le reste de l’appel : la mise à l’échelle, l’alpha, l’argument mask côté destination, et le paramètre roi côté destination qui restreint l”écriture à un rectangle de la destination.