Python et OpenCV
But: Découvrir le traitement de l’image grâce à Python et OpenCV
MATERIEL et prérequis:
– Un Ordinateur (ou une Raspberry pi)
– Une caméra
– Une connexion internet
– Un environnement Python ( Python 2.7 ici)
– Quelques connaissances en Python (optionnel)
– Quelques connaissances mathématiques
– Les librairies adaptées (numpy, scipy, matplotlib, cv2, mahotas, pip, imutils)
Introduction - installation et premiers
codes
Bonjour à tous, et bienvenue dans nos tutoriels dédiés à Python et OpenCV. Commençons tout de suite avec une introduction sur ce qu’est le traitement de l’image (computer vision en anglais).
“La vision par ordinateur (aussi appelée vision artificielle ou vision numérique) est une branche de l’intelligence artificielle dont le principal but est de permettre à une machine d’analyser, traiter et comprendre une ou plusieurs images prises par un système d’acquisition (par exemple: caméras, etc.)”
Le but du traitement de l’image est donc de comprendre ce que contient une image. Pour nous, humains, cela est assez simple et nous le faisons depuis que nous sommes enfants, mais pour les ordinateurs cela peut être une tache assez complexe.
Mais si c’est si complexe, pourquoi s’embeter à le faire ?
La raison est que les images et les vidéos sont partout aujourd’hui. La technologie des capteurs a tellement évoluée qu’aujourd’hui ils sont très abordables et qu’ils fournissent une qualité d’image totalement exploitable (ex: Caméra Raspberry Pi v2). Grâce à cela, les données vidéos sont très accessibles et permettent de concevoir des systèmes très pointus.
Prenons tout de suite un exemple. Vous vous êtes déja demandé comment Facebook positionnait ses cadres autour des visages pour que vous puissiez identifier vos amis ? Grâce au traitement de l’image ! Ils ont concu un algorithme capable de reconnaitre les visages dans une photo, et normalement à la fin de ces tutoriels vous devriez être capable de le faire également.
Vous l’aurez compris, le traitement de l’image est un outil extrêmement puissant et qui sera beaucoup utilisé à l’avenir dans tous les domaines.
Bien ! Maintenant que vous êtes motivés passons à l’installation des paquets nécessaire au traitement de l’image. Je ne m’interesserai ici qu’à l’installation pour des machines UNIX (n’ayant jamais programmé sous Windows). La bonne nouvelle c’est que python est déja pré-installé sur la plupart des systèmes donc nous allons juste nous intéresser aux librairies.
Vous êtes prêts ?
Ouvrez d’abord votre terminal.
Instructions installation
Pour Mac:
– Ouvrez votre terminal et tapez sans les guillemets ” sudo easy_install pip” puis appuyez sur entrée
– Faites la même chose pour :
– “/usr/bin/ruby -e “$(curl -fsSL “
– “brew install python2.7”
– “pip install numpy scipy mahotas matplotlib imutils “
– “brew tap homebrew/science”
– “brew install opencv “
Pour Linux:
– Ouvrez votre terminal et tapez sans les guillemets ” sudo pip install numpy scipy mahotas matplotlib imutils” puis appuyez sur entrée
– Faites la même chose pour:
– “sudo apt-get install libopencv-dev
Voila c’est prêt !
Maintenant que tout est installé nous allons pouvoir commencer ! Pour cela rien de plus facile, sous Unix prenez juste votre éditeur de texte préféré ( TextWrangler ou SublimeText ou même XCODE sous mac ) et créez un nouveau fichier texte sur votre bureau en le nommant “cours.py” par exemple.
Pour le début de la leçon je vais vous demander d’enregistrer une photo sur votre bureau (prenez n’importe quoi cette photo sera notre sujet de travail). Normalement votre bureau devrait ressembler a ça:

Ouvrez maintenant votre fichier cours.py avec votre éditeur de texte (ou avec XCODE), vous devriez obtenir ceci.

Bien maintenant que les bases sont posées il est temps de programmer un peu ! (Néanmoins si vous avez rencontrer des difficultés pour arriver jusqu’ici, je serai ravi de répondre à vos questions en commentaire)
Comme dans beaucoup d’autres langages de programmation, les commentaires sont présents dans Python et sont représentés par un # ou par “”” dans le cas de commentaires multi-lignes. Je me servirai des commentaires pour tenter d’expliquer au mieux le code que nous sommes en train d’écrire.
Premier code
import cv2 #import
d’OpenCV 2.4
“””
Ici l’objet image va prendre la valeur de l’image imagechat.jpg
Dans votre cas il faut que vous remplaciez imagechat.jpg par le nom de votre
image
“””
image = cv2.imread(‘imagechat.jpg’)
cv2.imshow(“test”, image) # creation d’une fenetre appelee test contenant
image
cv2.waitKey(1000)# detruire la fenetre au bout d’une seconde
Maintenant que notre code est écrit, il est temps de
l’éxecuter !
Pour cela rien de plus simple.
Ouvrez votre terminal et tapez:
– “cd
desktop”
– “python
cours.py”
Si
votre ordinateur est en français il se peut que vous ayez à taper “cd
bureau” à la place de “cd desktop”.
Et la
normalement votre
image devrait apparaitre pendant une seconde !
Enchainons
tout de suite avec un deuxième code nous permettant de connaitre les dimensions
de notre image.
Deuxième code
import cv2
image = cv2.imread(‘imagechat.jpg’)
hauteur = image.shape[0] # la variable hauteur prend la valeur de la hauteur de notre image
largeur = image.shape[1] # idem pour la largeur
print (hauteur, largeur) # afficher les deux
cv2.imshow(“test”, image)
cv2.waitKey(1000)
Tapez ce code dans votre fichier cours.py à la place du premier code, sauvegardez et éxecutez (si vous avez fermé le terminal rouvrez le et faites comme pour le premier code sinon faites juste fleche du haut dans le terminal puis entrée).
Si tout se passe comme prévu, vous devriez voir s’afficher votre image pendant une seconde, et il devrait y avoir les dimensions de l’image écrites dans votre terminal (comme ci dessous).

Bilan des deux premiers codes
Grâce à ces deux premiers codes vous avez découvert 4 fonctions:
– cv2.imread(‘image.jpg’)
Qui permet de lire une image
– cv2.imshow(“nomfenetre”, image)
Qui permet de créer une fenêtre contenant notre image
– cv2.waitKey(duree)
Attente avant la destruction de la fenêtre, notez que si vous mettez 0 la fenêtre s’affichera indéfiniment tant que vous n’aurez pas cliquer dessus et appuyer sur une touche
– image.shape[dim]
Qui permet de récuperer les dimensions de notre image ( dim peut etre égal à 0, 1, ou 2)
Maintenant que vous savez faire quelques actions de bases nous allons nous interesser aux images en elle même.
C'est quoi une image ?
Chaque image est constituée d’une multitude de pixels. Si l’on considère notre image comme une grille, chaque pixel est une case de cette grille. Prenons par exemple l’image que j’ai choisi pour le code précedent. Cette dernière avait une hauteur de 1200 et une largeur de 1600. Ces valeurs sont des nombres de pixels. Cela veut dire que mon image fait 1600 pixels de large, et 1200 pixels de haut. Donc mon image contient 1600×1200 = 1 920 000 pixels.
Vous l’aurez compris je pense nos images sont constituées de pixels accolés les uns aux autres.
Mais au fait c’est quoi un pixel ?
Et bien en fait ca dépend (de la technologie et du type d’image a afficher) ! Prenons par exemple un écran à LEDs, dans ces écrans chaque pixel est composé de 3 LEDs (une rouge, une bleu, et une verte) permettant ainsi de récréer d’autres couleurs par synthèse additive. L’intensité lumineuse de chaque LED peut prendre 256 valeurs (ou 0 est éteint et ou 255 est la valeur maximum).
Dans le cas d’une image en noir et blanc, les 3 LEDS ont la même intensité. Lorsque leur intensité vaut 0, le pixel est noir, et lorsque leur intensité est de 255, le pixel est blanc. Toutes les valeurs intermédiaires sont des nuances de gris. Du coup dans le cas d’image noir et blanc il n’y a qu’une valeur a stocker par pixel (l’intensité des 3 LEDs).
Dans le cas d’une image en couleur, les 3 LEDs n’ont pas la même intensité. Les différentes couleurs sont crées en combinant les 3 couleurs primaires à des intensités différentes. Il y a donc trois valeurs à stocker par pixel (l’intensité de chaque LED).
Cette différence va changer la façon dont sont représentés les images. Habituellement on associe les images à des matrices. Dans le cas d’images noir et blanc, la matrice image sera une matrice de dimension 2 (X lignes et Y colonnes). Pour les images en couleur, on les représentera sous la forme de matrices de dimension 3 (X lignes, Y colonnes et 3 de profondeur).
Dans une case de matrice on ne peut stocker qu’une valeur, donc dans le cas d’image en noir et blanc, on peut se satisfaire d’une matrice de dimension 2, car chaque case contient l’intensité de 3 LEDs. Cependant pour les images couleurs on est obligé d’utiliser des matrices de dimension 3, car il faut stocker l’intensité de chaque LED (d’ou la profondeur de 3).
D’ailleurs nous ne nous en sommes pas servi dans les codes d’introduction, mais la fonction .shape[2] retourne le nombre de channels ( 3 pour une image couleur, et 1 pour une image en noir et blanc). La fonction .shape[] permet donc de connaitre la dimension complète de notre matrice image. Pour notre première image cela aurait été (1200x1600x3).
Mais au fait c’est quelle couleur en premier ?
Effectivement on doit stocker la valeur de l’intensité de chaque LED, mais on ne peut pas les stocker n’importe comment !
En fait cela dépend de l’espace choisi. Dans l’espace RGB on stocke les couleurs ainsi (rouge, vert, bleu), alors que dans l’espace BGR on les notes différement (bleu, vert rouge). Voyons voir si vous avez compris.
Imaginons que je veuille afficher mon pixel [0,0] en rouge et que je suis en espace RGB, quelle couleur je dois lui envoyer ?
Pour ceux n’ayant pas trouvé la réponse est (255,0,0).
Et maintenant si je suis en espace BGR ?
Si je vous bassine avec ces différents espaces c’est qu’il faut faire attention à l’espace dans lequel est votre image. Par exemple , Opencv stocke ses images en BGR alors que Numpy lui utilise l’espace RGB ( mais nous verrons ca plus tard).
Maintenant que vous avez compris exactement comment sont formées les images, il est temps de pouvoir les modifier !
Premier Code
import cv2
image = cv2.imread(‘imagechat.jpg’)
“””
Ici on va lire la valeur du pixel (0,0), et b va stocker la valeur de l’intensite
de la LED bleu, g va stocker la valeur de la LED verte et idem pour r
“””
(b, g, r) = image[0,0]
print (b,g,r) # on affiche les 3 intensites representant notre couleur
image[0,0] = (255,255,255) # le pixel (0,0) devient blanc
(b, g, r) = image[0,0]
print (b,g,r) # on reaffiche la couleur du pixel (0,0) qui doit maintenant valoir (255,255,255)
cv2.imshow(“test”, image)
cv2.waitKey(0) # affichage de l’image tant que je n’appuie pas sur une touche
Comme d’habitude, enregistrez votre fichier et lancez le avec le terminal.
Comme vous avez pu le voir dans ce code l’utilsation de crochet nous permet de naviguer dans notre image. Ainsi image[0,0] nous renvoie la valeur du pixel situé ligne 0 et colonne 0.
Ces crochets peuvent aussi nous permettre de saisir une partie de l’image. Ainsi si j’écris image[0:100 , 0:100] cela va me retourner un carré de 100 pixels de coté allant du pixel (0,0) au pixel (100,100). Le pixel (0,0) se situe en haut à gauche de notre image et le pixel (100,100) se situe 100 pixels plus à droite et plus à bas.
Deuxième Code
import cv2
image = cv2.imread(‘imagechat.jpg’)
“””
Ici je cree une image (coin) qui va etre egale au carré supérieur gauche de notre image
“””
coin = image[0:200, 0:200] #creation de coin // qui est un carre de 200 pixels de cote
cv2.imshow(“test”, coin) #affichage de coin
cv2.waitKey(0) # affichage de l’image tant que je n’appuie pas sur une touche
Comme d’habitude, enregistrez votre fichier et lancez le avec le terminal.
L’utilisation des crochets est donc très utile, pour retailler nos images. Cependant on peut aussi s’en servir pour modifier de grandes zones de nos images. Ainsi si je dis image[100:200,100:200] = (255,0,0) cela va convertir tous les pixels qui sont dans ce carré en bleu.
Démonstration !
Troisième Code
import cv2
image = cv2.imread(‘imagechat.jpg’)
“””
Ici je modifie tous les pixels contenus dans le carre, pour qu’ils soient bleus
Le carre va du pixel (100,100) au pixel (200,200)
“””
image[100:200, 100:200] = (255,0,0)
cv2.imshow(“test”, image) #affichage de mon image modifiee
cv2.waitKey(0) # affichage de l’image tant que je n’appuie pas sur une touche

Comme d’habitude, enregistrez votre fichier et lancez le avec le terminal.
Maintenant que vous savez faire de vraies oeuvres d’art cela serait pas mal de pouvoir enregistrer nos images. Nous allons pour ca utiliser la fonction cv2.imwrite().
Quatrième Code
import cv2
image = cv2.imread(‘imagechat.jpg’)
cropped = image[100:250, 200:350] #cropped prend la valeur d’une partie seulement de l’image de base
image[100:200, 100:200] = (255,0,0) # on fait des dessins
image[300:350, 100:400] = (0,255,0)
image[400:500, 100:200] = (0,0,255)
cv2.imshow(“test”, image) #affichage de mon image modifiee
cv2.imwrite(‘copy.jpg’, image) # on sauvegarde notre image sous le nom “copy.jpg”
cv2.imwrite(‘cropped.jpg’, cropped) # on sauvegarde notre crop sous le nom “cropped.jpg”
cv2.waitKey(0) # affichage de l’image tant que je n’appuie pas sur une touche
Voila ! Nos images sont enregistrées !

Bilan
Grâce à tout ca vous savez maintenant:
– de quoi est constituée une image et la différence entre noir et blanc et couleurs
– lire la valeur l’un pixel et la changer
grâce aux crochets (ex: image[100,100])
– copier une partie d’une image, et changer toute une zone de pixels
toujours grâce aux crochets (ex: image[0:100, 0:100] = (255,0,0))
– sauvegarder une image
grâce à la fonction cv2.imwrite(‘nom’, imageasauvegarder)
Maintenant que vous avez acquis les bases sur ce qu’est une image et comment interagir de façon simple avec elle, il est temps de passer à des fonctions un peu plus complexes.
Dessiner
Dans le paragraphe précédent, on a réussi à tracer des rectangles de couleur sur notre image. Mais comment dessiner des formes plus complexes, un cercle ou même une ligne ? Rassurez vous, nous n’allons pas faire ça à la main ! Nous allons utiliser des fonctions d’OpenCv déjà toutes faites: cv2.line(), cv2.rectangle(), cv2.circle().
cv2.line() demande 5 arguments (5 paramètres qu’on doit lui donner quand on l’appelle).
cv2.line(canvas, (xstart, ystart), (xend, yend), (blue, green, red), (thickness))
– canvas est l’image sur laquelle OpenCv doit tracer une ligne
– (xstart, ystart) sont les coordonnées du point de départ de notre droite (en pixel)
– (xstart, ystart) sont les coordonnées du point d’arrivée de notre droite (en pixel)
– (blue, green, red) est la couleur de notre droite
– thickness est l’épaisseur de notre ligne (en pixel)
ex: je souhaite tracer une droite sur mon image du pixel (0,0) au pixel (100,100) en bleu d’une épaisseur de 1 pixel
cv2.line(image, (0,0), (100,100), (255,0,0), 1)
Voila ! facile non ? 🙂
Bien interessons nous à cv2.rectangle() maintenant. Tout comme cv2.line(), cv2.rectangle demande 5 arguments.
cv2.rectangle(canvas, (xstart, ystart), (xend, yend), (blue, green, red), (thickness))
– canvas est l’image sur laquelle OpenCv doit tracer un rectangle
– (xstart, ystart) sont les coordonnées du point de départ de notre rectangle (en pixel)
– (xstart, ystart) sont les coordonnées du point d’arrivée de notre rectangle (en pixel)
– (blue, green, red) est la couleur de notre rectangle
– thickness est l’épaisseur de notre rectangle(en pixel) (à noter que si vous mettez une épaisser de -1 le rectangle sera rempli)
Normalement cette fonction ne devrait pas vous poser trop de problèmes vu qu’elle est quasiment identique à cv2.line().
Passons maintenant à cv2.circle(). Elle aussi demande 5 arguments.
cv2.circle(canvas, (centerx, centery), radius, (blue, green, red), (thickness))
– canvas est l’image sur laquelle OpenCv doit tracer un rectangle
– (centerx, centery) sont les coordonnées du centre de notre cercle (en pixel)
– radius est le rayon de notre cercle (en pixel)
– (blue, green, red) est la couleur de notre cercle
– thickness est l’épaisseur de notre cercle(en pixel) (à noter que si vous mettez une épaisser de -1 le cercle sera rempli)
Et voila pour la troisième fonction ! Rien de bien compliqué ! Il va bientôt être temps de passer à la pratique mais avant ca nous allons voir comment créer une image entièrement vide.
Par entièrement vide, je veux dire que l’image va être complètement noire. Pour cela nous allons utiliser une fonction de la librairie numpy. numpy.zeros() prend deux arguments: les dimensions de l’image à créer et son type (pour nous ce sera toujours uint8).
ex: numpy.zeros((300,300,3), dtype=”uint8″)
J’ai créé ici une image carrée de 300 pixels de coté entièrement noire pour le moment mais pouvant acceuillir de la couleur.
Bien maintenant il est l’heure de dessiner !
Premier code
import cv2
import numpy #import de numpy
image = numpy.zeros((300,300,3), dtype=’uint8′) #creation de mon image vide
cv2.rectangle(image, (100,100), (200,200), (200,150,100), 2) #on dessine un rectangle
cv2.circle(image, (150,150), 25, (255,0,0), -1) #on dessine un disque
cv2.line(image, (50,50), (250,250), (0,0,255), 2) #on dessine une droite
cv2.imshow(“test”, image) #affichage de mon image avec les dessins
cv2.imwrite(‘copy.jpg’, image)
cv2.waitKey(0)

Voila maintenant vous savez dessiner avec OpenCV ! Interessons nous maintenant aux transformations d’image.
Transformations géométriques
Maintenant que vous savez dessiner des formes géométriques ! Il est temps d’apprendre à transformer nos images.
Effectivement, il peut y avoir des moments, ou nous aurons besoin de changer la taille de nos images, ou effectuer une rotation ou même une translation de nos images.
Pour cela nous allons utiliser la librairie imutils. Cette librairie contient tout un tas de fonctions utilitaires dont nous allons parler maintenant.
La première fonction dont nous allons parler est: imutils.translate(). Elle demande trois arguments: l’image à décaler, le nombre de pixels sur l’axe x, et le nombre de pixel sur l’axe y.
ex: imutils.translate(image,100,100)
En faisant cela, je vais décaler mon image de 100 pixels vers la droite et de 100 pixel vers le bas. Vous pouvez bien sur mettre des valeurs négatives pour bouger votre image vers la gauche ou vers le haut. Passons tout de suite à la deuxième fonction !
La deuxième fonction dont nous allons parler est la fonction imutils.rotate(). Elle demande elle deux arguments: l’image à tourner, et l’angle de rotation.
ex: imutils.rotate(image, 90)
En faisant ça, je vais obtenir une image tournée de 90 degrés.
Attaquons maintenant la troisième fonction: imutils.resize(). Elle demande deux arguments: l’image à retailler, et la dimension de la largeur ou de la hauteur voulue. L’avantage de cette fonction est qu’elle conserve le ratio de base de l’image.
ex: imutils.resize(image, width = 300)
En faisant ca, je vais obtenir une image retaillée avec une largeur de 300 pixels.
Il est temps pour nous maintenant de coder pour apprendre à utiliser ces fonctions.
Premier Code
import cv2
import imutils
image = cv2.imread(‘imagechat.jpg’)
rotated = imutils.rotate(image, 90) #rotated est l’image tournee
resized = imutils.resize(image, width = 300) #resized est l’image retaillee
translated = imutils.translate(image,100,0) #translated est l’image decalee
cv2.imwrite(‘rotated.jpg’, rotated) # enregistrement de l’image tournee
cv2.imwrite(‘resized.jpg’, resized) # enregistrement de l’image retaillee
cv2.imwrite(‘translated.jpg’, translated) # enregistrement de l’image decalee
Comme d’habitude, enregistrez et lancez votre script avec le terminal. Si tout se passe bien, rien ne devrait s’afficher mais vous devriez avoir 3 photos enregistrées sur votre bureau.

Transformations - Luminosité et Bitwise
Continuons ici, avec d’autres types de transformation. Nous allons nous intéresser à l’éclaircissement et à l’obscurcissement de nos images. En plus de cela nous allons nous familiariser avec les opérations BITWISE et leur utilisation dans les masques.
Encore une fois nous allons utiliser une fonction de la librairie numpy: numpy.ones(). Cette fonction va créer une matrice remplie de un. Elle demande deux arguments: les dimensions de la matrice a créer, et le type (“uint8” comme tout à l’heure).
Mais à quoi ca va nous servir ? Et bien ensuite on peut multiplier cette matrice par n’importe quel nombre afin d’avoir une matrice remplie de 20 par exemple.
Oui et après ?
Après nous allons utiliser la fonction cv2.add(). Cette fonction va additionner deux matrices ensemble. Elle demande deux arguments: les deux images que nous voulons additionner. En additionnant notre matrice avec une autre matrice remplie de nombres on va augmenter l’intensité générale de tous nos pixels et ainsi on va éclaircir nos images.
A l’inverse, nous pourrons utiliser la fonction cv2.subtract(), pour retirer de la luminosité à notre image selon le même principe que précedemment.
NB: La librairie OpenCV veille a ce que les valeurs d’intensité des LEDs de chaque pixel ne dépassent jamais 255 ou ne passent jamais en dessous de 0.
Pour que vous compreniez bien voyons notre premier code.
Premier Code
import cv2
import numpy as np
image = cv2.imread(‘imagechat.jpg’)
transfo = np.ones(image.shape, dtype=”uint8″)*50 # creation de notre matrice de transformation
eclair = cv2.add(image, transfo) #creation de notre image plus lumineuse
sombre = cv2.subtract(image,transfo) #creation de notre image moins lumineuse
cv2.imwrite(‘eclair.jpg’, eclair) # on sauvegarde notre image plus claire sous le nom “eclair.jpg”
cv2.imwrite(‘sombre.jpg’, sombre) # on sauvegarde notre image plus sombre sous le nom “sombre.jpg”
Et voila le résultat que vous devriez obtenir !

Maintenant que vous savez éclaircir ou assombrir votre image, il est temps pour moi de vous parler des opérations BITWISE. Dans le cadre de ces opérations nous considérerons que nous comparons deux pixels ensemble (sauf pour le NOT). Pour l’instant nous nous interesserons uniquement aux opérations BITWISE sur les images en noir et blanc. Un pixel est donc considéré comme allumé si sa valeur est supérieure à 0.
Il existe quatre opérations BITWISE:
– AND : le bitwise AND est vrai si et seulement si les deux pixels comparés sont allumés.
– OR : le bitwise OR est vrai si au moins l’un des deux pixels comparés est vrai.
– XOR : le bitwise XOR est vrai si au moins l’un des deux pixels comparés est vrai, mais pas les deux.
– NOT : le bitwise NOT allume les pixels éteints et éteint les pixels allumés
L’avantage de ces opérations c’est qu’elles sont déja implémentées dans OpenCV. On les appelle ainsi:
– cv2.bitwise_and()
– cv2.bitwise_or()
– cv2.bitwise_xor()
– cv2.bitwise_not()
Elles prennent toutes deux arguments: les deux images à comparer (sauf NOT qui ne prend qu’un argument: l’image à inverser).
Voyons tout de suite comment elles fonctionnent en pratique (je trouve que le résultat est plus facile à comprendre graphiquement).
Deuxième Code
import cv2
import numpy
“””
Dans cet exemple on va creer un carre blanc sur fond noir, et un cercle blanc sur fond noir
Ensuite nous allons utiliser les operations BITWISE pour voir l’effet de ces dernieres
“””
carre = numpy.zeros((300,300), dtype=”uint8″) #creation du fond noir
cercle = numpy.zeros((300,300), dtype=”uint8″) #creation du fond noir
cv2.rectangle(carre,(100,100),(200,200),255,-1) #creation du carre
cv2.circle(cercle,(150,150),55,255,-1) #creation du cercle
btand = cv2.bitwise_and(carre,cercle) #operations bitwises
btor = cv2.bitwise_or(carre,cercle)
btxor = cv2.bitwise_xor(carre,cercle)
btnot = cv2.bitwise_not(cercle)
cv2.imshow(“carre”, carre) # affichage
cv2.imshow(“cercle”, cercle)
cv2.imshow(“bitwiseand”, btand)
cv2.imshow(“bitwiseor”, btor)
cv2.imshow(“bitwisexor”, btxor)
cv2.imshow(“bitwisenot”, btnot)
cv2.waitKey(0)
Et voila le résultat que vous devriez obtenir !
Pour l’opération bitwise AND, les coins du carré ont été rognés car il fallait que les deux pixels comparés soient allumés, et ceux du cercle étaient éteints à ce niveau là.
Pour l’opération bitwise OR, on voit que le carré et le cercle ont été superposés, car il fallait qu’au moins un des des pixels comparés soit allumés.
Pour l’opération bitwise XOR, on voit que la seule chose blanche est la zone ou le carré et le cercle ne se croisent pas, ce qui est logique car il faut qu’un des deux pixels soit allumés mais pas les deux en même temps.
Pour l’opération bitwise NOT, c’est une simple inversion des pixels allumés et des pixels éteints.

Maintenant que vous avez bien compris la logique des opérations BITWISE nous allons pouvoir passer aux masques, qui est un outil extremement puissant reposant sur ces opérations.
L’avantage du masque est qu’il va nous permettre de nous concentrer uniquement sur une partie de l’image qui nous intéresse.
Imaginons, je cherche à mettre au point un algorithme permettant de detecter les plaques d’immatriculation. D’abord je dois détecter les voitures dans mon image, et ensuite je pourrai détecter les plaques.
Mais qu’on soit bien d’accord; il est inutile de rechercher une plaque d’immatriculation dans toute l’image, nous devrons la chercher uniquement sur la voiture. Et c’est là que les masques interviennent.
Les masques sont déja implémentés sous OpenCV dans les fonctions BITWISE que nous avons vu précedemment. Les arguments qu’il faut fournir sont différents par contre.
Interessons nous à l’opération AND (qui est l’opération la plus utile). Habituellement, on lui fournit les deux images à comparer et basta. Mais pour le masquage cela va être différent. Les deux premiers arguments vont être l’image qu’on veut masquer. Et le troisième argument va être notre masque.
NB: La partie de l’image qui va être conservée sera uniquement la partie blanche du masque
Voyons ca avec notre image test.
Troisième Code
import cv2
import numpy
“””
ici on cree un masque de forme carree qu’on va appliquer a notre image
“””
image = cv2.imread(‘imagechat.jpg’)
carre = numpy.zeros(image.shape[:2], dtype=”uint8″)
cv2.rectangle(carre, (100,100),(200,200),255,-1) #creation du mask
masked = cv2.bitwise_and(image, image, mask = carre) #operation bitwise
cv2.imshow(“original”, image) # affichage
cv2.imshow(“mask”, carre)
cv2.imshow(“final”, masked)
cv2.waitKey(0)
Et voila le résultat que vous devriez obtenir !

Transformations - Couleurs et fou
Attaquons maintenant notre avant-dernière partie sur les transformations. Nous allons commencer avec les changements d’espace colorimétrique. Pour l’instant nous n’avons utiliser que l’espace colorimétrique RGB (ou BGR). Dans cet espace chaque pixel est représenté par 3 valeurs : les valeurs d’intensité des LEDS rouge, verte et bleu. Cependant il existe d’autres espaces colorimétriques.
Nous allons notamment parler de l’espace HSV (ou TSV en français). Dans cet espace chaque pixel est lui aussi représenter par 3 valeurs. La première valeur est la teinte, la deuxième est la saturation et la troisième est la valeur.
Pour expliquer comment constituer une couleur dans cette espace voici une image montrant l’espace HSV

Dans cet espace, la teinte représente la couleur (H sur le schéma). La saturation répresente l’intensité de la couleur. Et la valeur représente la brillance de la couleur.
La teinte est codée suivant l’angle qui lui correspond sur le cercle des couleurs. On a donc:
– 0° ou 360° : rouge ; – 60° : jaune ; -120° : vert ; -180° : cyan ; -240° : bleu ; -300° : magenta.
Cependant comme nos valeurs ne peuvent pas dépasser 255, la teinte dans OpenCv est comprise entre 0 et 180 ( par exemple la teinte jaune vaut 30 dans OpenCV).
La saturation et la valeur elle seront comprises entre 0 et 255. Pour la valeur: 0 veut dire que le pixel est éteint et 255 qu’il est allumé au maximum . La saturation elle correspond à l’intensité de la couleur (0 veut dire gris et 255 veut dire “coloré au maximum”).
Heureusement pour nous nous n’aurons pas à effectuer les conversions nous même, OpenCV s’en chargera pour nous, grâce à une fonction très utile de la librairie cv2: cv2.cvtColor().
Elle demande deux arguments: l’image à transformer et la transformation à effectuer.
Pour l’instant nous n’utiliserons que deux transformations: COLOR_BGR2HSV et COLOR_BGR2GRAY.
La première passe une image d’un espace RGB à un espace HSB, et la deuxième passe notre image d’un espace RGB à un espace noir et blanc.
NB: Quand nous allons afficher notre image après qu’elle ait été convertie dans l’espace HSB, elle apparaitra bizarrement car l’afficheur ne sait pas que c’est une image HSV. Pour lui la première valeur de notre pixel sera l’intensité de la LED bleue alors qu’en fait cette valeur sera la teinte de notre pixel.
Voyons tout de suite le résultat avec notre image test.
Premier Code
import cv2
“””
ici on importe nos deux images, on applique nos transformations et on les affiche
“””
image = cv2.imread(‘imagechat.jpg’)
gris = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
cv2.imshow(“original”, image)
cv2.imshow(“gris”, gris)
cv2.imshow(“hsv”, hsv)
cv2.waitKey(0)
Et voila le résultat que vous devriez obtenir !

Bien sur le résultat visuel de la transformation HSV, n’est pas exploitable. Cependant cette transformation nous sera très utile par la suite. On utilisera principalement ces deux transformations pour préparer notre traitement.
Tant que nous parlons de préparations de traitement, parlons du flou. Je suis quasiment sur que vous savez tous ce qu’est le flou. C’est ce qui se passe quand votre mise au point ne fait pas le focus, ou que vous bougez lorsque vous prenez une photo. Le résultat est que l’image possède moins de détails. Au niveau des pixels cela s’explique par le fait que chaque pixel est un peu mélangé avec ceux qui l’entoure.
Lorsque vous prenez des photos de vacances le flou est à éviter, mais pour faire du traitement de l’image il est plutôt recherché. En effet les fonctions de seuillage (threshold en anglais) et de détection de contours marchent mieux si l’image qu’elles traitent est légerement floutée. Pour cela nous allons découvrir quelques fonctions de la librairie OpenCV qui vont nous permettre de flouter nos images.
La première fonction que nous allons voir est : cv2.blur().
Elle demande deux arguments: l’image à flouter, et la taille de notre matrice de convolution.
La matrice de convolution, est une fenêtre qui va balayer notre image. Imaginons que ma matrice soit de dimension (3,3). Elle va balayer l’image de gauche à droite et de haut en bas. A chacun de ses passages, le pixel central de notre matrice (ici le pixel (1,1)) va être changer pour obtenir une intensité égale à l’intensité moyenne des autres pixels de la matrice de convolution. Ainsi on aura un lissage de la valeur moyenne de nos pixels et donc notre image sera flou.
NB: Les dimensions de notre matrice de convolution doit forcément être impaire pour garantir l’existence d’un pixel central.
NB2: Logiquement, plus vous agrandissez la taille de la matrice de convolution plus votre image sera floutée.
Voyons tout de suite l’effet de cette fonction.
Premier Code
import cv2
import numpy as np
“””
Ici j’importe numpy ‘”as np” cela veut dire que dans mon code au lieu d’ecrire “numpy.'” j’ecrirai “np.”
J’importe mon image, et ensuite je cree 3 images pour montrer la difference de floutage.
La fonction hstack de numpy permet de coller trois images par leur hauteur si elles possedent
la meme hauteur, ainsi je n’ai pas besoin de creer plusieurs fenetres
Ensuite j’affiche ‘affic’ qui est l’image avec mes trois images floutees, collees.
“””
image = cv2.imread(‘imagechat.jpg’)
test3 = cv2.blur(image, (3,3))
test5 = cv2.blur(image, (5,5))
test7 = cv2.blur(image, (7,7))
affic = np.hstack([test3,test5,test7])
cv2.imshow(“resultat”, affic)
cv2.waitKey(0)
Et voila le résultat que vous devriez obtenir !

Bien, maitenant nous allons parler d’une deuxième méthode pour créer du flou: le flou gaussien. Ce dernier fonctionne comme le flou que nous avons vu précédemment. La seule différence est que les pixels proches du centre de la matrice de convolution sont plus pris en compte pour constituer la référence que les pixels extérieurs. Grâce à cela le flou gaussien à un rendu plus naturel.
Pour l’appeler nous allons utiliser la fonction cv2.GaussianBlur().
Cette fonction prend en argument: l’image à flouter, la taille de la matrice de convolution, et la déviation standard selon l’axe x.
NB: On laissera toujours le dernier argument à 0 pour que opencv le configure lui même.
Maintenant voyons le résultat comparé à celui que l’on a obtenu précedemment.
Deuxième Code
import cv2
import numpy as np
“””
Ici je traite mon image avec nos deux methodes de floutage pour comparer le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
flou = cv2.blur(image, (5,5))
flougaussien = cv2.GaussianBlur(image, (5,5), 0)
affic = np.hstack([flou,flougaussien])
cv2.imshow(“resultat”, affic)
cv2.waitKey(0)

Comme annoncé, l’image flouté avec la méthode Gauss à un résultat plus naturel que la méthode précédente.
NB: Nous ne discuterons pas ici de la méthode du flou médian, mais elle sera abordé oralement lors de notre formation à l’école en bonus. Néanmoins vous trouverez toute la documentation de cette fonction sur le site d’OpenCV (cv2.medianBlur()).
Abordons maintenant notre dernière méthode de floutage: le flou bilatéral.
Cette méthode est très utile car elle permet de flouter nos images tout en conservant les contours (ce que ne font pas les autres méthodes). On peut l’utiliser grâce à la fonction cv2.bilateralFilter().
Nous n’allons pas rentrer dans les détails mathématiques, mais nous allons nous intéresser au fonctionnement de cette méthode.
Cette méthode fonctionne un peu comme les autres, avec une fenêtre de convolution, cependant le pixel central ne va pas prendre la valeur moyenne des pixels de la fenetre comme dans les deux premières méthodes. Au lieu de ca, les pixels qui vont être utilisés pour faire la moyenne vont être les pixels possédant une intensité proche de celle du pixel central. Ainsi les contours seront préservés.
Voila pour la théorie, interessons nous maintenant à la fonction elle même.
Cette fonction demande quatre arguments. Le premier argument est l’image que nous voulons traiter. Le deuxième est le diamètre de notre fenêtre de convolution, le troisième et quatrième sont la couleur et l’espace. Globalement plus vous les augmenterez, plus le floutage sera important.
NB: Pour ceux souhaitant comprendre ce que font ces arguments. Nous avons dit que les pixels qui vont être utilisés pour faire la moyenne, sont les pixels possédant une couleur proche de celle du pixel central. Imaginons que notre pixel central est bleu (200,0,0).
Les pixels qui vont être condisérés comme similaire sont ceux ayant une couleur de (200+/- couleur, 0+/- couleur, 0+/- couleur). En augmentant la valeur de la couleur on augmente donc le nombre de pixels qui seront utilisés pour calculer la moyenne. Pour la valeur de l’espace, nous allons faire court. Cette valeur sert à accorder plus de poids pour la valeur moyenne aux pixels qui sont loins du pixel central.
Voyons un exemple pour que vous compreniez bien, et pour que nous puissions comparer le résultat obtenu avec les autres méthodes.
Troisième code
import cv2
import numpy as np
“””
Ici je traite notre image avec nos trois methodes de floutage pour comparer le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
flou = cv2.blur(image, (5,5))
flougaussien = cv2.GaussianBlur(image, (5,5), 0)
floubilateral = cv2.bilateralFilter(image, 9, 30, 30)
affic = np.hstack([flou,flougaussien, floubilateral])
cv2.imshow(“resultat”, affic)
cv2.waitKey(0)

Comme vous pouvez le constater, le floutage bilatéral lisse notre image en préservant nos contours. Cette méthode est donc très utile en préparation des fonctions détectant les contours. Son seul désavantage est qu’elle assez lourde au niveau du processeur.
Transformations - Thresholds et contours
Nous allons maintenant aborder la dernière partie de notre leçon sur Python et OpenCV. Celle ci sera dédiée aux Thresholds et aux contours.
Commençons tout de suite avec le thresholding (ou seuillage en français). Le seuillage est une binarisation de nos images. La plupart du temps nous allons binariser des images noirs et blancs.
Mais c’est quoi la binarisation ?
“En traitement d’image, la binarisation est une opération qui produit deux classes de pixels, en général, ils sont représentés par des pixels noirs et des pixels blancs.”
En gros, tous les pixels en dessous du seuil vont être converti en pixel noir, et ceux au dessus seront converti en pixel blanc.
Ainsi on pourra se concentrer sur la partie de l’image qui nous interesse.
Bien voyons maintenant les fonctions de thresholding d’OpenCV.
La première est cv2.threshold().
Elle demande quatre arguments: le premier est l’image à seuiller (forcément une image noir et blanc), le deuxième est le seuil, le troisième est la valeur maximum, et le dernier est la méthode de binarisation.
Principe de fonctionnement: Si la méthode de binarisation est cv2.THRESH_BINARY, alors chaque pixel ayant une intensité supérieure à celle du seuil verra sa valeur transformer en la valeur maximum (255 souvent). Les autres seront ramenés à une intensité de 0.
Si la méthode de binarisation est cv2.THRESH_BINARY_INV, alors ce sera l’inverse. Les pixels ayant une intensité supérieure au seuil seront ramenés à une intensité de 0, et les pixels ayant une intensité inférieure au seuil prendront la valeur de l’intensité maximale.
NB: la fonction cv2.threshold() retourne deux valeurs: la première est la valeur du seuil, et la deuxième est l’image seuillée.
Voyons tout de suite un code d’exemple.
Premier Code
import cv2
import numpy as np
“””
Ici j’importe mon image, je la passe en noir et blanc et je la floute.
Ensuite j’applique le seuillage
Je vais ensuite ecrire sur mon image avec la fonction putText
voici comment elle se presente
cv2.putText(imagesurlaquelleecrire, texte, positiondutexte, police, taille, couleur, epaisseur)
J’affiche ensuite le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.GaussianBlur(gray, (5,5), 0)
(T, seuillagenorm) = cv2.threshold(flougaussien, 155, 255, cv2.THRESH_BINARY)
(T1, seuillageinv) = cv2.threshold(flougaussien, 155, 255, cv2.THRESH_BINARY_INV)
text = “seuil: {} / normal”.format(T)
cv2.putText(seuillagenorm, text, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
text1 = “seuil: {} / inverse”.format(T1)
cv2.putText(seuillageinv, text1, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,0), 2)
result = np.hstack([seuillagenorm, seuillageinv])
cv2.imshow(“resultat”, result)
cv2.waitKey(0)

Voila le résultat que vous devriez obtenir. J’ai refait une capture d’écran pour une valeur de seuil de 100, pour que voyez la différence.

L’un des gros problèmes de cette fonction est que le seuil doit être défini par l’utilisateur. Donc si les conditions de luminosité change trop notre seuillage peut ne plus être efficace.
Pour régler ce problème, nous allons utiliser une nouvelle fonction: cv2.adaptiveThreshold().
Cette fonction comme son nom l’indique adapte son seuil elle même en fonction de la zone à traiter (au lieu de seuiller l’image dans sa globalité elle va la seuiller zone par zone). Voyons comment nous allons l’utilser.
Cette fonction demande six arguments: l’image à seuiller, la valeur max, la méthode adaptative, la méthode classique, la taille de la zone, et un paramètre C.
Au niveau du fonctionnement, cette fonction va parcourir l’image à seuiller. A chaque nouvel zone elle va attribuer une valeur de seuil grâce à la méthode adaptative, et ensuite elle binarisera la zone avec la méthode classique et le seuil qu’elle aura déterminer précédemment.
NB: La méthode adaptative peut être: cv2.ADAPTIVE_THRESH_MEAN_C ou cv2.ADAPTIVE_THRESH_GAUSSIAN_C, les deux méthodes fournissent des résultats légérement différents.
Voyons tout de suite le code.
Deuxième Code
import cv2
import numpy as np
“””
Ici j’importe mon image, je la passe en noir et blanc et je la floute.
Ensuite j’applique les seuillages adaptatifs
J’affiche ensuite le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.GaussianBlur(gray, (5,5), 0)
seuillagenorm = cv2.adaptiveThreshold(flougaussien, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 4)
seuillagegaussien = cv2.adaptiveThreshold(flougaussien, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 4)
cv2.putText(seuillagenorm, “Normal”, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
cv2.putText(seuillagegaussien, “Gaussien”, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
result = np.hstack([seuillagenorm, seuillagegaussien])
cv2.imshow(“resultat”, result)
cv2.waitKey(0)

Comme vous pouvez le remarquer le seuillage gaussien à un résultat plus fin que le seuillage classique.
NB: Il existe aussi un seuil adaptatif que nous pouvons appliquer directement dans la fonction cv2.threshold(). Ce seuil est le seuil d’OTSU. Voici comment on l’utilise.
cv2.threshold(imageaseuiller, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
Voici le code et le résulat obtenu.
Troisième Code
import cv2
import numpy as np
“””
Ici j’importe mon image, je la passe en noir et blanc et je la floute.
Ensuite j’applique le seuil classique et le seuil d’Otsu
J’affiche ensuite le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.GaussianBlur(gray, (5,5), 0)
(T, seuillageotsu) = cv2.threshold(flougaussien, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
(T, seuillageclassique) = cv2.threshold(flougaussien, 155, 255, cv2.THRESH_BINARY)
cv2.putText(seuillageotsu, “Otsu”, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
cv2.putText(seuillageclassique, “Classique : 155”, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
result = np.hstack([seuillageotsu, seuillageclassique])
cv2.imshow(“resultat”, result)
cv2.waitKey(0)

Voila ! Maintenant vous savez tout sur les thresholds. Vous l’aurez compris le plus important est de bien choisir son seuil.
Maintenant nous allons aborder les contours. Pour les détecter nous allons utiliser une fonction d’OpenCV: cv2.Canny().
NB: Cette fonction comme les fonctions de seuillage demande que l’image soit en noir et blanc et si possible qu’elle soit légèrement floutée (pour exclure les contours parasites).
Cette fonction demande trois arguments: l’image à traiter, le seuil 1, et le seuil 2.
ex: cv2.Canny(blurred, 30, 150)
En gros le seuil 1 est le seuil minimal, c’est à dire qu’en dessous de ce seuil le contour ne sera pas pris en compte. Le seuil 2 est le seuil maximal, c’est à dire qu’au dessus de ce seuil le contour est pris en compte. Entre les deux c’est la fonction qui va déterminer si ce sont des contours ou non en fonction de leurs liens avec les autres contours.
Voyons tout de suite le code.
Quatrième Code
import cv2
import numpy as np
“””
Ici j’importe mon image, je la passe en noir et blanc et je la floute.
Ensuite j’applique le filtre de Canny
J’affiche ensuite le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.GaussianBlur(gray, (3,3), 0)
edge = cv2.Canny(flougaussien, 30, 150)
edge1 = cv2.Canny(flougaussien, 70, 200)
result = np.hstack([edge, edge1])
cv2.imshow(“resultat”, result)
cv2.waitKey(0)

Les filtres de Canny comme les thresholds ont donc des paramètres qui changent le rendu de l’image. C’est donc tout naturellement qu’est apparu le filtre Canny adaptatif. Il provient de la librairie imutils, on l’appele ainsi: imutils.auto_canny(imageàtraiter)
Voyons un code se servant de cette fonction.
Cinquième Code
import cv2
import numpy as np
import imutils
“””
Ici j’importe mon image, je la passe en noir et blanc et je la floute.
Ensuite j’applique les filtres de canny
J’affiche ensuite le resultat
“””
image = cv2.imread(‘imagechat.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.GaussianBlur(gray, (3,3), 0)
edge = imutils.auto_canny(flougaussien)
edge1 = cv2.Canny(flougaussien, 70, 200)
result = np.hstack([edge, edge1])
cv2.imshow(“resultat”, result)
cv2.waitKey(0)

Voila ! Personnellement je trouve que cette fonction est très pratique car on n’a pas à s’embeter avec les valeurs du filtre de Canny.
Il est bientot temps pour nous de nous quitter mais avant ca il faut que nous parlions de contours. Pour ca nous allons tous travailler sur la même image: celle ci (cliquer sur celle ci pour la télécharger). Notre but va être de déterminer le nombre de pièces dans l’image.
Pour cela nous allons voir une nouvelle fonction: cv2.findContours().
Elle demande trois arguments: l’image sur laquelle chercher, et les méthodes de recherche. Elle retourne la liste des contours détéctés.
NB: La recherche est destructrice pour l’image dont la fonction se sert. Si vous souhaitez vous resservir de cette image , il faut la copier au préalable.
La deuxième fonction dont nous allons nous servir est cv2.contourArea(). Elle ne prend en argument qu’un contour et elle retourne l’aire de ce contour.
Voyons maintenant le code.
Sixième Code
import cv2
import numpy as np
import imutils
“””
Ici j’importe mon image, je la passe en noir et blanc, je la floute,
puis j’applique mon filtre de Canny automatique.
Ensuite je cherche les contours et je les stock dans “cnts” qui est une liste contenant
les contours.
Ensuite je parcours cette liste et si l’aire du contour est superieur a 40 alors
je considere que c’est une piece donc je la dessine sur mon image et j’augmente
le compteur de 1.
Une fois que tous les contours sont passes. J’ecris le nombre de pieces trouvees
J’affiche ensuite le resultat
“””
image = cv2.imread(‘piecetest.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.bilateralFilter(gray, 5, 40, 40)
edge = imutils.auto_canny(flougaussien)
(cnts, _) = cv2.findContours(edge, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
compteur = 0
for c in cnts:
if (cv2.contourArea(c) > 40):
cv2.drawContours(image, [c], -1, (0,255,0),3)
compteur += 1
text = ” {} pieces trouvees”.format(compteur)
cv2.putText(image, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,255,0), 2)
cv2.imshow(“resultat”, image)
cv2.waitKey(0)
Et voila le résultat ! Bien sur ce résultat est perfectible mais nous n’utilisons ici que des procédés simples et légers pour le CPU. Donc pour une première approximation c’est pas mal.

Voici une alternative ou j’ai utilisé les masques pour afficher les pièces détectées.
Septième Code
import cv2
import numpy as np
import imutils
“””
Ici j’importe mon image, je la passe en noir et blanc, je la floute,
puis j’applique mon filtre de Canny automatique.
Je cree mon mask de la meme dimension que mon image
Ensuite je cherche les contours et je les stock dans “cnts” qui est une liste contenant
les contours.
Ensuite je parcours cette liste et si l’aire du contour est superieur a 80 alors
je considere que c’est une piece donc je la dessine sur mon mask et j’augmente
le compteur de 1.
Une fois que tous les contours sont passes. J’ecris le nombre de pieces trouvees et
je masque mon image de base
J’affiche ensuite le resultat
“””
image = cv2.imread(‘piecetest.jpg’)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
flougaussien = cv2.GaussianBlur(gray, (3,3), 0)
#flougaussien = cv2.bilateralFilter(gray, 5, 40, 40)
edge = imutils.auto_canny(flougaussien)
mask = np.zeros(image.shape[:2], dtype=’uint8′)
(cnts, _) = cv2.findContours(edge.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
compteur = 0
for c in cnts:
if (cv2.contourArea(c) > 80):
cv2.drawContours(mask, [c], 0, (255,255,255),-1)
compteur += 1
resultat = cv2.bitwise_and(image, image, mask = mask)
text = ” {} pieces trouvees”.format(compteur)
cv2.putText(resultat, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,255,0), 2)
cv2.imshow(“resultat”, resultat)
cv2.waitKey(0)

Voila ! Notre premier tutoriel sur OpenCv et Python est maintenant terminé. Je vous invite à continuer avec nous dans le deuxième tutoriel disponible ici. Merci de votre attention et à bientot pour de nouvelles aventures.