Aller au contenu principal

Couleur, histogramme et seuillage

Cours​

Traitements classiques couleur​

{(A,B,C)=M.(R,G,B)}→(A′,B′,C′)→{(R′,G′,B′)=M−1.(A′,B′,C′)}\{(A,B,C)= M.(R,G,B)\} \rightarrow (A', B', C') \rightarrow \{(R',G',B') = M^{-1}.(A',B',C')\}

où M=(abcdefghi)M = \begin{pmatrix} a & b & c \\ d & e & f \\ g & h & i \end{pmatrix}

Quelques espaces couleur et applications​

  • RGB : acquisition/restitution écran
  • CMY : impression
  • XYZ : modélisation des couleurs
  • YUV/YCbCr : transmission et codage
  • HSV/HSL : espace intuitif, vision humaine
  • Lab/Luv : espace uniforme, distance entre les couleurs

Contraste et histogramme​

  1. Contraste : caractérisation des différences (variations) de niveau de gris
    • maximale : C=maxI−minImaxI+minIC = \dfrac{max_I - min_I}{max_I + min_I}
    • écart type : C=1MN∑i,jMN(I(i,j)−B)2C = \sqrt{\dfrac{1}{MN} \sum \limits_{i,j}^{MN} (I(i,j) - B)^2} avec B=1MN∑i,jMNI(i,j)B= \dfrac{1}{MN} \sum \limits_{i,j}^{MN} I(i,j)
  2. Histogramme : description de la répartition des niveaux de gris, distribution statistique, bornes de la répartition
    • H(k)=#{(i,j)∈M×N:I(i,j)=k}H(k) = \#\{(i,j) \in M \times N : I(i,j) = k\}
    • Il ne code pas l'information spatiale, 2 images sémantiquement différentes peuvent avoir le même histogramme
    • Il n'est pas possible de reconstruire une image à partir de son histogramme
  3. Contraste ↔\leftrightarrow histogramme : des valeurs concentrées près de 0 ou de 255 correspondent à une image sombre ou claire ; des valeurs tassées ou étalées correspondent à un contraste faible ou élevé.
  4. Éclaircir une image sombre : correction logarithmique I′=log⁡(1+I)I' = \log(1+I) (suivie d'une renormalisation)
  5. Assombrir une image claire : correction exponentielle I′=exp⁡(I)I' = \exp(I) (suivie d'une renormalisation)
  6. Translation d'histogramme : conserver le contraste mais modifier la luminosité
  7. Normalisation : étirement d'histogramme
    • Modifier l'intervalle de variation [min,max]→[min′,max′][min, max] \rightarrow [min', max']
    • Général I′(i,j)=max′−min′max−minI(i,j)+min′.max−max′.minmax−minI'(i,j) = \dfrac{max' - min'}{max - min} I(i,j) + \dfrac{min'.max - max'.min}{max-min}
    • Particulier [min,max]→[0,255][min, max] \rightarrow [0,255], I′(i,j)=255max−min(I(i,j)−min)I'(i,j) = \dfrac{255}{max - min}(I(i,j) - min)

Équilibrage d'histogramme​

Définitions : pour une intensité kk d'une image II de taille M×NM \times N à KK intensités :

  • Histogramme normalisé : Hn(k)=H(k)MNH_n(k) = \dfrac{H(k)}{MN} c'est une loi de probabilité : la probabilité qu'un pixel ait le niveau de gris kk vaut Hn(k)H_n(k), avec Hn(k)≥0H_n(k) \geq 0 et ∑k=0K−1Hn(k)=1\sum \limits_{k=0}^{K-1} H_n(k)=1
  • Histogramme cumulé : Hc(k)=∑l=0kH(l)H_c(k) = \sum \limits_{l=0}^k H(l)
  • Histogramme cumulé normalisé : Hcn(k)=∑l=0kHn(l)H_{cn}(k) = \sum \limits_{l=0}^k H_n(l) c'est-à-dire la fonction de répartition de la loi de probabilité
  • k=I(i,j)k = I(i,j), l'intensité initiale, k′=I′(i,j)k' = I'(i,j) la nouvelle
  • ImaxI_{max} une intensité maximale (par exemple 255). La transformation d'égalisation est alors : k′=ImaxHcn(k)=Imax∑l=0kHn(l)=Imax∑l=0kH(l)MNk' = I_{max} H_{cn}(k) = I_{max} \sum \limits_{l=0}^k H_n(l) = I_{max} \sum \limits_{l=0}^k \dfrac{H(l)}{MN}

