- 1. Operazioni bit per bit e mascheramento
- 2. Convoluzione e sfocatura
- 3. Nitidezza - Invertendo le sfocature dell'immagine
- 4. Trebbiatura (binarizzazione)
- 5. Dilatazione, erosione, apertura / chiusura
- 6. Rilevamento dei bordi e gradienti dell'immagine
- 14. Prospettiva e trasformazione affine
- 8. Applicazione Live Sketch
Nei tutorial precedenti, abbiamo imparato a conoscere OpenCV e fatto alcune elaborazioni di base delle immagini e poi nel prossimo tutorial abbiamo fatto alcune manipolazioni delle immagini in OpenCV come ritaglio, rotazione, trasformazione delle immagini ecc. Quindi, in continuazione con il precedente tutorial sulla manipolazione delle immagini, qui impariamo alcune altre tecniche di manipolazione delle immagini come e alla fine del tutorial costruiremo un programma python-opencv per creare sketch dal vivo dal feed live della webcam. Questa applicazione utilizzerà molte delle funzioni di elaborazione delle immagini che abbiamo appreso finora o impareremo in questo tutorial, quindi questo sarà un buon esempio pratico per coprire tutte le funzioni.
Come detto nel tutorial precedente, OpenCV è Open Source Commuter Vision Library che ha interfacce C ++, Python e Java e supporta Windows, Linux, Mac OS, iOS e Android. Quindi può essere facilmente installato in Raspberry Pi con Python e ambiente Linux. E Raspberry Pi con OpenCV e telecamera collegata può essere utilizzato per creare molte applicazioni di elaborazione delle immagini in tempo reale come Face Detection, Face Lock, Object Tracking, Auto Number Plate Detection, Home Security System, ecc
In questo tutorial, vedremo alcune altre manipolazioni di immagini usando Python OpenCV. Qui impareremo ad applicare la seguente funzione su un'immagine usando Python OpenCV:
- Operazioni bit per bit e mascheramento
- Convoluzione e sfocatura
- Nitidezza: l'inversione delle sfocature dell'immagine
- Soglia (binarizzazione)
- Dilatazione, Erosione, Apertura / Chiusura
- Rilevamento dei bordi e gradienti dell'immagine
- Prospettiva e trasformazione affine
- Applicazione Live Sketch
1. Operazioni bit per bit e mascheramento
Le operazioni bit per bit ti aiutano a mascherare le immagini e ti aiutano a creare alcune semplici immagini.
Fare un quadrato
import cv2 import numpy come np # usiamo solo due dimensioni perché questa è un'immagine in scala di grigi, se stessimo usando un'immagine #colored, avremmo quindi usato un rettangolo = np.zeros ((300,300,3), np.uint8) # Creare un quadrato quadrato = np.zeros ((300,300), np.uint8) cv2.rectangle (quadrato, (50,50), (250,250), 255, -1) cv2.imshow ("quadrato", quadrato) cv2. waitKey (0)
Fare un'ellisse
ellipse = np.zeros ((300,300), np.uint8) cv2.ellipse (ellipse, (150,150), (150,150), 30,0,180,255, -1) cv2.imshow ("ellipse", ellipse) cv2.waitKey (0)
Sperimentare con operazioni bit per bit
#AND_ mostra solo il punto in cui i due si intersecano
BitwiseAND = cv2.bitwise_and (quadrato, ellisse) cv2.imshow ("AND", BitwiseAND) cv2.waitKey (0)
#OR_ mostra solo dove si trova il quadrato o l'ellisse
BitwiseOR = cv2.bitwise_or (quadrato, ellisse) cv2.imshow ("OR", BitwiseOR) cv2.waitKey (0)
#XOR_ mostra solo dove uno dei due esiste da solo
BitwiseXOR = cv2.bitwise_xor (quadrato, ellisse) cv2.imshow ("XOR", BitwiseXOR) cv2.waitKey (0)
#NOT_ mostra tutto ciò che non fa parte dell'ellisse e l' operazione NOT può essere applicata solo a una singola figura
BitwiseNOT_elp = cv2.bitwise_not (ellipse) cv2.imshow ("NOT_ellipse", BitwiseNOT_elp) cv2.waitKey (0) cv2.destroyAllWindows ()
2. Convoluzione e sfocatura
Una convoluzione è un'operazione matematica eseguita su due funzioni che producono una terza funzione che è tipicamente una versione modificata della funzione originale.
Immagine di output = immagine Funzione Dimensione del kernel
Nella visione artificiale utilizziamo il kernel per specificare la dimensione su cui eseguiamo la nostra funzione di manipolazione sulla nostra immagine.
La sfocatura è un'operazione in cui calcoliamo la media dei pixel all'interno di una regione (kernel)
OpenCV sfoca un'immagine applicando i kernel, un kernel ti dice come cambiare il valore di un dato pixel combinandolo con una quantità diversa di pixel vicini il kernel viene applicato a ogni pixel dell'immagine uno per uno per produrre l'immagine finale.
Semplicemente dicendo, una convoluzione dell'immagine è semplicemente una moltiplicazione saggia di due matrici seguita da una somma.
Possiamo semplicemente capirlo con il seguente esempio.
Quanto sopra è un kernel 3X3.
Moltiplichiamo per 1/25 per normalizzare cioè sommando a 1 abbiamo aumentato l'intensità o diminuito l'intensità come nel caso dello schiarimento o dell'oscuramento delle immagini.
Testiamo un metodo di sfocatura opencv filter2D, dato dalla funzione cv2.filter2D (immagine, -1, kernel)
importa cv2 importa numpy come immagine np = cv2.imread ('elephant.jpg') cv2.imshow ('originale', immagine) cv2.waitKey (0)
#creazione di una matrice del kernel 3x3
kernel_3x3 = np.ones ((3,3), np.float32) / 9
# usiamo cv2.filter2D per convolgere il kernel con un'immagine
sfocato = cv2.filter2D (immagine, -1, kernel_3x3) cv2.imshow ('3x3_blurring', sfocato) cv2.waitKey (0)
#creazione di una matrice del kernel 7x7
kernel_7x7 = np.ones ((7,7), np.float32) / 49
# usiamo cv2.filter2D per convolgere il kernel con un'immagine
sfocato = cv2.filter2D (immagine, -1, kernel_7x7) cv2.imshow ('7x7_blurring', sfocato) cv2.waitKey (0) cv2.destroyAllWindows ()
Esistono anche altri tipi di metodi di sfocatura:
cv2.blur - Calcola la media del valore su una finestra specificata.
cv2.GaussianBlur - Simile ma utilizza una finestra gaussiana (maggiore enfasi sui punti attorno al centro).
cv2.medianBlur– Utilizza la mediana di tutti gli elementi nella finestra.
cv2.bilateralFilter– Sfoca mantenendo i bordi nitidi, preserva i bordi ei dettagli delle linee.
Vedremo uno per uno di seguito, prima visualizza l'immagine originale usando il codice sottostante:
importa cv2 importa numpy come immagine np = cv2.imread ('elephant.jpg') cv2.imshow ('originale', immagine) cv2.waitKey (0)
cv2.blur:
In questo metodo la media viene eseguita convolgendo l'immagine con un box filter normalizzato, questo prende posto sotto il box e sostituisce l'elemento centrale. Qui la dimensione della scatola deve essere strana e positiva .
# cv2.blur blur = cv2.blur (image, (3,3)) cv2.imshow ('Averaging', blur) cv2.waitKey (0)
cv2.GaussianBlur:
# cv2.GaussianBlur #Invece del box filter, proviamo Gaussian kernel Gaussian = cv2.GaussianBlur (image, (7,7), 0) cv2.imshow ('Gaussian blurring', Gaussian) cv2.waitKey (0)
cv2.medianBlur:
Prende la mediana di tutti i pixel sotto l'area del kernel e l'elemento centrale viene sostituito con questo valore mediano.
# cv2.medianBlur # prende la mediana di tutti i pixel sotto l'area del kernel e l'elemento centrale # viene sostituito con questo valore mediano. mediana = cv2.medianBlur (foto 5) cv2.imshow ('mediana sfocatura', mediana) cv2.waitKey (0)
cv2.bilateralFilter:
Bilaterale è molto efficace nella rimozione del rumore mantenendo i bordi affilati
# cv2.bilateralFilter #Bilateral è molto efficace nella rimozione del rumore mantenendo i bordi nitidi bilaterale = cv2.bilateralFilter (image, 9,75,75) cv2.imshow ('bilateral blurring', bilateral) cv2.waitKey (0) cv2. distruggereAllWindows ()
Image De-noising-non Local significa Denoising
importa cv2 importa numpy come immagine np = cv2.imread ('elephant.jpg') cv2.imshow ('originale', immagine) cv2.waitKey (0)
#parameter dopo None è la forza del filtro 'h' (5-10 è un buon intervallo) #next è h per i componenti del colore, impostare di nuovo lo stesso valore di h
dst = cv2.fastNlMeansDenoisingColored (image, None, 6,6,7,21) cv2.imshow ('Fast means denois', dst) cv2.waitKey (0) cv2.destroyAllWindows ()
Esistono 4 varianti di denoising mezzi non locali
cv2.fastNlMeansDenoising () - per una singola immagine in scala di grigi
cv2.fastNlMeansDenoisingColored () - Immagine a un colore
cv2.fastNlmeansDenoisingMulti () - per la sequenza di immagini in scala di grigi
cv2.fastNlmeansDenoisingcoloredMulti () - per sequenze di immagini colorate
3. Nitidezza - Invertendo le sfocature dell'immagine
La nitidezza è l'opposto della sfocatura, rafforza o enfatizza i bordi dell'immagine.
Kernel =,,
La nostra matrice del kernel somma fino a uno, quindi non è necessario normalizzare (cioè moltiplicare per un fattore alla stessa luminosità dell'originale), se il kernel non è normalizzato a 1 l'immagine sarebbe più luminosa o più scura.
importa cv2 importa numpy come immagine np = cv2.imread ('elephant.jpg') cv2.imshow ('originale', immagine) cv2.waitKey (0)
kernel_sharpening = np.array (,
])
#applicare il kernel di nitidezza all'immagine di input
sharpened = cv2.filter2D (image, -1, kernel_sharpening) cv2.imshow ('sharpened image', sharpened) cv2.waitKey (0) cv2.destroyAllWindows ()
4. Trebbiatura (binarizzazione)
La soglia è l'azione di convertire un'immagine in forma binaria. In opencv esiste una funzione separata per la soglia definita come
Cv2.threshold (immagine, valore di soglia, valore massimo, tipo di soglia)
Esistono i seguenti tipi di soglia:
- cv2.THRESH_BINARY - il più comune
- cv2. THRESH_BINARY_INV - più comune
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2. THRESH_TOZERO_INV
NOTA: l'immagine deve essere convertita in scala di grigi prima della soglia
importa cv2 importa numpy come np # carica immagine come immagine in scala di grigi = cv2.imread ('gradiente.jpg', 0) cv2.imshow ('originale', immagine) cv2.waitKey (0)
#valore inferiore a 127 va a 0 (nero) e superiore a 127 va a 255 (bianco)
_, thresh1 = cv2.threshold (image, 127,255, cv2.THRESH_BINARY) cv2.imshow ('1 threshold', thresh1) cv2.waitKey (0)
# il valore inferiore a 127 va a 255 e i valori superiori a 127 vanno a 0 (al contrario di sopra)
_, thresh2 = cv2.threshold (immagine, 127,255, cv2.THRESH_BINARY_INV) cv2.imshow ('2 threshold', thresh2) cv2.waitKey (0)
#valori superiori a 127 vengono troncati (mantenuti) a 127, l'argomento 255 è inutilizzato.
_, thresh3 = cv2.threshold (image, 127,255, cv2.THRESH_TRUNC) cv2.imshow ('3 thresh trunc', thresh3) cv2.waitKey (0)
# i valori inferiori a 127 vanno a 0, quelli superiori a 127 non vengono modificati
_, thresh4 = cv2.threshold (image, 127,255, cv2.THRESH_TOZERO) cv2.imshow ('4 threshold', thresh4) cv2.waitKey (0)
#Revesrse di sopra, sotto 127 è invariato, sopra 127 va a zero
_, thresh5 = cv2.threshold (immagine, 127,255, cv2.THRESH_TOZERO_INV) cv2.imshow ('soglia 5', thresh5) cv2.waitKey (0) cv2.destroyAllWindows ()
5. Dilatazione, erosione, apertura / chiusura
Queste sono le operazioni nel campo della morfologia matematica
Dilatazione: aggiunge pixel ai bordi dell'oggetto in un'immagine.
Erosione: rimuove i pixel ai bordi dell'oggetto in un'immagine.
Apertura - Erosione seguita da dilatazione.
Chiusura - Dilatazione seguita da erosione.
L'apertura è molto utile per il denoising delle immagini poiché prima assottiglia l'immagine per erosione (rimuove il rumore) e poi la dilata.
Confusione con dilatazione ed erosione
A volte c'è confusione tra dilatazione ed erosione di solito nelle immagini con sfondo bianco, poiché opencv considera lo sfondo bianco come un'immagine da dilatare o erosa invece dell'immagine originale, quindi in questo caso l'erosione funziona come dilatazione e viceversa, come mostrato nell'immagine campione mostrato sotto.
Ricorda, Dilatazione aggiunge pixel ai bordi degli oggetti in un'immagine mentre Erosione rimuove i pixel ai bordi degli oggetti in un'immagine
importa cv2 importa numpy come immagine np = cv2.imread ('imagecv.png', 0) cv2.imshow ('originale', immagine) cv2.waitKey (0)
#Erosion
# definiamo la dimensione del nostro kernel
kernel = np.ones ((5,5), np.uint8)
#Ora noi erodiamo l'immagine, qui l'iterazione non è il caso in cui vuoi erodere l'immagine
erosione = cv2.erode (immagine, kernel, iterazioni = 1) cv2.imshow ('Erosione', erosione) cv2.waitKey (0)
#dilatazione
dilation = cv2.dilate (immagine, kernel, iterazioni = 1) cv2.imshow ('dilation', dilation) cv2.waitKey (0)
#opening, buono per rimuovere il rumore
opening = cv2.morphologyEx (immagine, cv2.MORPH_OPEN, kernel) cv2.imshow ('opening', opening) cv2.waitKey (0)
#closing, ottimo per rimuovere il rumore
closing = cv2.morphologyEx (immagine, cv2.MORPH_CLOSE, kernel) cv2.imshow ('closing', closing) cv2.waitKey (0) cv2.destroyAllWindows ()
6. Rilevamento dei bordi e gradienti dell'immagine
Il rilevamento dei bordi è un'area molto importante nella visione artificiale, specialmente quando si tratta di contorni.
I bordi possono essere definiti come confini dell'immagine, in realtà sono bordi che definiscono l'oggetto nelle immagini che conservano molte informazioni sull'immagine.
Formalmente I bordi possono essere definiti come cambiamenti improvvisi (discontinuità) in un'immagine e possono codificare tante informazioni quanti pixel.
L'immagine sopra mostra come la visione artificiale identifica e riconosce l'immagine.
Algoritmi di rilevamento dei bordi: - Esistono tre tipi principali di algoritmi di rilevamento dei bordi
- Sobel - per enfatizzare le immagini verticali o orizzontali.
- Laplaciano: ottimale grazie al basso tasso di errore, bordi ben definiti e rilevamento accurato.
- Algoritmo di rilevamento Canny Edge (sviluppato da john.F.Canny nel 1986)
1. Applica la sfocatura gaussiana
2. Trova il gradiente di intensità dell'immagine
3. applica una soppressione non massima (ovvero rimuove i pixel che non sono bordi).
4. L'isteresi applica la soglia (cioè se il pixel si trova all'interno della soglia superiore e inferiore, viene considerato come un bordo)
importa cv2 importa numpy come np image = cv2.imread ('input.jpg', 0) altezza, larghezza = immagine.shape
#sobel
#estrazione dei bordi sobri
sobel_x = cv2.Sobel (immagine, cv2.CV_64F, 0,1, ksize = 5) sobel_y = cv2.Sobel (immagine, cv2.CV_64F, 1,0, ksize = 5) cv2.imshow ('originale', immagine) cv2.waitKey (0) cv2.imshow ('sobelx', sobel_x) cv2.waitKey (0)
#Sobely
cv2.imshow ('sobely', sobel_y) cv2.waitKey (0)
sobel_OR = cv2.bitwise_or (sobel_x, sobel_y) cv2.imshow ('sobelOR', sobel_OR) cv2.waitKey (0)
#laplaian
laplacian = cv2.Laplacian (immagine, cv2.CV_64F) cv2.imshow ('Laplacian', laplacian) cv2.waitKey (0)
#canny edge detection algoritmo utilizza valori di gradiente come soglie
#in astuzia dobbiamo fornire due valori: soglia1 e soglia2.
# qualsiasi gradiente maggiore della soglia 2 è considerato un bordo.
#qualsiasi gradiente maggiore della soglia 1 è considerato non un bordo.
# i valori tra la soglia 1 e la soglia 2 sono o come bordo o non-bordo
# sul modo in cui le loro intensità sono collegate, in questo caso qualsiasi valore inferiore a 60 è considerato
#non bordi mentre qualsiasi valore superiore a 120 è considerato come bordo.
canny = cv2.Canny (image, 60,120) cv2.imshow ('canny', canny ) cv2.waitKey (0) cv2.destroyAllWindows ()
14. Prospettiva e trasformazione affine
Facciamo un passo indietro e diamo un'occhiata alle trasformazioni affini e non affini, l'immagine originale mostrata di seguito è chiaramente un'immagine non affine poiché i bordi si incontreranno ad un certo punto, tuttavia possiamo raddrizzarla deformando e prendendo la prospettiva trasformare.
Per questa trasformazione prospettica abbiamo bisogno delle quattro coordinate dell'immagine originale e quindi dei quattro punti dell'immagine di output, sono indicati da points_A e points_B. In primo luogo con l'aiuto di questi punti calcoliamo una matrice di trasformazione, M con l'aiuto della funzione getPerspectiveTransform.
E poi questa matrice viene data alla funzione warpPerspective per generare l'output finale.
Ora proviamo prima la trasformazione Prospettiva.
importa cv2 importa numpy come np importa matplotlib.pyplot come immagine plt = cv2.imread ('paper.jpg') cv2.imshow ('originale', immagine) cv2.waitKey (0)
#coordinata dei 4 angoli dell'immagine originale
points_A = np.float32 (,,,])
#coordinate dei 4 angoli dell'output desiderato
#usiamo un rapporto di un foglio A4 1: 1,41
points_B = np.float32 (,,,])
# usa i due set di due punti per calcolare la matrice di trasformazione prospettica , M
M = cv2.getPerspectiveTransform (points_A, points_B) warped = cv2.warpPerspective (image, M, (420,594)) cv2.imshow ('warpprespective', warped ) cv2.waitKey (0) cv2.destroyAllWindows ()
La trasformazione affine è più facile della trasformazione non affine poiché abbiamo bisogno di solo tre punti per ottenere la trasformazione. L'intero processo procede allo stesso modo, ma invece della trasformazione prospettica ora abbiamo una trasformazione affine e definiamo colonne e righe in warpAffine dalla funzione forma invece di inserirla manualmente.
importa cv2 importa numpy come np importa matplotlib.pyplot come immagine plt = cv2.imread ('box.jpg') righe, cols = image.shape cv2.imshow ('originale', immagine) cv2.waitKey (0)
#coordinata di 3 angoli dell'immagine originale
points_A = np.float32 (,,])
#coordinate di 3 angoli dell'output desiderato
#usiamo un rapporto di un foglio A4 1: 1,41
points_B = np.float32 (,,])
# usa i due set di due punti per calcolare la matrice #transformation Affine
, M
M = cv2.getAffineTransform (points_A, points_B) warped = cv2.warpAffine (image, M, (cols, rows)) cv2.imshow ('warpaffine', warped ) cv2.waitKey (0) cv2.destroyAllWindows ()
8. Applicazione Live Sketch
Prima di tutto, congratulati con te stesso per aver realizzato questo mini progetto dopo aver letto tutte le funzioni di manipolazione delle immagini sopra. Quindi in questo mini progetto di Python OpenCV impareremo alcuni nuovi concetti di loop e funzioni. Se hai familiarità con la programmazione, devi avere un'idea più ampia di cosa siano la funzione e i loop. Tuttavia, in Python il concetto di base di cicli e funzioni rimane lo stesso ma il metodo per definirli cambia leggermente.
Quindi all'inizio di questo programma possiamo vedere un certo gruppo di istruzioni sotto la voce " def sketch (immagine): " questa è una definizione formale di una funzione un gruppo di istruzioni che lavorano insieme per un certo output.
Quindi questo schizzo è una funzione, in python la funzione è definita da "def" e termina con un segno ":". Anche le istruzioni che devono essere all'interno della funzione o si può dire quali sono necessarie affinché la funzione funzioni correttamente, vengono allineate automaticamente dalla funzione. Quindi, per uscire dalle funzioni, le istruzioni dovevano essere completamente allineate a sinistra. Per ulteriori riferimenti potete fare riferimento a google su come vengono definite le funzioni in python.
Quindi in questa funzione di schizzo abbiamo introdotto diversi livelli di elaborazione delle immagini che si combinano insieme per fornire un output. In primo luogo, l'immagine viene convertita in scala di grigi in modo che l'opencv possa elaborarla facilmente e quindi viene applicata una sfocatura gaussiana all'immagine in scala di grigi in modo da ridurre il rumore. Quindi i bordi vengono estratti con l'aiuto dell'algoritmo di rilevamento dei bordi del canny, quindi viene applicato un inverso binario sull'immagine definita dal bordo, qui l'inverso binario potrebbe anche essere fatto da bitwise_NOT ma abbiamo scelto deliberatamente questa inversa binaria di soglia in quanto dà libertà per impostare i suoi parametri fino a ottenere un'immagine chiara.
Inoltre da notare che la funzione prende l'immagine degli argomenti e restituisce i due argomenti ret e mask. Mentre ret è il booleano che dice che la funzione viene eseguita correttamente o meno e la maschera è l'output finale della funzione, ovvero l'immagine elaborata.
Quindi il secondo concetto è di far funzionare la webcam in opencv che è fatto dalla funzione cv2.VideoCapture (0) , che memorizza l'immagine in un oggetto cap che può essere letto con la funzione cap.read () , anche qui per notare quel cap. read () è all'interno del ciclo while infinito poiché doveva catturare continuamente le immagini, per dargli un senso di un video dal vivo, dove il frame rate del video sarebbe il frame rate della tua webcam che è per lo più compreso tra 24 e 60 fps.
cap.read () restituisce ret e frame, dove ret è il booleano che indica che la funzione è stata eseguita correttamente o meno e il frame contiene l'immagine presa dalla webcam.
Di seguito è riportato il codice Python OpenCV completo per l'esecuzione di Live Sketch
importa cv2 importa numpy come np #sketch che genera la funzione def sketch (immagine): #converte l'immagine in scala di grigi img_gray = cv2.cvtColor (image, cv2.COLOR_BGR2GRAY) # ripulire l'immagine usando la sfocatura gaussiana img_gray_blur = cv2.GaussianBlur (img_gray 5,5), 0) #extract edge canny_edges = cv2.Canny (img_gray_blur, 10,70) #do an invert binarizza l'immagine ret, mask = cv2.threshold (canny_edges, 70,255, cv2.THRESH_BINARY_INV) return mask #initialize webcam, tappo è l'oggetto fornito da video di cattura #it contiene un booleano che indica in caso di successo (RET) # contiene anche le immagini raccolte dalla webcam (frame) cap = cv2.VideoCapture (0) mentre True: ret, frame = cap.read () cv2.imshow ('livesketcher', sketch (frame)) if cv2.waitKey (1) == 13: # 13 è la chiave di accesso interrompi #release camera and close window, ricordatevi di rilasciare la webcam con l'aiuto di cap.release () cap.release () cv2.destroyAllWindows ()
Quindi questa è la fine della Parte 2 della manipolazione delle immagini in Python-OpenCV. Per capire bene la visione artificiale e OpenCV, consulta gli articoli precedenti (Iniziare con Python OpenCV e Manipolazioni di immagini in Python OpenCV (Parte 1) e sarai in grado di creare qualcosa di interessante con Visione artificiale.