5.6. Kreslení tvarů a textu

Algoritmus, který o obrazu něco rozhoduje, často potřebuje, aby toto rozhodnutí bylo viditelné. Detektor blobů najde oblast, na které aplikaci záleží; aplikace chce tuto oblast vykreslit do snímku, aby operátor – nebo vývojář spouštějící skript – viděl, co bylo nalezeno. Transformace souřadnic mapuje vstupní pozici na výstupní; její ladění obvykle znamená označení obou pozic na témže obrazu. Náhled v IDE čte cokoli, co se nachází ve snímkovém bufferu (frame buffer) v okamžiku, kdy jej dotazuje, takže nejjednodušším způsobem, jak zviditelnit výstup algoritmu, je zapsat anotace přímo do snímkového bufferu. Skupina kreslicích metod ve třídě Image je nástrojovou sadou přesně pro tuto práci.

5.6.1. Primitiva

Každá kreslicí metoda umístí na obraz jeden konkrétní druh značky. Katalog je malý a drží se blízko geometrických primitiv, která anotace skutečně potřebuje:

  • draw_line() – přímá úsečka mezi dvěma koncovými body.

  • draw_rectangle() – obdélník zarovnaný s osami, dutý nebo vyplněný.

  • draw_circle() – kružnice kolem středu, dutá nebo vyplněná.

  • draw_ellipse() – elipsa s libovolnou rotací.

  • draw_cross() – znaménko plus v bodě, obvyklá značka pro těžiště nebo cíl kliknutí.

  • draw_arrow() – šipka z počátečního bodu do koncového bodu.

  • draw_edges() – čtyři strany libovolného čtyřúhelníku zadané čtyřmi rohovými body; přirozený způsob, jak obkreslit detekovaný tag nebo perspektivně zkreslenou oblast.

  • draw_string() – text z vestavěného bitmapového fontu.

Každá z těchto metod upravuje zdrojový obraz na místě a vrací tentýž obraz pro zřetězení, v souladu s konvencí operujících metod zavedenou dříve.

Mřížka malých panelů, z nichž každý zobrazuje jedno z osmi kreslicích primitiv aplikované jednou. Každý panel obsahuje čáru, obdélník, kružnici, elipsu, kříž, šipku, čtyřúhelník nebo krátký textový řetězec, přičemž název metody, která jej vytvořila, je uveden níže.

Osm kreslicích primitiv, jedno na panel. Každá metoda vytváří jeden druh značky.

5.6.2. Barva

Každá kreslicí metoda přijímá argument color, který rozhoduje o tom, jaká hodnota se zapíše do každého vykresleného pixelu. Podoba tohoto argumentu závisí na formátu obrazu. Pro obraz RGB565 je přirozenou podobou n-tice (r, g, b) s každým kanálem v rozsahu 0255; modul ji před zápisem zabalí do 16bitového slova RGB565. Pro obraz ve stupních šedi je přirozenou podobou jediné celé číslo jasu od 0 (černá) po 255 (bílá). Metody přijímají i surovou uloženou hodnotu daného formátu – 16bitové zabalené slovo pro RGB565, 8bitové celé číslo pro stupně šedi – což je efektivní podoba, když byla barva spočtena jinde a je již v uložené podobě.

Vynechání argumentu color kreslí bíle. Tato výchozí hodnota je vhodná pro práci ve stupních šedi, kde je bílá maximální hodnotou a proti většině pozadí se čte zřetelně. Pro ladicí překryvy v RGB565 je téměř vždy nesprávná: zelená nebo červená se obvykle čte lépe proti druhu scény, jakou kamera skutečně vidí, a explicitní barva sděluje záměr.

5.6.3. Tloušťka a výplň

Většina geometrických metod přijímá dva příznaky, které rozhodují o tom, jak se značka vykreslí:

  • thickness=N nastavuje šířku čáry v pixelech. Výchozí hodnota je 1, což pro většinu překryvů vyhovuje; větší hodnota je užitečná, když musí anotace zůstat viditelná proti rušné scéně nebo poté, co obraz dále upraví následující fáze zpracovatelského řetězce.

  • fill=True přepíná značku z obrysu na plnou a vyplňuje každý vnitřní pixel zvolenou barvou. Výchozí hodnota je False.

Tyto příznaky se nevztahují na primitiva, která nemají vnitřek k vyplnění – na čáru, kříž, šipku, čtyřúhelník – kde má smysl pouze thickness.

5.6.4. Kreslení textu

draw_string() vypisuje znaky z vestavěného bitmapového fontu o velikosti 8 krát 10 pixelů. x a y jsou levý horní roh buňky prvního znaku, text je řetězec ke kreslení a color se řídí stejnou konvencí jako u geometrických metod. Font nese celý rozsah tisknutelného ASCII a nemá kerning – každý znak zabírá stejně širokou buňku o 8 pixelech – což usnadňuje umístění výstupu.

img.draw_string(10, 10, "blobs: 3", color=(0, 255, 0))

Řetězec může obsahovat odřádkování (\n); každé odřádkování přesune další znak na začátek nového řádku deset pixelů pod předchozím. Argument scale kreslí každý znak ve větší velikosti podle desetinného násobku a x_spacing a y_spacing přidávají odsazení kolem každého znaku. Malá sada příznaků otočení / zrcadlení / převrácení se vztahuje buď na celý řetězec, nebo na každý znak zvlášť – dostatek kontroly pro rozvržení textu podél úhlu nebo proti nevodorovné hraně, když to rozvržení vyžaduje.

5.6.5. Vymazání plátna

Jedna metoda v této skupině nekreslí žádnou konkrétní značku. Pouze vynuluje každý pixel obrazu:

  • clear() – vynuluje každý pixel, volitelně omezeno na ROI nebo vymezeno pomocí masky.

clear() je správnou odpovědí, když aplikace skládá anotaci od základu v každém snímku – začne s černým plátnem, nakreslí nové anotace a předá výsledek displeji – místo překrývání zachyceného snímku. Je to také nejlevnější způsob, jak připravit pomocný obraz pro použití jako buffer masky.

Čerstvě alokovaný obraz je již z konstruktoru vynulovaný, takže clear() má význam zejména u bufferů znovu používaných mezi snímky.