5.7. Afbeeldingen samenstellen¶
De tekenprimitieven van de vorige pagina schilderen geometrische markeringen op een afbeelding – een lijn, een rechthoek, een stuk tekst. Dat dekt de meeste annotaties die een algoritme zichtbaar moet maken, maar niet allemaal. Soms is de annotatie zelf een afbeelding: een vastgelegd referentieframe om naast het huidige frame te tonen, een miniatuur van een eerdere opname in een hoek van het voorbeeld, of een eerder opgeslagen sjabloon dat boven op een live frame wordt gevisualiseerd voor kalibratie. Het mechanisme om de ene afbeelding op de andere te tekenen is een enkele methode – draw_image() – met genoeg parameters om de positie, de schaling, het kleurenpalet en de transparantie te verwerken die echte compositie nodig heeft.
5.7.1. De basisaanroep¶
In zijn eenvoudigste vorm neemt draw_image een andere Image en een positie om die op te tekenen:
reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)
De bestemming is img; de bron is reference; de pixel linksboven van de bron landt op (10, 10) van img, en de rest van de pixels van de bron volgt van daaruit naar rechts en naar beneden. Pixels van de bestemming die door de bron worden bedekt, worden overschreven met de overeenkomstige pixels van de bron; pixels buiten het bereik van de bron blijven ongemoeid.
Als de bron voorbij de rand van de bestemming reikt, worden de delen die eraf vallen stilzwijgend afgekapt – hetzelfde vergevingsgezinde gedrag dat set_pixel toont bij posities buiten bereik. Toepassingscode hoeft de positie niet vooraf vast te klemmen op de afmetingen van de afbeelding; ze kan de gewenste positie doorgeven en de methode het afkappen laten afhandelen.
5.7.2. Een bestand inline laden¶
draw_image accepteert een bestandspad in plaats van het Image-argument en laadt het bestand voordat het wordt samengesteld:
img.draw_image("/sdcard/reference.bmp", x=10, y=10)
Dat lijkt op een gemak – één regel in plaats van twee – en dat is het ook, maar het verschil is meer dan syntaxis. Het construeren van een Image uit een bestand wijst een buffer toe om de gedecodeerde pixels te bevatten, en die buffer blijft bestaan totdat garbagecollection hem vrijgeeft. Het pad rechtstreeks aan draw_image doorgeven laat de module het bestand decoderen naar een tijdelijke buffer, ermee componeren en de buffer vrijgeven wanneer de aanroep terugkeert, zonder dat de toepassingscode een verwijzing naar een aparte Image tussen frames hoeft te bewaren.
5.7.3. Schalen¶
Wanneer de bron en de bestemming verschillende afmetingen hebben – een opname met lage resolutie die op een canvas met hogere resolutie wordt samengesteld, of een miniatuur die op een bepaald deel van het frame moet worden geschaald – zorgen twee schaalparameters voor het herschalen van de bron terwijl deze wordt getekend:
img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)
x_scale en y_scale zijn onafhankelijke floats; beide op dezelfde waarde doorgeven schaalt uniform, en verschillende waarden doorgeven rekt de bron uit of krimpt hem langs één as. Het schalen gebeurt op tekenmoment; de bron reference wordt niet gewijzigd.
Een bitmasker van hint-vlaggen bepaalt hoe de schaling daadwerkelijk interpoleert tussen pixels. image.BILINEAR levert vloeiendere resultaten ten koste van meer rekenwerk; image.BICUBIC levert nog vloeiendere resultaten en kost opnieuw meer; de standaardinstelling gebruikt nearest-neighbour, wat het goedkoopst is en de juiste keuze wanneer de bron al op de pixelresolutie van de bestemming staat. Aspectverwerkingsvlaggen – SCALE_ASPECT_KEEP, SCALE_ASPECT_EXPAND, SCALE_ASPECT_IGNORE – bepalen wat er gebeurt wanneer de beeldverhouding van de bron niet overeenkomt met de rechthoek waarin hij wordt getekend.
5.7.4. Alpha blending¶
Standaard vervangt draw_image bestemmingspixels door bronpixels. Wanneer het doel een doorschijnende overlay is – zodat de bestemming door de bron heen zichtbaar is – bepaalt de parameter alpha hoe de twee worden gemengd. alpha=0 toont alleen de bestemming (geen bron); alpha=255 is de standaard en toont alleen de bron (volledige vervanging); tussenliggende waarden mengen de twee proportioneel:
img.draw_image(overlay, x=0, y=0, alpha=128)
Een apart alpha_palette-argument is het enige per-pixel-alphamechanisme van de module. Het neemt een GRAYSCALE-afbeelding waarvan de waarden worden gebruikt als alpha op de overeenkomstige positie in de bron – een heatmap waarvan de alpha varieert met de intensiteit, bijvoorbeeld. De alpha moet als dat aparte grijswaarden-argument worden aangeleverd; een bronafbeelding die haar eigen alphakanaal meedraagt (bijvoorbeeld een PNG met transparantie) brengt deze niet automatisch mee.
5.7.5. Bron-ROI en palet¶
Twee verdere parameters maken het compositiemechanisme compleet:
roi=(x, y, w, h)beperkt de bron tot een deelrechthoek van zichzelf, zodat alleen die rechthoek op de bestemming wordt samengesteld. Handig om binnen dezelfde aanroep bij te snijden, zonder een bijgesneden tussenresultaat voor te bereiden.color_palettevervangt de waarde van elke bronpixel via een opzoektabel voordat er wordt getekend – hetzelfde mechanisme datto_rainbow()ento_ironbow()gebruiken, hier blootgesteld zodat een overlay tijdens het plaatsen op de bestemming van een palet kan worden voorzien zonder een aparte conversiestap.
Beide werken samen met al het andere in de aanroep: de schaling, de alpha, het mask-argument aan de bestemmingszijde, en de roi-parameter aan de bestemmingszijde die de schrijfactie beperkt tot een rechthoek van de bestemming.