Introducere
Detectarea marginilor este ceva ce facem în mod natural, dar nu este la fel de ușor când vine vorba de definirea regulilor pentru computere. În timp ce au fost concepute diferite metode, metoda dominantă a fost dezvoltată de John F. Canny în 1986 și este numită în mod adecvat metoda Canny.
Este rapid, destul de robust și funcționează cam cel mai bine pentru tipul de tehnică care este. Până la sfârșitul ghidului, veți ști cum să efectuați detectarea marginilor în timp real pe videoclipuri și să produceți ceva de genul:
Canny Edge Detection
Ce este metoda Canny? Constă din patru operații distincte:
- netezire gaussiană
- Calcularea gradienților
- Suprimare non-max
- Limitarea histerezisului
netezire gaussiană este folosit ca prim pas pentru a „calca” imaginea de intrare și a atenua zgomotul, făcând rezultatul final mult mai curat.
Gradienți de imagine au fost utilizate în aplicații anterioare pentru detectarea marginilor. În special, filtrele Sobel și Scharr se bazează pe gradienți de imagine. Filtrul Sobel se reduce la două sâmburi (Gx și Gy), Unde Gx detectează modificări orizontale, în timp ce Gy detectează modificări verticale:
G
x
=
[
-
1
0
+
1
-
2
0
+
2
-
1
0
+
1
]
G
y
=
[
-
1
-
2
-
1
0
0
0
+
1
+
2
+
1
]
Când le glisați peste o imagine, fiecare va „prinde” (subliniază) liniile în orientarea lor respectivă. Nuezele Scharr funcționează în același mod, cu valori diferite:
G
x
=
[
+
3
0
-
3
+
10
0
-
10
+
3
0
-
3
]
G
y
=
[
+
3
+
10
+
3
0
0
0
-
3
-
10
-
3
]
Aceste filtre, odată transformate peste imagine, vor produce hărți de caracteristici:
Credit imagine: Davidwkennedy
Pentru aceste hărți de caracteristici, puteți calcula magnitudinea gradientului și orientarea gradientului – adică cât de intensă este schimbarea (cât de probabil este ca ceva să fie o margine) și în ce direcție este îndreptată schimbarea. Deoarece Gy denotă schimbarea verticală (gradient Y), iar Gx reprezintă schimbarea orizontală (gradient X) – puteți calcula mărimea prin simpla aplicare a teoremei lui Pitagora, pentru a obține ipotenuza triunghiului format de „stânga” și direcții „corecte”:
$$
{G} ={sqrt {{{G} _{x}}^{2}+{{G} _{y}}^{2}}}
$$
Folosind mărimea și orientarea, puteți produce o imagine cu marginile evidențiate:
Credit imagine: Davidwkennedy
Totuși – puteți vedea cât de mult zgomot s-a prins și din structura cărămizilor! Gradienții de imagine sunt foarte sensibili la zgomot. Acesta este motivul pentru care filtrele Sobel și Scharr au fost folosite ca componentă, dar nu singura abordare în metoda lui Canny. Netezirea gaussiană ajută și aici.
Suprimare non-max
O problemă notabilă cu filtrul Sobel este că marginile nu sunt chiar clare. Nu este ca și cum cineva a luat un creion și a tras o linie pentru a crea o imagine liniară a imaginii. Marginile de obicei nu sunt atât de clare în imagini, deoarece lumina difuzează treptat. Cu toate acestea, putem găsi linia comună în margini și suprimăm restul pixelilor din jurul ei, obținând în schimb o linie de separare curată și subțire. Acest lucru este cunoscut sub numele de Suprimare Non-Max! Pixelii non-max (cei mai mici decât cel cu care îi comparăm într-un câmp local mic, cum ar fi un nucleu 3×3) sunt suprimați. Conceptul este aplicabil la mai multe sarcini decât aceasta, dar să-l legăm de acest context pentru moment.
Limitarea histerezisului
Multe non-marchii pot și probabil vor fi evaluate ca margini, din cauza condițiilor de iluminare, a materialelor din imagine etc. Din cauza diferitelor motive pentru care apar aceste calcule greșite – este greu să faci o evaluare automată a ceea ce este și nu este o muchie. 't. Puteți limita gradienții și includeți doar pe cei mai puternici, presupunând că marginile „adevărate” sunt mai intense decât marginile „false”.
Limitarea funcționează în același mod ca de obicei – dacă gradientul este sub un prag mai mic, eliminați-l (reduceți-l la zero), iar dacă este peste un anumit prag superior, păstrați-l. Tot ceea ce este între limita inferioară și limita superioară se află în „zona gri”. Dacă orice margine dintre praguri este conectată la a marginea definitivă (cele peste prag) – sunt considerate și margini. Dacă nu sunt conectate, probabil ar fi arficate cu o margine greșit calculată.
Asta este prag de histerezis! De fapt, ajută la curățarea rezultatului final și la eliminarea marginilor false, în funcție de ceea ce clasificați drept margine falsă. Pentru a găsi valori de prag bune, veți experimenta în general cu diferite limite inferioare și superioare pentru praguri sau veți folosi o metodă automată, cum ar fi metoda lui Otsu sau metoda Triunghiului.
Să încărcăm o imagine și să o facem în tonuri de gri (Canny, la fel cum Sobel/Scharr necesită ca imaginile să fie în tonuri de gri):
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('finger.jpg', cv2.IMREAD_GRAYSCALE)
img_blur = cv2.GaussianBlur(img, (3,3), 0)
plt.imshow(img_blur, cmap='gray')
Imaginea de aproape a unui deget va servi ca un bun teren de testare pentru detectarea marginilor – nu este ușor să discerneți o amprentă din imagine, dar putem aproxima una.
Detectarea marginilor pe imagini cu cv2.Canny()
Algoritmul lui Canny poate fi aplicat folosind OpenCV Canny()
metodă:
cv2.Canny(input_img, lower_bound, upper_bound)
Consultați ghidul nostru practic și practic pentru a învăța Git, cu cele mai bune practici, standarde acceptate de industrie și fisa de cheat incluse. Opriți căutarea pe Google a comenzilor Git și de fapt învăţa aceasta!
Găsirea echilibrului corect între limita inferioară și limita superioară poate fi dificilă. Dacă ambele sunt scăzute - veți avea puține margini. Dacă limita inferioară este scăzută și superioară este ridicată, veți avea zgomot. Dacă ambele sunt înalte și apropiate unul de celălalt, veți avea puține margini. Locul potrivit are suficient spațiu între limite și le are pe scara potrivită. Experiment!
Imaginea de intrare va fi neclară prin metoda Canny, dar de multe ori, veți beneficia de estomparea acesteia înainte intra si el. Metoda aplică o estompare gaussiană de 5×5 la intrare înainte de a trece prin restul operațiunilor, dar chiar și cu această neclaritate, ceva zgomot poate trece, așa că am estompat imaginea înainte de a o introduce în algoritm:
edge = cv2.Canny(img_blur, 20, 30)
fig, ax = plt.subplots(1, 2, figsize=(18, 6), dpi=150)
ax[0].imshow(img, cmap='gray')
ax[1].imshow(edge, cmap='gray')
Rezultă:
Valorile 20
și 30
aici nu sunt arbitrare – am testat metoda pe diverși parametri și am ales un set care părea să producă un rezultat decent. Putem încerca să automatizăm asta?
Limitare automată pentru cv2.Canny()?
Puteți găsi un set optim de valori de prag? Da, dar nu funcționează întotdeauna. Puteți face propriul calcul pentru o valoare bună și apoi ajustați intervalul cu a sigma
în jurul acestui prag:
lower_bound = (1-sigma)*threshold
upper_bound = (1+sigma)*threshold
Cand sigma
, este să spunem, 0.33
– limitele vor fi 0.66*threshold
și 1.33*threshold
, permițând un interval de ~1/3 în jurul acestuia. Cu toate acestea, găsirea threshold
este ceea ce este mai dificil. OpenCV ne oferă metoda lui Otsu (funcționează excelent pentru imagini bi-modale) și metoda Triunghi. Să le încercăm pe ambele, precum și să luăm o mediană simplă a valorilor pixelilor ca a treia opțiune:
otsu_thresh, _ = cv2.threshold(img_blur, 0, 255, cv2.THRESH_OTSU)
triangle_thresh, _ = cv2.threshold(img_blur, 0, 255, cv2.THRESH_TRIANGLE)
manual_thresh = np.median(img_blur)
def get_range(threshold, sigma=0.33):
return (1-sigma) * threshold, (1+sigma) * threshold
otsu_thresh = get_range(otsu_thresh)
triangle_thresh = get_range(triangle_thresh)
manual_thresh = get_range(manual_thresh)
print(f"Otsu's Threshold: {otsu_thresh} nTriangle Threshold: {triangle_thresh} nManual Threshold: {manual_thresh}")
Rezultă:
Otsu's Threshold: (70.35, 139.65)
Triangle Threshold: (17.419999999999998, 34.58)
Manual Threshold: (105.18999999999998, 208.81)
Acestea sunt destul de diferite! Din valorile pe care le-am văzut înainte, putem anticipa metoda Triunghiului care funcționează cel mai bine aici. Pragul manual nu este foarte informat, deoarece ia doar valoarea mediană a pixelilor și ajunge să aibă un prag de bază ridicat, care este înmulțit în continuare într-o gamă largă pentru această imagine. Metoda lui Otsu suferă mai puțin din cauza asta, dar suferă totuși.
Dacă rulăm Canny()
metoda cu aceste intervale de prag:
edge_otsu = cv2.Canny(img_blur, *otsu_thresh)
edge_triangle = cv2.Canny(img_blur, *triangle_thresh)
edge_manual = cv2.Canny(img_blur, *manual_thresh)
fig, ax = plt.subplots(1, 3, figsize=(18, 6), dpi=150)
ax[0].imshow(edge_otsu, cmap='gray')
ax[1].imshow(edge_triangle, cmap='gray')
ax[2].imshow(edge_manual, cmap='gray')
Notă: Funcția așteaptă mai multe argumente, iar pragurile noastre sunt un singur tuplu. Noi putem destructură tuplu în mai multe argumente prefixându-l cu *
. Acest lucru funcționează și pe liste și seturi și este o modalitate excelentă de a furniza mai multe argumente după obținerea lor prin mijloace programatice.
Rezultă:
Metoda Triunghiului a funcționat destul de bine aici! Aceasta nu este o garanție că va funcționa bine și în alte cazuri.
Detectarea marginilor în timp real pe videoclipuri cu cv2.Canny()
În cele din urmă, să aplicăm detectarea marginilor Canny unui videoclip în timp real! Vom afișa videoclipul în curs de procesare (fiecare cadru așa cum este gata) folosind cv2.imshow()
care afișează o fereastră cu cadrul pe care dorim să-l afișam. Cu toate acestea, vom salva și videoclipul într-un fișier MP4 care poate fi ulterior inspectat și partajat.
Pentru a încărca un videoclip folosind OpenCV, folosim VideoCapture()
metodă. Dacă trecem înăuntru 0
– va înregistra de pe camera web curentă, astfel încât să puteți rula codul și pe camera dvs. web! Dacă introduceți un nume de fișier, acesta va încărca fișierul:
def edge_detection_video(filename):
cap = cv2.VideoCapture(filename)
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('output.mp4', fourcc, 30.0, (int(cap.get(3)), int(cap.get(4))), isColor=False)
while cap.isOpened():
(ret, frame) = cap.read()
if ret == True:
frame = cv2.GaussianBlur(frame, (3, 3), 0)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edge = cv2.Canny(frame, 50, 100)
out.write(edge)
cv2.imshow('Edge detection', edge)
else:
break
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
edge_detection_video('secret_video.mp4')
VideoWriter
acceptă mai mulți parametri – numele fișierului de ieșire, FourCC (patru coduri de codec, care indică codecul folosit pentru a codifica videoclipul), framerate și rezoluția ca tuplu. Pentru a nu ghici sau redimensiona videoclipul – am folosit lățimea și înălțimea videoclipului original, obținute prin VideoCapture
instanță care conține date despre videoclipul în sine, cum ar fi lățimea, înălțimea, numărul total de cadre etc.
În timp ce captura este deschisă, încercăm să citim următorul cadru cu cap.read()
, care returnează un cod de rezultat și următorul cadru. Codul rezultat este True
or False
, care denotă prezența cadrului următor sau o lipsă a acestuia. Numai când există un cadru, vom încerca să-l procesăm în continuare, altfel, vom întrerupe bucla. Pentru fiecare cadru valid, îl rulăm printr-o neclaritate gaussiană, îl convertim în tonuri de gri, rulăm cv2.Canny()
pe el și scrieți-l folosind VideoWriter
pe disc și afișați folosind cv2.imshow()
pentru o vizionare live.
În cele din urmă, lansăm captarea și writerul video, deoarece ambele lucrează cu fișiere de pe disc și distrug toate ferestrele existente.
Când rulați metoda cu a secret_video.mp4
intrare - veți vedea o fereastră pop-up și odată ce este terminată, un fișier în directorul dvs. de lucru:
Concluzie
În acest ghid, am aruncat o privire asupra modului în care funcționează detectarea marginilor Canny și a părților sale constitutive – netezire gaussiană, filtre Sobel și gradienți de imagine, suprimare non-max. și prag de histerezis. În cele din urmă, am explorat metode de căutare automată a intervalului de prag pentru detectarea marginilor Canny cu cv2.Canny()
, și a folosit tehnica pe un videoclip, oferind detectarea marginilor în timp real și salvând rezultatele într-un fișier video.
Mergând mai departe – Învățare profundă practică pentru viziunea computerizată
Natura ta curios te face să vrei să mergi mai departe? Vă recomandăm să verificați Curs: „Învățare profundă practică pentru viziunea computerizată cu Python”.
Un alt curs de Computer Vision?
Nu vom face clasificarea cifrelor MNIST sau a modei MNIST. Și-au servit rolul cu mult timp în urmă. Prea multe resurse de învățare se concentrează pe seturile de date de bază și pe arhitecturile de bază înainte de a lăsa arhitecturile avansate de tip cutie neagră să asume povara performanței.
Vrem să ne concentrăm asupra demistificare, practic, înţelegere, intuiţie și proiecte reale. Vreau sa invat cum poți face o diferență? Vă vom duce într-o plimbare de la modul în care creierul nostru procesează imaginile până la scrierea unui clasificator de învățare profundă de nivel de cercetare pentru cancerul de sân la rețele de învățare profundă care „halucinează”, învățându-vă principiile și teoria prin muncă practică, echipându-vă cu know-how și instrumente pentru a deveni un expert în aplicarea învățării profunde pentru a rezolva viziunea computerizată.
Ce e inauntru?
- Primele principii ale vederii și modul în care computerele pot fi învățate să „vadă”
- Diferite sarcini și aplicații ale vederii computerizate
- Instrumentele meseriei care vă vor ușura munca
- Găsirea, crearea și utilizarea seturilor de date pentru viziune computerizată
- Teoria și aplicarea rețelelor neuronale convoluționale
- Gestionarea deplasării de domeniu, apariției concomitente și a altor părtiniri în seturile de date
- Transfer Învățați și utilizați timpul de instruire și resursele de calcul ale altora în beneficiul dumneavoastră
- Construirea și formarea unui clasificator de ultimă generație pentru cancerul de sân
- Cum să aplicați o doză sănătoasă de scepticism ideilor principale și să înțelegeți implicațiile tehnicilor adoptate pe scară largă
- Vizualizarea unui „spațiu conceptual” al unui ConvNet folosind t-SNE și PCA
- Studii de caz despre modul în care companiile folosesc tehnicile de viziune computerizată pentru a obține rezultate mai bune
- Evaluarea corectă a modelului, vizualizarea spațiului latent și identificarea atenției modelului
- Efectuarea cercetărilor de domeniu, procesarea propriilor seturi de date și stabilirea de teste de model
- Arhitecturi de ultimă oră, progresul ideilor, ce le face unice și cum să le implementăm
- KerasCV – o bibliotecă WIP pentru crearea de conducte și modele de ultimă generație
- Cum să analizați și să citiți lucrările și să le implementați singur
- Selectarea modelelor în funcție de aplicația dvs
- Crearea unui canal de învățare automată de la capăt la capăt
- Peisaj și intuiție în detectarea obiectelor cu R-CNN-uri mai rapide, RetinaNets, SSD-uri și YOLO
- Instanță și segmentare semantică
- Recunoașterea obiectelor în timp real cu YOLOv5
- Instruirea detectoarelor de obiecte YOLOv5
- Lucrul cu Transformers folosind KerasNLP (bibliotecă WIP puternică în industrie)
- Integrarea Transformers cu ConvNets pentru a genera subtitrări ale imaginilor
- Deepdream
- Optimizarea modelului de Deep Learning pentru viziunea computerizată