l'image de fond

fr       en

Traitements d'Images Binaires

Utilisation des Régions

L'étiquetage

Matlab propose déjà des fonctions nous permettant d'obtenir l'étiquetage des objets d'une image binaire. "labelmatrix"

%x = imread('forme.PNG');
x=x(:,:,1);
[M N] = size(x);
%binarisation
level = graythresh(x);
img = im2bw(x,0.1);
%labellisation
CC = bwconncomp(img);
L = labelmatrix(CC);

%affihcage
figure('color',[0.3137 0.3137 0.5098])
subplot(221)
imshow(img)
title('binary image')
subplot(222)
imshow(label2rgb(L));
title('labeling')


contourbin1

Cadre de Région (Bounding Box)

Le cadre d'une région est le plus petit cadre qui peut enfermer une région. On définie pour chaque région 2 coordonnées. Une donnant le coin en haut à gauche du cadre et l'autre le coin en bas à droite. Dans le code suivant la variable 'param' donne, pour chaque région, [le numéro de région, le nombre de point de la région, limite gauche du cadre, limite droite du cadre, limite haute du cadre et limite basse du cadre].

%nombre d'objet, number of objects
nbobj = max(max(L));

%parametres des objets, object's parameters
param=zeros(nbobj,6);
for i = 1 : nbobj
   param(i,1)=i;
end
%param = [ numero , nb pixel , boite_gauche , boite_droite , boite_haut ,
%boite_bas]

for i = 1 : M
    for j = 1 : N
        if L(i,j)~=0
            numero = L(i,j);
            param(numero,2)= param(numero,2) + 1 ;
            if param(numero,3)==0 || param(numero,3)>j
                param(numero,3)=j;
            end
            if param(numero,4)==0 || param(numero,4)<j
                param(numero,4)=j;
            end
            if param(numero,5)==0 || param(numero,5)>i
                param(numero,5)=i;
            end
            if param(numero,6)==0 || param(numero,6)<i
                param(numero,6)=i;
            end
        end
    end
end
% supression petit objet
var =1;
for i = 1 : nbobj
    if param(i,2)>10
        parametre(var,:)=param(i,:);
        var=var+1;
    end
end;
nbobj = size(parametre,1);

A la fin de ce code, On supprime les petites régions.

Voici l'affichage des régions :


contourbin2

Centre de Gravité

Pour lle calculer, on va utiliser les coordonnées en x et y de chaque point appartenant à une région et le nombre de point total de la région. on calcule la somme des coordonnées en x pour chaque point et on divise par le nombre total de point de la région. Même opération pour les y. la coordonnée trouvée est le centre de gravité de l'objet. On a les équations suivantes :

x c = 1 n b p o i n t y = 1 N x = 1 M I ( x , y ) x ,
y c = 1 n b p o i n t y = 1 N x = 1 M I ( x , y ) y ,

Où xc et yc sont les coordonnées du centre de gravité, I l'image binaire où I(x,y)=1 si le pixel fait partie de la région sinon I(x,y)=0. M est le nombre de ligne et N le nombre de colonne. nbpoint est le nombre de point de la région.

for i = 1 : nbobj
    poidsx = 0;
    poidsy = 0;
    nbpoint = 0;
    for x = parametre(i,5) : parametre(i,6)
        for y = parametre(i,3) : parametre(i,4)
            if L(x,y) == parametre(i,1)
                poidsx = poidsx + x;
                poidsy = poidsy + y;
                nbpoint = nbpoint + 1;
            end
        end
        parametre(i,7)=round(poidsx/nbpoint);%centre ligne
        parametre(i,8)=round(poidsy/nbpoint);%centre colonne
    end
end
% affichage centre de gravité
subplot(223)
imshow(img)
hold on
for i = 1 : nbobj
    plot(parametre(i,8),parametre(i,7),'r+','LineWidth',1)
end
title('center of gravity')


contourbin3

Contour des Régions

Il existe beaucoup d'algorithme pour effectuer la détection de contour pour les images binaires. Je vais en expliquer un seul.
direction :

d 6 d 7 d 8 d 5 p d 1 d 4 d 3 d 2

