Méthode d'Otsu : comment elle fonctionne ?

Méthode_d'Otsu

La segmentation permet de mettre en évidence et d’isoler les différents objets présents dans une image.Il existe différentes méthodes de segmentation (le seuillage, la classification, le clustering, les level-set, graph-cut, etc .…).Dans cet article j’aborderais avec vous le seuillage et plus particulièrement le seuillage automatique avec la méthode d’Otsu.


Bien que je vais vous expliquer le fonctionnement de la méthode d’Otsu, pour l’utiliser il vous sera nécessaire d’utiliser OpenCV python. Si vous ne connaissez pas, OpenCV, je vous recommande de jeter un coup d’œil au tutoriel d’initiation à OpenCV que j’ai écrit.


C’est quoi le seuillage ?

Le seuillage est une opération qui permet de transformer une image en niveau de gris en image binaire (noir et blanc), l'image obtenue est alors appelée masque binaire. Il existe 2 méthodes pour seuiller une image, le seuillage manuel et le seuillage automatique.


En pratique, le seuil optimal est considéré comme étant celui qui sépare le mieux le fond et les objets présents sur l’image. L'image ci-dessous illustre ce principe.




 Seuillage optimal

Dans cet exemple, le seuil idéal est 175, car il permet de mettre en évidence tous les objets présents dans l’image.


Comment utiliser le seuillage en python ?


Pour utiliser le seuil manuel avec OpenCV, il suffit d’appeler la fonction thresold comme suit :


ret,th=cv.threshold(img, seuil,couleur, option)



Elle prend en paramètre, img : l’image à traiter , seuil : la valeur du seuil , couleur : la couleur que l’on souhaite attribuer à la zone objet et elle retourne ret : la valeur du seuil, et th : l’image binaire résultat du seuillage. Afin d’illustrer cela, dans le code suivant, j’ai seuillé l’image fleur.png préalablement passée en niveau de gris avec quatre seuils : 35,75,150,225.




fleur.png


Code :


Résultat :

Résultat du seuillage


Nous remarquons que le seuillage n’a pas fonctionné, quel que soit le seuil. En effet, les pixels du fond sont mélangés au pixel des fleurs. C’est pour cela qu’il est préférable de passer l'image dans l’espace HSV avant de seuiller.


La méthode d’Otsu : Décryptage


Soit 2 classes de pixels C1 et C2. La classe 1 (C1) est définie comme étant composée des pixels ayant une valeur comprise entre 0 et k avec k<255. Le reste (classe C2) des pixels compris entre k et 255 (inclus) faits partit de la seconde classe. Le but du jeu est de trouver "k" tel qu’il sépare au mieux le fond et les objets de l'image traitée.


Afin de trouver "k", la méthode d’Otsu va calculer la variance interclasses entre C1 et C2 pour tous les k possibles (de 0 à 255). La variance interclasses caractérise la dissemblance qu’il existe entre les pixels des deux classes. Plus elle est haute, moins les deux classes se ressemblent. La réciproque est également vraie.


Par conséquent, le seuil optimal est le k obtient la plus haute variance interclasse.



Maintenant que je vous ai montré comment elle fonctionne en principe, nous allons voir comment l’implémenter. Les étapes de l’algorithme d’Otsu sont les suivantes :


1- Construction de l’histogramme des niveaux de gris de l’image.


2-Normalisation de l’histogramme obtenu en 1. Normaliser l’histogramme, permet d’obtenir un histogramme dont toutes les valeurs sont comprises entre 0 et 1. Le calcul ci-dessous permet d’y parvenir :



f(x)=(x-min)/(max -min)

Formule normalisation


avec x étant la valeur en ordonnée de l’histogramme que l’on souhaite transformer, min et max étant respectivement la valeur minimale et maximale en ordonnée de l’histogramme Le pseudo-code permettant d’obtenir la normalisation est présenté ci-dessous :


N = taille_image (image) ;

hist=histogramme(image)

for col in hist :

    col=col/N 


Remarque : en normalisant l’histogramme des couleurs, l’on obtient une distribution de probabilité. Par exemple la probabilité que dans notre image il y ait un pixel dont le niveau de gris est 255 est la valeur de notre histogramme normalisé pour l’abscisse 255.

3-Calcul de la probabilité qu’un pixel de l’image appartienne à C1. Cela est fait en calculant la somme de toutes les colonnes de l’histogramme comprises entre 0 et k.

4-Calcul de la probabilité qu’un pixel de l’image appartienne à C2. En faisant simplement 1- proba(C1) calculé dans l’étape précédente.

5- Calcule de la variance interclasses entre C1 et C2 grâce à la formule :

