Dans l’article d’aujourd’hui, nous allons nous attaquer à notre premier problème qui est de retrouver un dé dans une image et d’en déduire le chiffre représenté.

Pour ce faire nous nous attaquerons à la question de la reconnaissance de formes pour extraire le carré représentant un dé dans l’image ainsi que les points représentant le chiffre de la face.

Nous étudierons également les différentes fonctions permettant de rajouter des formes et du texte sur une image.

Cet article étant une initiation à la reconnaissance des dés, nous nous baserons sur des images simples ne contenant qu’un seul dé et où la luminosité est constante. Si vous débutez dans OpenCV, je vous invite à consulter cet article.

Nous allons effectuer 3 étapes principales:

  • Prétraiter notre image, c’est-à-dire effectué un certain nombre d’opérations permettant la meilleure détection des dés.
  • Effectuer la détection et l’extraction des dés.
  • Étudier le nombre de points.

C’est parti !

Étape 1: Prétraitement de l’image

import cv2
import numpy as np

img=cv2.imread('Dice_2.jpg')
HSV=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
V=HSV[:,:,2]
V=cv2.GaussianBlur(V, (5, 5), 0)
_,thresh=cv2.threshold(V,200,255,cv2.THRESH_BINARY)

Les lignes 1 à 4 permettent le chargement de la bibliothèque OpenCV , de NumPy, ainsi que le chargement de l’image.

Nous changeons de repère colorimétrique à la ligne 5 où nous transformons notre image RGB en image HSV.

Le modèle HSV est une représentation des images en 3 composantes: la teinte de la couleur(Hue), la Saturation (l’intensité de la couleur) et la Valeur (la « brillance » de la couleur).

Il est ainsi aisé repérer les objets brillant de la scène en étudiant uniquement la composante V de l’image (ligne 6).

Nous effectuons un lissage de l’image à la ligne 7 afin d’enlever les éventuels bruits de l’image.

Enfin nous effectuons, ligne 8, un seuillage de l’image afin de n’étudier que les parties brillantes de l’image.

Nous obtenons ainsi une image binaire, où le dé est parfaitement identifiable.

Étape 2: Détection des dés

Nous allons maintenant nous occuper de l’obtention des coordonnées du dé dans l’image:

_,cnts,_ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
    area = cv2.contourArea(c)
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.04 * peri, True)
    if len(approx) >= 4 and area > 100:
        (x, y, w, h) = cv2.boundingRect(approx)
        cv2.rectangle(img, (x, y), (x + w, y + h), (200, 0, 0), 2)

La fonction findContours (ligne 10)  permet d’obtenir, comme son nom l’indique, tous les contours présents dans une image binaire.

Pour chaque contour obtenu, nous calculons l’aire et la périphérie de la forme (lignes 12-13).

Nous allons ensuite faire une approximation de notre forme (ligne 14).

L’approximation de contour est un algorithme permettant de réduire le nombre de points permettant de définir une courbe. L’idée de cette méthode est d’approcher une courbe (un contour) par une série de courtes droites.

Le contour de notre dé devrait pouvoir être approché par une série de 4 droites correspondant à ces 4 côtés. Cependant à cause de la luminosité et de la forme du dé, un nombre supérieur de droites et nécessaire.

Nous définissons donc (ligne 15) comme condition que le nombre de droites doit être supérieur ou égal à 4. De plus nous mettons comme condition que l’aire de la forme soit supérieure à 100 afin d’éliminer les éventuels bruits.

Afin d’obtenir le rectangle encadrant de notre forme (ligne 16), nous utilisons la fonction boundingRect qui renvoie les coordonnées du rectangle dans lequel se situe la forme. Nous pouvons ainsi tracer le rectangle obtenu sur notre image initiale (ligne 17).

Étape 3: Reconnaissance de la valeur

Maintenant que nous connaissons la position du dé, nous pouvons étudier son nombre de points.

        crop=V[y:y+h,x:x+w]
        _, thresh2 = cv2.threshold(crop, 100, 255, cv2.THRESH_BINARY_INV)
        dilated = cv2.dilate(thresh2, kernel=np.ones((5,5 ),'int'))
        _,cnts2,_ = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        nombre=0
        for c in cnts2:
            area = cv2.contourArea(c)
            if area > 100:
                nombre+=1
        cv2.putText(img,str(nombre),((int(x+w)),int((y+h/2))),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        print("Valeur du dé : "+ str(nombre))

Nous commençons par extraire de la composante de la luminance (Value) la zone correspondant au dé (ligne 19) et nous effectuons un seuil permettant de mettre en avant les zones sombres de l’image (ligne 20).

Nous effectuons ensuite une opération morphologique ligne 21: une dilatation permettant de corriger les déformations provenant de l’éclairage:

Dé dans dilatation (à droite) – Dé avec dilatation (à gauche)

Nous effectuons de nouveau une recherche de contours ligne 22. Et nous comptabilisons les formes ayant une aire supérieure à 100 (lignes 24-28).

Enfin nous fonction putText (ligne 29) permet de rajouter sur l’image d’origine, la valeur du dé:

Nous avons dans cet article mis en place un moyen simple pour reconnaitre la valeur d’un dé à partir d’une image. Pour ce faire, nous avons eu besoin d’utiliser des seuils afin de faciliter la détection de contour.

Ce procédé est cependant extrêmement sensible aux changements d’illumination de la scène, ainsi qu’à l’orientation des dés.

Nous verrons dans un prochain article comment il est possible d’améliorer notre système de reconnaissance.


1 commentaire

Moi · 13 mars 2019 à 14 h 48 min

super explication :
suite modification de la bibliotheque : il n’y a plus que 2 valeurs en retour pour cv2.findContours il faut donc remplacer
ligne 10 : _,cnts,_ = cv2.findContours par cnts,_ = cv2.findContours
ligne 21 : _,cnts2,_ = cv2.findContourssur par cnts2,_ = cv2.findContours

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.