Seuillage (Thresholding)​

  • Ramener l'image à quelques niveaux de gris dans une bande
  • Mettre en avant des régions ou des détails, sans améliorer l'image

Quelques variantes sur le seuillage global​

I[imin,imax](p)={i1  si  imin≤I(p)≤imaxi2  sinon  ou  {i1,  si  imin≤I(p)≤imaxI(p),  sinon I_{[i_{min}, i_{max}]}(p) = \begin{cases} i_1 \; \text{si} \; i_{min} \leq I(p) \leq i_{max} \\ i_2 \; \text{sinon} \end{cases} \; \text{ou} \; \begin{cases} i_1, \; \text{si} \; i_{min} \leq I(p) \leq i_{max} \\ I(p), \; \text{sinon} \end{cases}

Cas particulier : binarisation​

I[imin,imax](p)={1  si  imin≤I(p)≤imax0  sinonI_{[i_{min}, i_{max}]}(p) = \begin{cases} 1 \; \text{si} \; i_{min} \leq I(p) \leq i_{max} \\ 0 \; \text{sinon} \end{cases}

Seuillage adaptatif local​

Le paramètre de seuillage dépend d'un voisinage VV autour du pixel pp (transformation locale) : I′(p)={i1,  si  I(p)≤F(V(p))i2,  sinon I'(p) = \begin{cases} i_1, \; \text{si} \; I(p) \leq F(V(p)) \\ i_2, \; \text{sinon} \end{cases}

  • Le seuillage est principalement utilisé en niveaux de gris
  • Difficulté de trouver les valeurs de seuillage, très dépendant de l'application, de nombreuses méthodes existent

Otsu​

Minimiser la variance intra-classe vw(t)v_w(t) : pour II de taille M×NM \times N à KK intensités, un seuil tt sépare deux classes C1C_1 et C2C_2, et vw(t)=p1(t)v1(t)+p2(t)v2(t)v_w(t) = p_1(t) v_1(t) + p_2(t) v_2(t), où vi(t)v_i(t) est la variance de la classe CiC_i : p1(t)=1MN∑i=0tH(i)=∑i=0tHn(i)  et  p2(t)=1MN∑i=t+1K−1H(i)=∑i=t+1K−1Hn(i)p_1(t) = \dfrac{1}{MN} \sum \limits_{i = 0}^t H(i) = \sum \limits_{i=0}^t H_n(i) \; \text{et} \; p_2(t) = \dfrac{1}{MN} \sum \limits_{i=t+1}^{K-1} H(i) = \sum \limits_{i=t+1}^{K-1} H_n(i) avec p1,p2p_1,p_2 les probabilités d'appartenance aux classes C1C_1 et C2C_2. Le seuil optimal est T=argmin⁡{vw(t),t∈[0,K−1]}T = \operatorname{argmin}\{v_w(t), t \in [0, K-1]\}.

Maximisation de la variance inter-classe vb(t)v_b(t) : minimiser vw(t)v_w(t) revient à maximiser vb(t)=p1(t)p2(t)(μ1(t)−μ2(t))2v_b(t) = p_1(t) p_2(t)(\mu_1(t) - \mu_2(t))^2 μ1(t)=1∑i=0tH(i)∑i=0ti.H(i)  et  μ2(t)=1∑i=t+1K−1H(i)∑i=t+1K−1i.H(i)\mu_1(t) = \dfrac{1}{\sum \limits_{i=0}^t H(i)} \sum \limits_{i=0}^t i.H(i) \; \text{et} \; \mu_2(t) = \dfrac{1}{\sum \limits_{i=t+1}^{K-1} H(i)} \sum \limits_{i=t+1}^{K-1} i.H(i) où μ1\mu_1, μ2\mu_2 sont les moyennes des classes C1C_1 et C2C_2. Le seuil optimal est T=argmax⁡{vb(t),t∈[0,K−1]}T = \operatorname{argmax}\{v_b(t), t \in [0, K-1]\}.

Maximiser vbv_b est plus efficace algorithmiquement que minimiser vwv_w : la variance totale vw+vbv_w + v_b est constante, et les quantités p1p_1 et μ1\mu_1 se mettent à jour incrémentalement lorsque tt augmente, puisque p1+p2=1p_1 + p_2 = 1 et p1μ1+p2μ2=μIp_1 \mu_1 + p_2 \mu_2 = \mu_I, avec μI\mu_I la moyenne globale de l'image II.

Mise en pratique​

color-convert <ims>​

Écrire le programme color-convert.cpp qui :

  • affiche les canaux R,G et B dans 3 images monochromes
  • convertit l'image couleur en niveaux de gris et l'affiche
  • convertit l'image RGB en YCbCr et la reconvertit en RGB, afficher l'image résultat
  • affiche les canaux Y, Cb et Cr
  • y a-t-il une différence entre l'image en niveaux de gris et le canal Y ?
  • y a-t-il une différence entre l'image initiale et l'image reconvertie en RGB ?
  • Note 1 : pour convertir les images dans d'autres espaces couleurs utiliser la fonction cvtColor
  • Note 2 : pour pouvoir voir les différences, il est conseillé de faire attention aux types de données

hsv-modification <h> <s> <v> <ims> <imd>​

Écrire le programme hsv-modification.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>
  • convertit l'image dans l'espace HSV
  • affiche les canaux hh, ss et vv (si applicable, attention aux problèmes de normalisation)
  • modifie les canaux HSV en fonction des valeurs hh, ss et vv données en paramètres en les ajoutant aux valeurs initiales
  • sauvegarde la nouvelle image avec le nom donné en paramètre <imd>
  • visualiser l'image produite via pvisu

eq-histogram <ims>​

Écrire le programme eq-histogram.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>
  • réalise la méthode d'équilibrage d'histogramme de l'image source
  • la méthode considère que l'image est en niveaux de gris
  • la construction des histogrammes se fait "à la main"
  • sauve l'image dans un fichier eq.png
  • utiliser la fonction OpenCV equalizeHist ; sauver le résultat dans une image eq-ocv.png
  • calculer une image de différence : diff.png
  • visualiser les images produites via pvisu

adaptative-th <ims> <radius> <const>​

Écrire le programme adaptative-th.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>
  • réalise un seuillage adaptatif avec la moyenne, où le voisinage est déterminé par le paramètre <radius> (voisinage de taille (2⋅radius+1)×(2⋅radius+1)(2 \cdot radius + 1) \times (2 \cdot radius + 1)) et paramétré par la constante <const>
  • sauve l'image dans un fichier th.png
  • utiliser la fonction adaptiveThreshold et réaliser le même seuillage. Sauver dans une image th-ocv-mean.png
  • calculer une image de différence diff.png
  • tester l'option ADAPTIVE_THRESH_GAUSSIAN_C et sauver l'image dans th-ocv-gauss.png
  • visualiser l'image produite en la visualisant via pvisu

otsu <ims>​

Écrire le programme otsu.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>. L'image est traitée comme une image en niveaux de gris
  • réalise une binarisation en utilisant le calcul d'un seuil automatique par la méthode d'Otsu
  • affiche l'image binaire et la sauve dans un fichier nommé otsu-th.png
  • utilise la fonction threshold avec le paramètre THRESH_BINARY + THRESH_OTSU afin de réaliser la même opération. Afficher l'image binaire et la sauver dans un fichier otsu-th-ocv.png
  • affiche une image de différence entre les deux méthodes
  • affiche sur la sortie standard les valeurs de seuil trouvées par votre implémentation et par OpenCV. Comparer les valeurs
  • visualiser les images résultats via pvisu
  • Remarque importante : en analysant l'algorithme, les équations de la méthode d'Otsu et les propriétés suivantes : p1μ1+p2μ2=μGp_1 \mu_1 + p_2 \mu_2 = \mu_G et p1+p2=1p_1 + p_2 = 1, une implémentation plus efficace peut être réalisée par rapport à une version naïve de l'algorithme. Il est fortement conseillé de produire une telle implémentation.