- 1. Opérations et masquage au niveau du bit
- 2. Convolution et flou
- 3. Netteté - Inverser le flou de l'image
- 4. Threshoding (binarisation)
- 5. Dilatation, érosion, ouverture / fermeture
- 6. Détection des bords et dégradés d'image
- 14. Perspective et transformation affine
- 8. Application Live Sketch
Dans les didacticiels précédents, nous avons découvert OpenCV et effectué un traitement d'image de base, puis dans le didacticiel suivant, nous avons effectué des manipulations d'images dans OpenCV comme le recadrage, la rotation, la transformation d'image, etc. quelques autres techniques de manipulation d'image comme et à la fin du didacticiel, nous allons créer un programme python-opencv pour créer un croquis en direct à partir du flux en direct de la webcam. Cette application utilisera de nombreuses fonctions de traitement d'image que nous avons apprises jusqu'à présent ou que nous allons apprendre dans ce tutoriel, ce sera donc un bon exemple pratique pour couvrir toutes les fonctions.
Comme indiqué dans le didacticiel précédent, OpenCV est une bibliothèque Open Source Commuter Vision qui a des interfaces C ++, Python et Java et prend en charge Windows, Linux, Mac OS, iOS et Android. Il peut donc être facilement installé dans Raspberry Pi avec l'environnement Python et Linux. Et Raspberry Pi avec OpenCV et caméra connectée peut être utilisé pour créer de nombreuses applications de traitement d'image en temps réel telles que la détection de visage, le verrouillage du visage, le suivi d'objet, la détection de plaque d'immatriculation de voiture, le système de sécurité domestique, etc.
Dans ce tutoriel, nous allons voir d'autres manipulations d'images à l'aide de Python OpenCV. Ici, nous allons apprendre à appliquer la fonction suivante sur une image en utilisant Python OpenCV:
- Opérations au niveau du bit et masquage
- Convolution et flou
- Netteté - Inversion du flou de l'image
- Seuil (binarisation)
- Dilatation, érosion, ouverture / fermeture
- Détection des contours et dégradés d'image
- Perspective et transformation affine
- Application d'esquisse en direct
1. Opérations et masquage au niveau du bit
Les opérations au niveau du bit vous aident à masquer l'image et vous aident à créer des images simples.
Faire un carré
import cv2 import numpy as np # nous n'utilisons que deux dimensions car il s'agit d'une image en niveaux de gris, si nous utilisions une image #colored, nous avions alors utilisé un rectangle = np.zeros ((300,300,3), np.uint8) # Faire un carré carré = np.zeros ((300,300), np.uint8) cv2.rectangle (carré, (50,50), (250,250), 255, -1) cv2.imshow ("carré", carré) cv2. waitKey (0)
Faire une ellipse
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)
Expérimenter des opérations au niveau du bit
#AND_ montre seulement où les deux se croisent
BitwiseAND = cv2.bitwise_and (carré, ellipse) cv2.imshow ("AND", BitwiseAND) cv2.waitKey (0)
#OR_ montre uniquement où se trouve le carré ou l'ellipse
BitwiseOR = cv2.bitwise_or (carré, ellipse) cv2.imshow ("OR", BitwiseOR) cv2.waitKey (0)
#XOR_ montre seulement où l'un ou l'autre existe par lui-même
BitwiseXOR = cv2.bitwise_xor (carré, ellipse) cv2.imshow ("XOR", BitwiseXOR) cv2.waitKey (0)
#NOT_ montre tout ce qui ne fait pas partie de l'ellipse et l' opération NON ne peut être appliquée qu'à une seule figure
BitwiseNOT_elp = cv2.bitwise_not (ellipse) cv2.imshow ("NOT_ellipse", BitwiseNOT_elp) cv2.waitKey (0) cv2.destroyAllWindows ()
2. Convolution et flou
Une convolution est une opération mathématique effectuée sur deux fonctions produisant une troisième fonction qui est typiquement une version modifiée de la fonction originale.
Image de sortie = image Fonction Taille du noyau
En vision par ordinateur, nous utilisons le noyau pour spécifier la taille sur laquelle nous exécutons notre fonction de manipulation sur notre image.
Le flou est une opération où l'on fait la moyenne des pixels dans une région (noyau)
OpenCV brouille une image en appliquant des noyaux, un noyau vous indique comment changer la valeur d'un pixel donné en le combinant avec une quantité différente de pixels voisins, le noyau est appliqué à chaque pixel de l'image un par un pour produire l'image finale.
En termes simples, une convolution d'image est simplement une multiplication élément par élément de deux matrices suivie d'une somme.
Nous pouvons simplement le comprendre par l'exemple suivant.
Ce qui précède est un noyau 3X3.
Nous multiplions par 1/25 pour normaliser, c'est-à-dire que nous additionnons à 1 nous avions augmenté ou diminué l'intensité comme dans le cas de l'éclaircissement ou de l'assombrissement des images.
Testons une méthode de flou opencv filter2D, donnée par la fonction cv2.filter2D (image, -1, kernel)
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', image) cv2.waitKey (0)
# création d'une matrice de noyau 3x3
kernel_3x3 = np.ones ((3,3), np.float32) / 9
# nous utilisons cv2.filter2D pour convoluer le noyau avec une image
flou = cv2.filter2D (image, -1, noyau_3x3) cv2.imshow ('flou_3x3', flou) cv2.waitKey (0)
# création d'une matrice de noyau 7x7
kernel_7x7 = np.ones ((7,7), np.float32) / 49
# nous utilisons cv2.filter2D pour convoluer le noyau avec une image
flou = cv2.filter2D (image, -1, noyau_7x7) cv2.imshow ('flou_ 7x7', flou) cv2.waitKey (0) cv2.destroyAllWindows ()
Il existe également d' autres types de méthodes de flou:
cv2.blur - Fait la moyenne de la valeur sur une fenêtre spécifiée.
cv2.GaussianBlur - Similaire mais utilise une fenêtre gaussienne (plus d'emphase sur les points autour du centre).
cv2.medianBlur - Utilise la médiane de tous les éléments de la fenêtre.
cv2.bilateralFilter - Estompe tout en gardant les bords nets, il préserve les bords et les détails des lignes.
Nous verrons un par un ci-dessous, afficher d'abord l'image d'origine en utilisant le code ci-dessous:
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', image) cv2.waitKey (0)
cv2.blur:
Dans cette méthode, le moyennage se fait en convolvant l'image avec un filtre de boîte normalisé, cela prend la place sous la boîte et remplace l'élément central. Ici, la taille de la boîte doit être impaire et positive .
# cv2.blur blur = cv2.blur (image, (3,3)) cv2.imshow ('Moyenne', flou) cv2.waitKey (0)
cv2.GaussianBlur:
# cv2.GaussianBlur #instead de filtre de la boîte, ESSAYONS noyau gaussien gaussien = cv2.GaussianBlur (image, (7,7), 0) cv2.imshow ('flou gaussien', gaussienne) cv2.waitKey (0)
cv2.medianBlur:
Il prend la médiane de tous les pixels sous la zone du noyau et l'élément central est remplacé par cette valeur médiane.
# cv2.medianBlur # prend la médiane de tous les pixels sous la zone du noyau et l'élément central # est remplacé par cette valeur médiane. médiane = cv2.medianBlur (image, 5) cv2.imshow ('médiane flou', médiane) cv2.waitKey (0)
cv2.bilateralFilter:
Le bilatéral est très efficace pour éliminer le bruit tout en gardant les bords nets
# cv2.bilateralFilter #Bilateral est très efficace pour éliminer le bruit tout en gardant les bords nets bilatéraux = cv2.bilateralFilter (image, 9,75,75) cv2.imshow ('flou bilatéral', bilatéral) cv2.waitKey (0) cv2. destroyAllWindows ()
Image De-noising-non Local signifie Denoising
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', image) cv2.waitKey (0)
#parameter après None est le (5-10 est un bon choix) « h » de la force du filtre #next est h pour des composantes de couleur, définie comme même valeur en tant que nouveau h
dst = cv2.fastNlMeansDenoisingColored (image, Aucun, 6,6,7,21) cv2.imshow ('Rapide signifie denois', dst) cv2.waitKey (0) cv2.destroyAllWindows ()
Il existe 4 variantes de débruitage des moyens non locaux
cv2.fastNlMeansDenoising () - pour une image à échelle de gris unique
cv2.fastNlMeansDenoisingColored () - Image monochrome
cv2.fastNlmeansDenoisingMulti () - pour une séquence d'images en niveaux de gris
cv2.fastNlmeansDenoisingcoloredMulti () - pour la séquence d'images colorée
3. Netteté - Inverser le flou de l'image
La netteté est l'opposé du flou, elle renforce ou accentue les bords de l'image.
Kernel =,,
Notre matrice de noyau totalise jusqu'à un, il n'est donc pas nécessaire de normaliser (c'est-à-dire de multiplier par un facteur la même luminosité que l'original), si le noyau n'est pas normalisé à 1, l'image serait plus claire ou plus sombre.
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', image) cv2.waitKey (0)
kernel_sharpening = np.array (,
])
#application du noyau de netteté à l'image d'entrée
sharpened = cv2.filter2D (image, -1, kernel_sharpening) cv2.imshow ('image nette ', accentuée) cv2.waitKey (0) cv2.destroyAllWindows ()
4. Threshoding (binarisation)
Le seuillage est un acte de conversion d'une image en forme binaire. Dans opencv, il existe une fonction distincte pour le seuillage défini comme
Cv2.threshold (image, valeur seuil, valeur max, type de seuil)
Il existe les types de seuils suivants:
- cv2.THRESH_BINARY - le plus courant
- cv2. THRESH_BINARY_INV - le plus courant
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2. THRESH_TOZERO_INV
REMARQUE: l'image doit être convertie en niveaux de gris avant le seuillage
import cv2 import numpy as np #load image as grayscale image = cv2.imread ('gradient.jpg', 0) cv2.imshow ('original', image) cv2.waitKey (0)
#valeur inférieure à 127 passe à 0 (noir) et au-dessus de 127 passe à 255 (blanc)
_, thresh1 = cv2.threshold (image, 127,255, cv2.THRESH_BINARY) cv2.imshow ('1 seuil', thresh1) cv2.waitKey (0)
#valeur inférieure à 127 passe à 255 et les valeurs supérieures à 127 vont à 0 (inverse de ci-dessus)
_, seuil2 = cv2.threshold (image, 127,255, cv2.THRESH_BINARY_INV) cv2.imshow ('2 seuil', seuil2) cv2.waitKey (0)
#value au-dessus de 127 est tronquée (maintenue) à 127, l'argument 255 est inutilisé.
_, thresh3 = cv2.threshold (image, 127,255, cv2.THRESH_TRUNC) cv2.imshow ('3 thresh trunc', thresh3) cv2.waitKey (0)
#values inférieures à 127 passe à 0, supérieures à 127 sont inchangées
_, seuil4 = cv2.threshold (image, 127,255, cv2.THRESH_TOZERO) cv2.imshow ('4 seuil', seuil4) cv2.waitKey (0)
#Revesrse de ci-dessus, en dessous de 127 est inchangé, au-dessus de 127 passe à zéro
_, seuil5 = cv2.threshold (image, 127,255, cv2.THRESH_TOZERO_INV) cv2.imshow ('5 seuil', seuil5) cv2.waitKey (0) cv2.destroyAllWindows ()
5. Dilatation, érosion, ouverture / fermeture
Ce sont les opérations dans le domaine de la morphologie mathématique
Dilatation - ajoute des pixels aux limites de l'objet dans une image.
Erosion - Supprime les pixels aux limites de l'objet dans une image.
Ouverture - Erosion suivie d'une dilatation.
Fermeture - Dilatation suivie d'érosion.
L'ouverture est très utile pour réduire le bruit des images car elle amincit d'abord l'image par érosion (supprime le bruit) puis la dilate.
Confusion avec dilatation et érosion
Il y a parfois confusion entre la dilatation et l'érosion généralement dans les images avec un fond blanc, car opencv considère le fond blanc comme une image à dilater ou à éroder au lieu de l'image originale, donc dans ce cas, l'érosion fonctionne comme une dilatation et vice-versa, comme le montre l'exemple d'image indiqué ci-dessous.
N'oubliez pas que la dilatation ajoute des pixels aux limites des objets dans une image tandis que l' érosion supprime les pixels aux limites des objets dans une image
import cv2 import numpy as np image = cv2.imread ('imagecv.png', 0) cv2.imshow ('original', image) cv2.waitKey (0)
#Erosion
# définissons la taille de notre noyau
noyau = np.ones ((5,5), np.uint8)
# maintenant nous érodons l'image, ici il n'y a pas d'itération où vous voulez éroder l'image
érosion = cv2.erode (image, noyau, itérations = 1) cv2.imshow ('Erosion', érosion) cv2.waitKey (0)
#dilatation
dilation = cv2.dilate (image, noyau, itérations = 1) cv2.imshow ('dilatation', dilatation) cv2.waitKey (0)
#opening, bon pour éliminer le bruit
ouverture = cv2.morphologyEx (image, cv2.MORPH_OPEN, noyau) cv2.imshow ('ouverture', ouverture) cv2.waitKey (0)
#closing, bon pour éliminer le bruit
fermeture = cv2.morphologyEx (image, cv2.MORPH_CLOSE, noyau) cv2.imshow ('fermeture', fermeture) cv2.waitKey (0) cv2.destroyAllWindows ()
6. Détection des bords et dégradés d'image
La détection des contours est un domaine très important de la vision par ordinateur, en particulier lorsqu'il s'agit de contours.
Les bords peuvent être définis comme des limites de l'image, en fait ce sont des bords qui définissent l'objet dans les images, ils conservent beaucoup d'informations sur l'image.
Formellement, les bords peuvent être définis comme des changements soudains (discontinuités) dans une image et ils peuvent encoder autant d'informations que les pixels.
L'image ci-dessus montre comment la vision par ordinateur identifie et reconnaît l'image.
Algorithmes de détection des bords : - Il existe trois principaux types d'algorithmes de détection des bords
- Sobel - pour mettre l'accent sur les images verticales ou horizontales.
- Laplacien - optimal en raison du faible taux d'erreur, des bords bien définis et de la détection précise.
- Algorithme de détection de Canny Edge (développé par john.F.Canny en 1986)
1. Applique un flou gaussien
2. Recherche le gradient d'intensité de l'image
3. applique une suppression non maximale (c'est-à-dire supprime les pixels qui ne sont pas des bords).
4. L'hystérésis applique un seuil (c'est-à-dire que si le pixel est compris entre les seuils supérieur et inférieur, il est considéré comme un bord)
import cv2 import numpy as np image = cv2.imread ('input.jpg', 0) height, width = image.shape
#sobel
#extraction de bords sobel
sobel_x = cv2.Sobel (image, cv2.CV_64F, 0,1, ksize = 5) sobel_y = cv2.Sobel (image, cv2.CV_64F, 1,0, ksize = 5) cv2.imshow ('original', image) cv2.waitKey (0) cv2.imshow ('sobelx', sobel_x) cv2.waitKey (0)
#Sobely
cv2.imshow ('sobrement', sobel_y) cv2.waitKey (0)
sobel_OR = cv2.bitwise_or (sobel_x, sobel_y) cv2.imshow ('sobelOR', sobel_OR) cv2.waitKey (0)
#laplaian
laplacien = cv2.Laplacian (image, cv2.CV_64F) cv2.imshow ('laplacien', laplacien) cv2.waitKey (0)
L'algorithme de détection des contours #canny utilise des valeurs de gradient comme
seuils.
# tout gradient supérieur au seuil 2 est considéré comme une arête.
# tout gradient supérieur au seuil 1 est considéré comme n'étant pas une arête.
#values entre le seuil 1 et le seuil 2 sont soit comme front, soit comme non-front
# sur la façon dont leurs intensités sont connectées, dans ce cas toute valeur inférieure à 60 est considérée comme
#non bords alors que toute valeur supérieure à 120 est considérée comme des bords.
canny = cv2.Canny (image, 60,120) cv2.imshow ('canny', canny ) cv2.waitKey (0) cv2.destroyAllWindows ()
14. Perspective et transformation affine
Prenons du recul et examinons les transformations affines et non affines, l'image originale ci-dessous est clairement une image non affine car les bords vont se rencontrer à un moment donné, cependant, nous pouvons la redresser en déformant et en prenant la perspective transformer.
Pour cette transformation de perspective, nous avons besoin des quatre coordonnées de l'image d'origine, puis des quatre points de l'image de sortie, ils sont notés points_A et points_B. Tout d'abord, à l'aide de ces points, nous calculons une matrice de transformation, M à l'aide de la fonction getPerspectiveTransform.
Et puis cette matrice est donnée à la fonction warpPerspective pour générer la sortie finale.
Maintenant, essayons d' abord la transformation Perspective.
import cv2 import numpy comme np import matplotlib.pyplot comme plt image = cv2.imread ('paper.jpg') cv2.imshow ('original', image) cv2.waitKey (0)
#coordonnée des 4 coins de l'image originale
points_A = np.float32 (,,,])
# coordonnées des 4 coins de la sortie souhaitée
# nous utilisons un rapport de papier A4 1: 1,41
points_B = np.float32 (,,,])
# utiliser les deux ensembles de deux points pour calculer la matrice de transformation présumée , 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 transformation affine est plus facile que la transformation non affine car nous n'avons besoin que de trois points pour obtenir la transformation. L'ensemble du processus se déroule de la même manière, mais au lieu de la transformation en perspective, nous avons maintenant une transformation affine et nous définissons également des colonnes et des lignes dans warpAffine à partir de la fonction de forme au lieu de l'entrer manuellement.
import cv2 import numpy comme np import matplotlib.pyplot as plt image = cv2.imread ('box.jpg') lignes, cols = image.shape cv2.imshow ('original', image) cv2.waitKey (0)
#coordonnée des 3 coins de l'image originale
points_A = np.float32 (,,])
# coordonnées des 3 coins de la sortie souhaitée
# nous utilisons un rapport de papier A4 1: 1,41
points_B = np.float32 (,,])
# utiliser les deux ensembles de deux points pour calculer 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. Application Live Sketch
Tout d'abord, félicitez-vous d'avoir rattrapé ce mini projet après avoir lu toutes les fonctions de manipulation d'images ci-dessus. Donc, dans ce mini projet de Python OpenCV, nous allons apprendre quelques nouveaux concepts de boucles et de fonctions. Si vous êtes familier avec la programmation, vous devez avoir une idée plus large de la fonction et des boucles. Cependant, en python, le concept de base des boucles et des fonctions reste le même mais la méthode pour les définir change un peu.
Ainsi, au début de ce programme, nous pouvons voir un certain groupe d'instructions en-tête sous la rubrique « def sketch (image): » c'est une définition formelle d'une fonction, un groupe d'instructions travaillant ensemble pour une certaine sortie.
Donc cette esquisse est une fonction, en python la fonction est définie par «def» et se termine par une marque «:». De plus, les instructions qui doivent être à l'intérieur de la fonction ou vous pouvez dire lesquelles sont nécessaires pour que la fonction fonctionne correctement, sont automatiquement alignées sur le côté par la fonction. Donc, pour sortir des fonctions, les déclarations devaient être totalement alignées à gauche. Pour les autres références, vous pouvez vous référer à google sur la façon dont les fonctions sont définies en python.
Donc, dans cette fonction d'esquisse, nous avons introduit plusieurs couches de traitement d'image qui se combinent pour donner une sortie. Tout d'abord, l'image est convertie en niveaux de gris afin que l'opencv puisse la traiter facilement, puis un flou gaussien est appliqué à l'image en niveaux de gris afin de réduire le bruit. Ensuite, les arêtes sont extraites à l'aide de l'algorithme de détection de bord de canny puis un inverse binaire est appliqué sur l'image définie par le bord, ici l'inverse binaire pourrait également être fait par bitwise_NOT mais nous avions délibérément choisi ce seuil inverse binaire car il donne la liberté pour définir ses paramètres jusqu'à ce que nous obtenions une image claire.
A noter également que la fonction prend les arguments image et renvoie les deux arguments ret et mask. Alors que le ret est le booléen indiquant que la fonction est exécutée avec succès ou non et le masque est la sortie finale de la fonction, c'est-à-dire l'image traitée.
Ensuite, le deuxième concept est de faire fonctionner la webcam dans opencv qui est fait par la fonction cv2.VideoCapture (0) , qui stocke l'image dans un objet cap que cap peut être lu avec la fonction cap.read () , également ici pour noter ce cap. read () est à l'intérieur de la boucle while infinie car il devait continuellement capturer les images, pour lui donner le sens d'une vidéo en direct, où la fréquence d'images de la vidéo serait la fréquence d'images de votre webcam qui se situe principalement entre 24 et 60 fps.
cap.read () renvoie ret et frame, où ret est le booléen indiquant que la fonction a été exécutée avec succès ou non et le cadre contient l'image prise par la webcam.
Vous trouverez ci-dessous le code Python OpenCV complet pour exécuter le Live Sketch
import cv2 import numpy as np #sketch fonction de génération def sketch (image): #convert image en niveaux de gris img_gray = cv2.cvtColor (image, cv2.COLOR_BGR2GRAY) #nettoyage de l'image en utilisant le flou gaussien img_gray_blur = cv2.GaussianBlur (img_gray, (img_gray) 5,5), 0) #extract bords canny_edges = cv2.Canny (img_gray_blur, 10,70) #do an invert binarize the image ret, mask = cv2.threshold (canny_edges, 70,255, cv2.THRESH_BINARY_INV) return mask #initialize webcam, cap est l'objet fourni par la capture vidéo # il contient un booléen indiquant si l'opération a réussi (ret) #it contient également les images collectées à partir de la webcam (cadre) cap = cv2.VideoCapture (0) avec True: ret, frame = cap.read () cv2.imshow ('livesketcher', sketch (frame)) si cv2.waitKey (1) == 13: # 13 est la caméra enterkey break #release et fermez la fenêtre, n'oubliez pas de libérer la webcam à l'aide de cap.release () cap.release () cv2.destroyAllWindows ()
C'est donc la fin de la partie 2 des manipulations d'images dans Python-OpenCV. Pour bien comprendre la vision par ordinateur et OpenCV, parcourez les articles précédents (Premiers pas avec Python OpenCV et les manipulations d'images dans Python OpenCV (partie 1) et vous pourrez faire quelque chose de cool avec Computer Vision.