Článek vznikl jako lehce upravený překlad anglického originálu od Onuralpa Sezera. Oproti originálu je vysvětleno pár nejasností, doplněno pár drobností a použité obrázky s českými popisky.

Svět technologií se rozvíjí a nároky na počítačové vidění, umělou inteligenci a strojové učení rostou každým dnem. Co to vlastně je počítačové vidění? Jednoduše řečeno, je to technologie, která umožňuje počítačům, mobilním telefonům (ale také třeba robotům) vidět své okolí. První pokusy s počítačovým viděním se datují do 50. let minulého století a od té doby urazila tato oblast obrovský kus cesty a našla si cestu nejen do našich mobilních telefonů, ale také třeba do aut. V tomto článku si ukážeme knihovnu OpenCV - jednu z nejrozšířenějších knihoven pro počítačové vidění.

Poznámka: OpenCV existuje pro C++, Python, Javu a MATLAB. V tomto seriálu budeme používat OpenCV pro Python.

Co je to OpenCV?

 

OpenCV (Open Source Computer Vision Library) je open-source knihovna pro počítačové vidění a strojové učení. OpenCV bylo vytvořené, aby vytvářelo společnou infrastrukturu pro aplikace, které používají počítačové vidění, a aby zrychlilo použití počítačového vnímání v komerčních produktech. Obsahuje více než 2500 optimalizovaných algoritmů, zahrnujících obsáhlou sadu klasických i moderních algoritmů pro počítačové vidění a strojové učení. Tyto algoritmy mohou být použité pro rozpoznávání obličejů, identifikaci objektů, klasifikaci lidských akcí ve videu, stanovení markerů pro použití v rozšířené realitě a mnoho dalšího.

opencv.org – about

Instalace OpenCV na Fedoře

Abychom mohli začít používat OpenCV, nainstalujeme ji pomocí příkazu níže:

$ sudo dnf install opencv opencv-contrib opencv-doc python3-opencv python3-matplotlib python3-numpy

Poznámka: Pokud používáte Fedoru Silverblue, můžete buď použít Toolbox a OpenCV nainstalujete do něj pomocí příkazu výše, nebo potřebné balíky překryjete pomocí rpm-ostree install opencv opencv-doc python3-opencv python3-matplotlib python3-numpy. Autor překladu ovšem pracuje v Toolboxu na Silveblue a vše v něm testuje, vše by tedy mělo být plně funkční i bez nutnosti overlaye.

Pro jistotu si ověříme, že je OpenCV v pořádku nainstalované:

