Kalibrace kamery k odstranění distorze¶
Teoretický úvod¶
Kalibrace kamery je jednou z velmi důležitých prerekvizit jakékoliv úlohy strojového vidění. Využívá se k tomu, aby odstranila vady optiky (distorze) vzniklé použitím kombinace snímače a objektivu. Nejčastěji se jedná o odstranění vady soudkovitosti objektivu (radiální distorze) či tangenciální distorze vzniklé neideálním umístěním objektivu na snímač.
Úkol je zaměřen na kalibraci kamery za účelem odstranění distorze ze snímků. K tomu, aby bylo možné provést kalibraci, je zapotřebí dostatečný počet snímků (10-30), které obsahují předem známý vzor (v našem případě šachovnice), zaznamenaný v různých pozicích. Knihovna OpenCV následně sama vzory vyhledá, vypočte vnitřní paremetry (intrinsics), vnější parametry (extrinsics) a parametry zkreslení (distortion coefficients).
Vnitřní parametry v OpenCV¶
Jsou definovány 3x3 maticí. V OpenCV se jedná o výstupní parametr cameraMatrix:
\begin{equation} K = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \end{equation}
Kde $f_x$ a $f_y$ jsou ohniskové vzdálenosti v pixelech a $c_x$ a $c_y$ jsou souřadnice optického středu v pixelech tzv. principal point.
Vnější parametry v OpenCV¶
Jsou definovány 3D rotační maticí a 3D vektorem. V OpenCV se jedná o výstupní parametry rvecs a tvecs (realně rvecs je 3x1 rotační vektor, kde uchováváme informaci o rotaci kolem os x, y, z - tzv. Rodriguesova reprezentace): \begin{equation} R = \begin{bmatrix} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \\ \end{bmatrix} \end{equation}
\begin{equation} t = \begin{bmatrix} t_{x} \\ t_{y} \\ t_{z} \\ \end{bmatrix} \end{equation}
Matice $R$ je 3x3 rotační matice a vektor $t$ je 3x1 translace kamery.
Parametry zkreslení v OpenCV¶
Jsou definovány několika prvkovým vektorem. V OpenCV se jedná o výstupní parametr distCoeffs: Typicky pouze používáme paremetry $k_1$, $k_2$, $p_1$ a $p_2$ a $k_3$!!! Které paremetru budou použity záleží na nastavení flagů při volání funkce kalibrace.
Rovnice radiální distorze:
\begin{equation} x_{\text{radial}} = x \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} \end{equation}
\begin{equation} y_{\text{radial}} = y\frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} \end{equation}
Rovnice tangenciální distorze:
\begin{equation} x_{\text{tangential}} = x + [2p_1xy + p_2(r^2 + 2x^2)] \end{equation}
\begin{equation} y_{\text{tangential}} = y + [p_1(r^2 + 2y^2) + 2p_2xy] \end{equation}
Reprojekční chyba¶
Reprojekční chyba je vzdálenost mezi naměřeným bodem a bodem jež byl spočítán z vnitřních, vnějších parametrů kamery a distorzních koeficientů.
Praktické tipy a triky¶
Plný list doporučení pro nejlepší výsledky kalibrace je k dispozici zde. Naopak 5 nejčastějších chyb při kalibraci kamery je uvedeno zde.
Zde uvádíme pouze několik základních tipů:
- Velikost šachovnice: Velikost šachovnice by měla být zvolena tak, aby při požadované pracovní vzdálenosti zabírala alespoň 50% snímku při pohledu, kdy je šachovnice paralelně se snímačem (fronto-paralelně).
- Natočení vzoru: Pro zjištění distorzních parametrů by měly postačit pouze fronto-paralelní snímky šachovnice. Pro zjištění vnitřních parametrů je zapotřebí vzor natáčet v různých úhlech. Doporučené natočení je $\pm 45^ {\circ}$ okolo vertikální a horizontální osy. I v případě, že chceme zjistit pouze distorzní parametry, je vhodné natáčet vzor v různých úhlech a vytvořit větší dataset.
- Rozložení snímků: Musíme vzor umístit do všech částí snímku. Pokud nebudeme mít např. vzor na okrajích, parametry nebudou dostatečně svázány (constrained).
- Filtrace snímků: Po samotné kalibrací je vhodné provést filtraci snímků. Často nekvalitní snímky mohou zhoršit výsledky kalibrace a jejich reproječní chyba je vyšší než u ostatních snímků. Následně je možné pořídit snímek znovu a opětovně provést kalibraci.
- Overfitting: Nízká reprojekční chyba neznamená nutně dobrou kalibraci. Může se jednat o přeučení (overfitting) modelu na daný dataset. Nastává při použití příliš flexibilního modelu (např. v OpenCV použijeme paremetry $k_1$, $k_2$, $p_1$ a $p_2$ a $k_3$, $k_4$, $k_5$, $k_6$).
Doplňující informace¶
Důležité je si uvědomit, že kalibrace kamery je fitování dat do rozšířeného pinhole kamera modelu. Je důležité, abychom měli námi vytvořený dataset ke kalibraci balancovaný. Vzory musejí být zaznamenány z různých úhlů a v různých částech obrazu. Měli bychom se vyhnout situaci, kdy bychom měli všechny vzory z jedné části obrazu, nebo všechny vzory pod jedním úhlem. Ideální je, když máme vzory rovnoměrně rozložené po celém obrazu a pod různými úhly.
V OpenCV kalibračním modulu je k dispozici funkce cv2.calibrateCameraExtended()
, která je rozšířena o reprojekční error a neurčitost vnitřních a vnějších parametrů kamery. Pro porozumění reprojekčnímu erroru se můžete podívat zde. Pro porozumění neurčitosti vnitřních a vnějších parametrů kamery se můžete podívat zde. Jedná se o velmi důležité informace, jež prozradí, jak moc můžeme věřit výsledkům kalibrace.
V předmětu se setkáme s šachovnicovým vzorem pro kalibraci kamery. Velmi často se používají i jiné vzory, příkladem může být Charuco board. Jedná se o kombinaci šachovnicového vzoru a Aruco markerů. Charuco board je robustnější a umožňuje kalibraci kamery i když je část vzoru zakryta. Při použití šachovnicového vzoru musí být vždy vidět celý vzor. Více informací o jednotlivých vzorech a kdy je použít můžete najít zde.
Pokud používáme kamerovou soustavu k přesnému měření apod. v Machine vision se setkáváme s potřebou velice malých kalibračních targetů. Často jsou tyto targety extrémně přesné a extrémě drahé. Při měřících aplikacích je důležite kalibrovat kameru v pozici a orientaci, ve které bude kamera použita nastavení ostrosti a clony objektivu musí zůstat nezměněno. Pokud nastavení jakkoliv změníme, může být kalibrace nepřesná.
Import knihoven a konfigurace¶
%pip install prettytable
from ipywidgets.widgets import FloatSlider
from ipywidgets import interact
from improutils import *
from library import *
Pomocné funkce¶
Z následujících funkcí je potřeba vybírat ty vhodné pro splnění úkolu.
Seznam funkcí pro přehlednost:
camera_calibration(...)
- library.pycalibration_stats(...)
- library.pycorrect_frame(...)
- library.pyplot_images(...)
- improutilsload_image(...)
- improutils
1) Experimentujte s hypotetyckými hodnotami distorzních parametrů¶
Ukažte alespoň jedno realistické nastavení parametrů radiální (k1, k2, k3, k4, k5, k6) a tangenciální (p1, p2) distorze. Diskutujte vliv jednotlivých parametrů na distorzní funkci.
interact(plot_distortion,
k1=FloatSlider(min=-10, max=10, step=0.01, value=0, description='k1', continuous_update=False, readout_format='.3f'),
k2=FloatSlider(min=-100, max=100, step=0.01, value=0, description='k2', continuous_update=False, readout_format='.3f'),
k3=FloatSlider(min=-1000,max=1000,step=0.01, value=0, description='k3', continuous_update=False, readout_format='.3f'),
k4=FloatSlider(min=-10, max=10, step=0.01, value=0, description='k4', continuous_update=False, readout_format='.3f'),
k5=FloatSlider(min=-100, max=100, step=0.01, value=0, description='k5', continuous_update=False, readout_format='.3f'),
k6=FloatSlider(min=-1000,max=1000,step=0.01, value=0, description='k6', continuous_update=False, readout_format='.3f'),
p1=FloatSlider(min=-0.5, max=0.5, step=0.01, value=0, description='p1', continuous_update=False, readout_format='.3f'),
p2=FloatSlider(min=-0.5, max=0.5, step=0.01, value=0, description='p2', continuous_update=False, readout_format='.3f'))
2) Získejte snímek s viditelnou!!! vadou distorze pomocí Pylon Viewer. Snímek si načtěte a zobrazte.¶
Hint: Mohl by se vám hodit vzor podložky stojanu.
img_distorsion = ...(...) ###
...(img_distorsion) ###
3) Získejte snímky šachovnice ke kalibraci. Snímky uložte do vámi zvolené složky. Cestu ke složce si uložte.¶
calib_folder_path = ... ###
4) Prověďte kalibraci kamery. Nezapomeňte zvolit správnou velikost šachovnice.¶
chess_shape = ... ### tuple
reprojection_error, camera_matrix, dist_coeffs, _, _, std_deviations_intrinsics, _, per_view_errors, chessboard_images = ...(calib_folder_path, chess_shape) ###
5) Zobrazte všechny snímků z datasetu s vyznačenými body detekované šachovnice.¶
detected_images = list(chessboard_images.values())
...(*detected_images) ###
6) Zobrazte statistiku kalibrace kamery.¶
Reprojekční chyba, vnitřní parametry, distorzní parametry, jejich odchylky a další informace. Věnujte především pozornost ochylkám u parametrů a reprojekčním chybám u jednotlivých snímků.
detected_image_names = list(chessboard_images.keys())
pixel_size = ... ### use cameras datasheet to find physical pixel size of the sensor
...(reprojection_error, camera_matrix, dist_coeffs, std_deviations_intrinsics, per_view_errors, detected_image_names, pixel_size)
7) Opravte zdrojový obrázek z podúkolu č. 1) pomocí funkce na odstranění soudkovitosti. Oba obrázky zobrazte.¶
img_corrected = ...(img_distorsion, camera_matrix, dist_coeffs) ###
...(img_distorsion, titles=["Distorted image"]) ###
...(img_corrected, titles=["Undistorted image"]) ###