considérant qu'on se trouve à un pixel p de coordonnée 0,0. On peut définir autour de lui 8 directions possibles. Les contours des objets seront donc définies suivant 8 directions. Le même raisonnement peut être fait avec les 4 directions d'indices impaires.
Pour chaque objet on parcourt son cadre de M lignes et N colonnes en commençant du pixel en haut à gauche. On sait que le premier pixel qui fera partie de l'objet sera un pixel appartenant au contour extérieur de l'objet. Grâce à cette affirmation, on sait que le premier contour calculé sera le contour extérieur. Par conséquent, tous les autres contours du même objet seront des contours intérieurs. A partir de la première coordonnée, nous allons suivre le contour extérieur dans le sens horaire. Comment trouver la coordonnée du pixel suivant. nous allons utiliser la direction précédente. comme nous somme au premier pixel du contour détecté, on sait que la direction était d1. On va se placer 6 directions plus loin dans le sens horaire. soit en d6. A partir d'ici on va regarder si le pixel, qui est pointé par la direction, fait partie ou non de l'objet. Si il en fait partie, alors nous avons trouvé la coordonnée suivante du contour. On enregistre donc la direction que le contour prend. Si le pixel ne fait pas partie de l'objet, alors on tourne d'un cran la direction (d6->d7) jusqu'à trouver un pixel appartenant à l'objet. Si il n'y en a pas alors l'objet ne fait qu'un pixel. On recommence l'opération jusqu'à retrouver la coordonnée d'origine du contour.
Une fois le contour extérieur trouvé, on va continuer le traitement pour trouver les contours intérieurs. On continue de scruter le cadre à partir du premier pixel du contour précédent. On va faire plusieurs hypothèse pour trouver un pixel appartenant à un contour intérieur.
- le pixel fait partie de la région
- la somme du pixel et de ses 8 voisins est différente de 9 fois la valeur de la région (si région = 1, différent de 9)
- le pixel et ses 8 voisins ne font pas partie d'un autre contour. Puis on procède de la même manière que pour les contours extérieurs mais au lieu de commencer par une direction d1 on commence avec une direction d5

sens=2;
contour = zeros(size(L));
figure(1)
for i = 1 : nbobj
    boite = L(parametre(i,5):parametre(i,6),parametre(i,3):parametre(i,4));
    boite = wextend(2,'zpd',boite,1);
    numerodecontour = 0;
    boite_contour = zeros(size(boite));
    label = parametre(i,1);
    ds = sens;
    for m = 2 : size(boite,1)-1
        for n = 2 : size(boite,2)-1
            if boite(m,n) == label && sum(sum(boite_contour(m-1:m+1,n-1:n+1)))==0 && sum(sum(boite(m-1:m+1,n-1:n+1)))~=9*label
                numerodecontour = numerodecontour+1;
                xs=[m n];
                %label/Lc
                %boite/I
                %boite_contour/LM
                [xt,dnext]= findnextpoint(xs,ds,boite,boite_contour,label);
                c{i,numerodecontour}=[xs(1)+parametre(i,5)-1, xs(2)+parametre(i,3)-1 dnext];
                xp=xs;
                xc=xt;
                fin = (xs(1)==xt(1) && xs(2)==xt(2));
                while fin==0
                    boite_contour(xp(1),xp(2))=numerodecontour;
                    dnext = mod(dnext+5,8)+1;
                    [xn,dnext]= findnextpoint(xc,dnext,boite,boite_contour,label);
                    xp=xc;
                    c{i,numerodecontour}=[c{i,numerodecontour};xp(1)+parametre(i,5)-1, xp(2)+parametre(i,3)-1 dnext];
                    xc=xn;
                    fin = (xs(1)==xp(1) && xs(2)==xp(2)) || (xt(1)==xn(1) && xt(2)==xn(2));
                end
                boite_contour(xn(1),xn(2))=numerodecontour;
                c{i,numerodecontour}=[c{i,numerodecontour};xn(1)+parametre(i,5)-1, xn(2)+parametre(i,3)-1 dnext];
                ds=7;
            end
        end
    end
    i
    contour(parametre(i,5):parametre(i,6),parametre(i,3):parametre(i,4))=contour(parametre(i,5):parametre(i,6),parametre(i,3):parametre(i,4))+boite_contour(2:end-1,2:end-1);
end
subplot(224)
imshow(contour)
title('contour')

et la fonction pour trouver le point suivant du contour.

function [xc,d]= findnextpoint(xc,d,I,LM,label)
   