$ <b>python</b>
Python 3.9.6 (default, Jul 16 2021, 00:00:00)
[GCC 11.1.1 20210531 (Red Hat 11.1.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> <strong>import cv2 as cv</strong>
>>> <strong>print( cv.__version__ )</strong>
4.5.2
>>> <strong>exit()</strong>

Pokud vidíte verzi OpenCV podobně jako v ukázce výše, je vše v pořádku.

Začínáme s OpenCV

Poté, co jsme úspěšně nainstalovali OpenCV, můžeme s jeho pomocí napsat náš první skript, který načte obrázek. Vytvořme tedy soubor starry_night.py a otevřeme ho v oblíbeném editoru. Do souboru vložíme následující:


import cv2 as cv
import sys
img = cv.imread(cv.samples.findFile("starry_night.jpg"))
if img is None:
 sys.exit("Could not read the image.")
cv.imshow("Display window", img)
k = cv.waitKey(0)
if k == ord("s"):
 cv.imwrite("starry_night.png", img)

Následně můžeme náš program spustit (z nově otevřeného okna se dostaneme stiskem klávesy S, při zavření okna křížkem zůstane skript běžet a je třeba ho ukončit pomocí ctrl + Z):

$ python starry_night.py

Hurá! Právě jsme otevřeli obrázek pomocí OpenCV. Co můžeme udělat dál? Třeba převést obrázek do stupňů šedi, když funkci cv.imread předáme druhý parametr cv.IMREAD_GRAYSCALE:
img = cv.imread(cv.samples.findFile("starry_night.jpg"), <strong>cv.IMREAD_GRAYSCALE</strong>)


Stejným způsobem můžeme použít celkem tři parametry:

  • cv.IMREAD_GRAYSCALE nebo 0: Načtení obrázku v odstínech šedi.
  • cv.IMREAD_COLOR nebo 1: Načtení barevného obrázku, jakákoli průhlednost ale bude odstraněna. Toto je základní mód, který se používá, pokud není mód specifikovaný.
  • cv.IMREAD_UNCHANGED nebo -1: Načtení obrázku včetně alfa kanálu (průhlednosti).

Zobrazování vlastností obrázku

Vlastnosti obrázku zahrnují rozměry (počet pixelů v jednom řádku/sloupci), počet kanálů, typ obrazových dat, počet pixelů a další. Některé z nich si níže zobrazíme. Začněme třeba rozměry obrázku a datovým typem pro ukládání hodnot kanálů:


import cv2 as cv
img = cv.imread(cv.samples.findFile("starry_night.jpg"))
print("Image size is", img.shape)
print("Data type of image is", img.dtype)


Image size is (600, 752, 3)
Data type of image is uint8

Kromě jiného si můžeme třeba zobrazit i hodnoty jednotlivých pixelů, jelikož samotný obrázek je uložený jako 2D pole:
print(f"Image 2D numpy array n {img}")


Image 2D numpy array
[[[0 0 0]
[0 0 0]
[0 0 0]
...
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
...

Poznámka: námi vybraný obtázek má po krajích černý "rámeček", proto nám výstup vypisuje samé nuly.

V kódu jsme použili atributy img.shape a img.dtype. První z nich určuje rozměry obrázku (výšku, šířku a počet kanálů), druhý z nich datový typ pro ukládání jedné hodnoty jednoho kanálu.
Už jsme si zobrazili obrázek pomocí OpenCV, teď si ho zobrazíme pomocí matplotlibu:


import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(cv.samples.findFile("starry_night.jpg"),0)
plt.imshow(img)
plt.show()

Co to?

Obrázek byl sice načtený jako šedotónový, ale to nutně neznamená, že tak bude zobrazený i pomocí matplotlibu. Funkce plt.imshow totiž v základu používá jiné mapování barev. Nic ale není ztraceno, pokud chceme zobrazit obrázek šedotónově, prostě přidáme druhý parametr funkci imshow následovně:


plt.imshow(img,cmap='gray')

Stejný problém se vyskytne i v situaci, kdy budeme otevírat obrázek v barevném módu. Matplotlib v základu počítá s barevným formátem RGB, OpenCV naproti tomu používá formát BGR (modrá a červená složka si vyměnily místa). Tento formát byl dříve velmi populární mezi výrobci videokamer a tvůrci software a původní tvůrci OpenCV proto (tehdy zcela logicky) zvolili tento formát. Časy se mění, BGR stále zůstává.

Zpět ke kódu! Pokud chceme, aby se i barevné obrázky zobrazily správně, je třeba konvertovat je z BGR do RGB:

import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(cv.samples.findFile("starry_night.jpg"),cv.IMREAD_COLOR)
fig, (ax1, ax2) = plt.subplots(1,2)
ax1.imshow(img)
ax1.set_title('Barvy BGR')
ax2.imshow(img[:,:,::-1])
ax2.set_title('Obrácené BGR (neboli RGB)')
plt.show()

Rozdělování a spojování kanálů

import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(cv.samples.findFile("starry_night.jpg"),cv.IMREAD_COLOR)
b,g,r = cv.split(img)
fig,ax = plt.subplots(2,2)
ax[0,0].imshow(r,cmap='gray')
ax[0,0].set_title("Červený kanál");
ax[0,1].imshow(g,cmap='gray')
ax[0,1].set_title("Zelený kanál");
ax[1,0].imshow(b,cmap='gray')
ax[1,0].set_title("Modrý kanál");
# Sloucime kanaly do BGR obrazku
imgMerged = cv.merge((b,g,r))
# Ukaz vysledek
ax[1,1].imshow(imgMerged[:,:,::-1])
ax[1,1].set_title("Spojené kanály");
plt.show()

  • cv.split: Rozdělí jeden vícekanálový obrázek (nebo, chcete-li, pole) na několik jednokanálových obrázků.
  • cv.merge: Jednotlivé jednokanálové obrázky zase spojí do jednoho vícekanálového. Všechny vstupní obrázky přitom musí mít stejné rozměry.

Poznámka: Čím jsou jednotlivé barevné složky tmavší, tím méně se dané barvy na daném místě nachází. Obrázek pro červený kanál je nejtmavší, což odpovídá tomu, že v originálu je červené barvy nejméně.

Konverze do jiných barevných prostorů

Funkce cv.cvtColor nám umožňuje konvertovat obrázek z jednoho barevného prostoru do druhého. Když transformujeme mezi barevnými prostory RGB a BGR, pomocí BGR2RGB a RGB2BGR specifikujeme, jakým směrem převádíme. Pokud někde narazíte na informaci, že základní barevný prostor v OpenCV je RGB, je to ve skutečnosti BGR! Pokud si tedy představíme standardní barevnou hloubku (24 bitů), pak prvních 8 bitů bude určovat modrou, dalších 8 bitů bude určovat zelenou, a konečně zbývající osmice nám určí červenou složku (kanál) pixelu. Následujích 24 bitů bude určovat složky druhého pixelu a tak dále... Níže se podíváme na použití výše zmíněné funkce cv.cvtColor:


import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread(cv.samples.findFile("starry_night.jpg"),cv.IMREAD_COLOR)
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.show()

Další informace

Pro podrobnější informace navštivte online dokumentaci. V příštím díle si ukážeme základní úpravy obrázků.