Perspektiva obrazu - měření závitu¶
Cvičení je pokračováním cvičení zaměřeného na práci s polárními souřadnicemi při využití nestandardních 360° objektivů od firmy Opto Engineering. Způsob použití takových objektivů je demonstrován v tutoriálu na stránkách výrobce. Ve cvičení jsou použita data získaná z optického systému typu boroskopická sonda.
Boroskopická sonda¶
Boroskopická sonda díky zrcadlu umožňuje podívat se 360 ° dokola kolem sebe. Typickými aplikacemi jsou průmyslové inspekce děr či kontroly správnosti závitů.
Teorie k měření¶
Matice s metrickým závitem jsou podle norem ČSN ISO 261, 262 definovány pomocí písmene M
a číslice průměru závitu
v názvu. Dále jsou definovány veličiny stoupání závitu
, které lze rozdělit na standardní, m (metric) a jemná stoupání, m-f, m-f2, m-f3 (metric-fine). Průměr závitu (D) je definován v mm, stoupání závitu (P) je také definováno v mm.
Specifickou veličinou je úhel stoupání
($\varphi$), který může být využit jako poznávací znamení. Je definován jako:
$$\varphi = \arctan \left(\frac{P}{\pi D} \right)$$
Obrázky i vzorce jsou přejaty z webu ZDE. Stejně tak tam lze najít více informací k tématu, pokud by někoho zaujalo.
Import knihoven a konfigurace¶
Některé funkce jsou k dispozici ve vlastním souboru s názvem library.py
. Jedná se hlavně o drobnosti použitelné pro tohle cvičení.
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
from improutils import *
np.set_printoptions(precision=3)
%matplotlib inline
%run library.py
<Figure size 432x288 with 0 Axes>
Pomocné funkce¶
Z následujících funkcí je potřeba vybírat ty vhodné pro splnění úkolu.
Seznam funkcí pro přehlednost:
Úkol¶
Cílem úlohy je poznat, která matice byla snímána pomocí boroskopické sondy. Následujícím způsobem jsou zadány hodnoty jednotlivých matic s metrickým závitem.
Název | D (mm) | P, m (mm) | P, m-f (mm) | P, m-f2 (mm) |
---|---|---|---|---|
M22 | 22 | 2.5 | 2 | 1.5 |
M24 | 24 | 3 | 2 | 1.5 |
M30 | 30 | 3.5 | 2 | 1.5 |
M36 | 36 | 4 | 3 | 2 |
atd.
Obrázek ukazuje, co je to matice a jejich různé velikosti. Je čistě ilustrační.
# Databáze matic z normy
# name: d, m, f, f2
nuts = {
'M22': [22, 2.5, 2, 1.5],
'M24': [24, 3, 2, 1.5],
'M30': [30, 3.5, 2, 1.5],
'M36': [36, 4, 3, 2],
'M42': [42, 4.5, 3, 2],
'M48': [48, 5, 3, 2],
'M52': [52, 5, 3, 2],
'M56': [56, 5.5, 4, 2],
'M60': [60, 5.5, 4, 2],
'M64': [64, 6, 4, 3],
'M68': [68, 6, 4, 3],
'M72': [72, 6, 4, 2],
'M76': [76, 6, 4, 2],
'M80': [80, 6, 4, 2],
'M90': [90, 6, 4, 2],
'M100': [100, 6, 4, 2],
'M110': [110, 6, 4, 2],
'M120': [120, 6, 4, 2],
'M125': [125, 6, 4, 2]
}
Ps = ['m', 'm-f', 'm-f2']
1) Načtení a předzpracování¶
Načtěte obrázek matice snímané pomocí boroskopické sondy. Obrázek je čtvercový. Vytvořte z něj obdélníkový obrázek závitu pomocí vhodného převodu mezi souřadnými systémy. Rotujte obrázek tak, aby vnitřek kruhu byl na spodní straně obdélníku (viz dokumentace OpenCV). Obrázky zobrazte.
image_path = 'data/boro_nut.png' ### cesta k obrázku
image_grey = to_gray(load_image(image_path)) ### načtení obrazu
plot_images(image_grey)
image_trans = warp_to_cartesian(image_grey) ### správná transformace
print(image_trans.shape)
plot_images(image_trans)
img_rotated = rotate(image_trans, 90) ###
# Zobrazí obrázky
plot_images(image_grey, image_trans)
plot_images(img_rotated)
(2079, 662)
2) Segmentace¶
Automaticky segmentujte část obrazu (vytvořte masku) obsahující pouze závit. Ořízněte obrázek podle vytvořené masky - výsledek lze vylepšit přidáním konstanty na ořez nahoře a dole, kde je závit špatně viditelný. Zobrazte obrázek.
img_bin = segmentation_auto_threshold(img_rotated) ### segmentace
tl_x, tl_y, w, h = cv2.boundingRect(img_bin)
print(img_rotated.shape)
crop_const = 25 ### vlastní konstanta
img_crop = crop(img_rotated, tl_x, tl_y + crop_const, tl_x + w, tl_y + h - crop_const) ### ořez
plot_images(img_crop)
(662, 2079)
3) Detekce závitů¶
Pro předzpracování obrazu využijte filtr vhodný pro zachování hran. Seznamte se a experimentujte s hranovým detektorem typu Canny pro detekci hran - závitů. Obrázek hran zobrazte.
img_filtered = filtration_median(img_crop, 5) ###
# img_filtered = img_crop
# img_filtered = cv2.Laplacian(img_crop, cv2.CV_64F)
plot_images(img_filtered)
img_edges = cv2.Canny(img_filtered, 0, 255) ### hranový detektor s vhodnými parametry
plot_images(img_edges)
4) Zisk geometrických charakteristik¶
Aproximujte nalezené hrany pomocí přímek (úseček). K aproximaci se seznamte a experimentujte s metodou Houghovy (čti hafovy) transformace. Obzvlášť vhodná je metoda pravděpodobnostní Houghovy transformace (HoughLinesP
).
Nastavte parametry funkce tak, aby hledala pouze delší čáry (ideálně delší než 300 px klidně s větší mezerou). Vhodný počet čar jsou jednotky až desítky. Samozřejmě ideální čáry jsou ty, které kopírují směr závitu.
Vykreslete čáry do obrázku a ten zobrazte. Můžete využít funkci draw_lines()
.
# linesP = cv2.HoughLinesP(img_edges, , ..., ..., ..., ..., ...) ### transformace s vhodnými parametry
linesP = cv2.HoughLinesP(img_edges, 1, 3.14159265359/180, 80, 30, 10) ### transformace s vhodnými parametry
linesP = cv2.HoughLinesP(img_edges, 1, 3.14159265359/180, 80, None, 30, 10) ### transformace s vhodnými parametry
img_lines = draw_lines(img_edges, linesP) ### kreslení
plot_images(img_lines)
5) Spočítejte úhel stoupání závitu¶
Pro všechny nalezené přímky spočítejte úhel stoupání závitu
.
Vzhledem k nedokonalosti v převodu obrazu z polárních souřadnic je vhodné nalezené přímky filtrovat s použitím spočteného úhlu a délky. Nemá smysl započítávat přímky, jejichž pomyslný trojúhelník žádný úhel nesvírá, stejně tak, jako přímky kratší než např. polovina délky snímku.
Použijte vhodnou metodu pro určení jedné hodnoty úhlu stoupání ze všech spočtených. Hodnotu úhlu stoupání zobrazte ve stupních.
print(linesP)
[[[ 999 66 1033 66]] [[1465 189 1821 183]] [[ 441 16 736 16]] ... [[1092 142 1164 140]] [[ 920 15 1022 15]] [[1495 160 1532 159]]]
angles = list()
for line in linesP:
### výpočet
line = line[0]
x, y = line[2] - line[0], line[3] - line[1]
norm = np.linalg.norm([x, y])
angle = np.arccos(np.clip(np.dot([x/norm, y/norm], [1, 0]), -1.0, 1.0))
# vhodná podmínka
if angle > 0:
angles.append(angle)
# print(angles)
# angle_rad = np....(angles) ### vhodná metoda
angle_rad = np.mean(angles)
print(str(angle_rad) + ' rad')
angle_deg = np.degrees(angle_rad) ### převod
print(str(angle_deg) + ' °')
0.02052312938468789 rad 1.1758886961435382 °
6) Bonusová část - Identifikujte matici¶
Nalezněte konkrétní typ snímané matice z databáze nuts
(proměnná zadefinovaná výše). Výsledek vypište ve tvaru: název, typ stoupání závitu
.
Co dalšího byste potřebovali vědět pro ještě přesnější identifikaci matice?
𝜑=arctan(𝑃𝜋𝐷)
### Výpočty a klasifikace
# print(Ps)
# D, P
angles = []
for k, v in nuts.items():
d = v[0]
p = v[1]
angle = np.arctan(p/(np.pi*d))
angle = np.degrees(angle)
angles.append(angle)
# print(angle)
# print(v)
diff = []
for angle in angles:
diff.append(abs(angle - angle_deg))
# print(nuts.keys())
k = list(nuts.keys())
k[np.argmin(diff)]
'M90'