direction = [ 0   1
              1   1
              1   0
              1  -1
              0  -1
             -1  -1
             -1   0
             -1   1 ];

for i = 0 : 7
    xp(1)=xc(1)+ direction(d,1);
    xp(2)=xc(2)+ direction(d,2);
    if I(xp(1),xp(2))~=label
        d=mod(d,8)+1;
    else
        xc(1)=xp(1);
        xc(2)=xp(2);
        break
    end
   
end

   

voici l'affichage des contours par région.
contourbingif

Reconstruction de contour grâce aux directions

Grâce aux coordonnées de départ du contour et de toutes les directions, il est possible de retracer le contour. On va utiliser à nouveau la table des directions :
d 6 d 7 d 8 d 5 p d 1 d 4 d 3 d 2
Il nous suffit simplement de prendre comme pixel suivant le pixel désigné par la direction qui a été enregistré. Si, par exemple, la direction suivante est d4 alors x=x+1 et y=y-1. Cette méthode est utilisée par la compression RLE (Run Length Encoding).

delta/direction d1 d2 d3d4d5d6d7d8
dx 0 1 1 1 0-1 -1 -1
dy 1 1 0-1 -1 -1 0 1

direction = [ 0   1
              1   1
              1   0
              1  -1
              0  -1
             -1  -1
             -1   0
             -1   1 ];
figure(4)
[nbregion nbcontour]=size(c);
for i = 1 : nbregion
    img=zeros(M,N);
    for j = 1:nbcontour
        if ~isempty(c{i,j})
            contour = c{i,j};
            x = contour(1,1);
            y = contour(1,2);
            img(x,y)=255;
            for indice = 1 : size(contour)
                x = x + direction(contour(indice,3),1);
                y = y + direction(contour(indice,3),2);
                img(x,y)=255;
            end
        end
    end
end


contourbingif

Longueur des contours

Grâce aux directions des contours, il est possible de calculer leurs longueurs. Pour chaque point du contour, nous allons sommer les longueurs définies par les directions. Si la direction est d'indice impaire alors la distance est de 1 = 0 2 + 1 2 . Si la direction est d'indice paire la distance est de 2 = 1 2 + 1 2
Le périmètre de la région est la longueur du contour extérieur. Cependant, ce calcul surestime la longueur. Pour corriger ce défault on multiplie la longueur par un facteur de 0.95.

[nbregion nbcontour]=size(c);
for i = 1 : nbregion
    for j = 1:nbcontour
        if ~isempty(c{i,j})
            contour = c{i,j};
            taille = 0;
            for indice = 1 : size(contour)
                direction =  contour(indice,3) ;
                longueurdirection = mod(direction,2);
                if longueurdirection == 1
                    taille = taille + 1;
                else
                    taille = taille + 2^0.5;
                end
                contour(indice,4)=taille;
            end
            c{i,j} = contour;
        end
    end
 
end
 


contourbin4

Aire des régions

a i r e = x = 1 M y = 1 N I r ( x , y )

Où aire est l'aire de la région, M le nombre de ligne de la boite de la région et N son nombre de colonne. Ir(x,y)=1 si le pixel fait partie de la région sinon Ir(x,y)=0;

for i = 1 : nbobj
    boite = L(parametre(i,5):parametre(i,6),parametre(i,3):parametre(i,4));
    label = parametre(i,1);
    for m = 1 : size(boite,1)
        for n = 1 : size(boite,2)
            if boite(m,n)==label
                aire(i,1)=aire(i,1)+1;
            end
        end
    end
end


contourbin5

Circularité

La circularité est un indice qui montre la rondeur d'une région. plus l'objet est rond plus sa valeur tend vers 1, plus il est différent d'un rond plus sa valeur tend vers 0.
c i r c u l a r i t y = 4 π a i r e p e r i m e t e r 2
Où aire est l'aire de l'objet et perimeter son périmètre.

circularity = zeros(nbobj,1);
[nbregion nbcontour]=size(c);
for i = 1 : nbregion
    contour = c{i,1};
    perimeter = contour(end,4);
    aera = aire(i);
    circularity(i)= 4*pi*(aera / ((0.95*perimeter)^2));
end


contourbin6

Copyright © 2010-2014, tous droits réservés, contact : operationpixel@free.fr