avec Moy étant la moyenne de l’image, ProbaC1(k) étant la probabilité qu’un pixel de l’image appartienne à C1, Moy(k) la moyenne des pixels de la classe C1.

6- Les étapes 2,3,4,5 sont répétées pour toutes les valeurs de k possible.



La fonction python permettant d’utiliser cet algorithme est la fonction thresold. Je ne vais pas la présenter, car je l’ai présenté précédemment et seuls le second (il passe à 0) et le dernier paramètre changent (+ cv.THRESH_OTSU a été rajouté) .

ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)


Exemple : Application de la méthode d’Otsu sur chaque canal de l’image HSV


Image de départ

Résultat :

Seuillage d'Otsu sur le canal hue



Seuillage d'Otsu sur le canal Saturation


Seuillage d'Otsu sur le canal Luminosité

Les seuils optimaux trouvés par Otsu pour les canaux teinte, saturation et luminosité sont respectivement 75, 168 et 114.

Remarquons que, la segmentation obtenue sur le canal luminosité n’a rien donné d’intéressant.

Celle du canal hue a permis d’extraire les fleurs blanches.

Enfin celle de la saturation a extrait toutes les fleurs sauf les blanches.

Afin d’obtenir une segmentation parfaite qui sépare toutes les fleurs du fond, il nous est nécessaire de fusionner le résultat obtenu en hue et en saturation.

Cette opération se fera par l’intermédiaire d’opérateurs binaires d’image.

Code complet méthode d'Otsu C++ :

float compute_first_order_cumulative_moment(float *hist, int k)

{

    float first_order_cumulative_moment = 0;

    for (int i = 0; i < k; i++)

    {

            first_order_cumulative_moment += i*hist[i];

    }

    return first_order_cumulative_moment;

}


float compute_variance_class_separability(float uT,float wk, float uk)

{

    return pow((uT*wk-uk),2)/(wk*(1-wk));

}


void otsu(Mat img)

{

    int s;

    float hist[256];

    for (int i = 0; i < 256; i++)

    {

        hist[i] = 0;

    }

    for (int i = 0; i < img.rows; i++)

    {

            for (int j = 0; j < img.cols; j++)

            {

                    hist[img.at<uchar>(i, j)] += 1;

            }

    }

    int N = img.cols*img.rows;

    for (int i = 0; i < 256; i++)

    {

            hist[i] = hist[i] / N;

    }

    float w[256],u[256],uT;

    for (int i = 0; i < 256; i++)

    {

            w[i] = compute_zero_order_cumulative_moment(hist, i);

            u[i] = compute_first_order_cumulative_moment(hist, i);

    }

    uT = compute_first_order_cumulative_moment(hist, 256);

    float variance_class_separability_max = -1;

    float best_threesold = 0;

    for (int i = 0; i < 256; i++)

    {

            int vk = compute_variance_class_separability(uT, w[i], u[i]);

            if (vk > variance_class_separability_max)

            {

                    variance_class_separability_max = vk;

                    best_threesold = i;

            }

    }

    for (int i = 0; i < img.rows; i++)

    {

            for (int j = 0; j < img.cols; j++)

            {

                    if (img.at<uchar>(i, j) < best_threesold)

                   {

                            img.at<uchar>(i, j) = 0;

                    }

                    else

                    {

                            img.at<uchar>(i, j) = 255;

                    }

            }

    }

}

Référence :

https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=4310076

https://en.wikipedia.org/wiki/Otsu%27s_method




Tu veux devenir un vrai monstre de la vision par ordinateur et du machine learning  en 5 à 10 minutes par jour?

Tu as aimé ce tutoriel et tu as pour objectif de devenir un vrai monstre de la vision par ordinateur et du machine learning. 

Mais tu n'as pas de temps pour apprendre.

As-tu 5 à 10 minutes par jour pour lire un email ?

Si c'est le cas inscris-toi gratuitement à la newsletter par email de kongakura.fr et participe dès à présent à une formation quotidienne continue par email à la vision par ordinateur, aux machine learning et deep learning. 

En t'inscrivant, tu recevras chaque jour une leçon de 5 à 10 minutes de lecture.

En plus de cela, tu recevra des cours, des tutoriels, des astuces et des conseils, afin que tu deviennes le meilleur de ces domaines et que tu sois au courant au plus tôt des dernières nouveautés. 

Ne manque pas la leçon de demain matin !

N'hésite pas à tester la newsletter, tu n'as rien à perdre si ce n'est ton temps et tu comprends que tu peut te désinscrire à tout moment de la formation avec le lien que je laisse au bas de chaque email.

.