[Matlab] Analyse d’image (cercles)

a marqué ce sujet comme résolu.

Bonjour à tous,

Pour un projet, je dois analyser plusieurs images (d’une même expérience, ie. Ce sont des réplicats) de ce type.

Droplets image (Eau & Huile)
Droplets image (Eau & Huile)

In fine, mon but sera d’obtenir le volume (en assumant des sphères) pour chacune des "gouttes" complètes (huile + eau). On élimine évidemment ce qui n’est pas circulaire (eg. la demi-sphère en haut à gauche). Ce sera un volume relatif par rapport à d’autres images. Je m’explique, je vais effectuer mon expériences à différentes températures pour voir l’effet sur le volume. Et à chacun de ces températures j’ai plusieurs images afin d’avoir des réplicats.

Comment je pense procéder pour l’analyse de chaque image: 1)Créer un masque pour ne pas avoir tout ce qui est dehors de la sphère (ou des différentes sphères si j’en ai plusieurs sur une même image)

2)Retirer le bord du cercle pour n’avoir que ce qui est à l’intérieur

3)Obtenir le volume en assumant la sphère parfaite

4)Stocker le volume de chaque sphère dans une matrice

Début de l’écriture du code:

Voici le code que j’ai écrit jusqu’à présent (en m’inspirant de certaines ressources trouvées sur Internet dans la documentation Matlab notamment). J’ai annoté et je pense surtout qu’il manque une partie au début (que je ne sais pas comment écrire) pour la collecte des images.

close all
clear all
clc

%Ici, j'aimerais trouver un moyen de trouver / d'identifier les sphères 
%Comment puis-je importer mes images ? (Elles se trouvent dans un fichier,
%format .tiff)

 
vol_tot_droplets=zeros(1,16); %Volume des sphères (ie. "droplets") = 0 (initialisation)


 
imshow(im_res,[0 255])

[size1_Hough,size2_Hough]=size(res_Hough);
mask=zeros(544,512); %544 x 512 est la taille de mon image (à modifier si elle change)
    
    
%% Création du masque (retirer tout ce qui est en dehors de la grosse sphère (huile + eau)

    for i=1:size1_Hough
        k=res_Hough(i,2); %x et y sont opposé image vs matrice => Equation cercle à considérer: (x-h)^2+(y-k)^2=r^2
        h=res_Hough(i,3);
        r=res_Hough(i,4);
    
    %enter the circle
    
        for x=1:544  %Dimensions de l'image
            for y=1:512
                if (x-h)^2+(y-k)^2<(r-12)^2 %Le "-12" est pour éviter d'avoir le bord foncé (on regarde à l'intérieur du cercle)
                   %On doit tester plusieurs valeurs (-10, -20, etc. p.ex)
     
                mask(x,y)=im_res(x,y);
                
                end
            end
        end
        figure(3)
        imshow(mask,[0 255]);
        %Pour trouver les cercles (via transformation de Hough)
        [centers,radii] = imfindcircles(mask,[1 10], ...  %intervalle de rayons (à tester en fonction de l'img)
            'ObjectPolarity','dark','Sensitivity',0.94); %dark car bord plutôt foncé; jouer avec "Sensitivity" en fonction de la forme
        viscircles(centers,radii);
        n_droplets=length(centers);
        %Calcul du volume en admettant une sphère
        for d=1:length(radii)
             vol_tot_droplets(loop)=4./3*pi*radii(d)^3+vol_tot_droplets(loop);
        end
        mask=zeros(544,512);  %Remettre le masque à zéro avant de recommencer avec la prochaine sphère (huile + eau)
    end

N’hésitez pas à me demander de préciser certaines choses. :)

Un grand merci d’avance pour votre aide! Sotibio

+0 -0

Salut,

Je pense que ton problème n’est pas super bien expliqué, en fait.

Tu peux montrer à la main ce que tu veux obtenir comme résultats ?

Aabu

Évidemment ! Désolé de ne pas avoir été clair. J’ai fais un petit schéma pour expliquer la procédure.

Donc, on part d’une image prise par une caméra "haute vitesse" comme celle d’en haut. Ce qui nous intéresse pour l’analyse c’est l’intérieur des grosses gouttes (les grosses gouttes sont faites d’huile et eau et on incruste des choses à l’intérieur mais pas important pour l’analyse).

Comme c’est l’intérieur qui nous intéresse, l’étape 1 serait de créer un masque pour enlever tout ce qui est autour du cercle.

Procédure - Etape 1
Procédure - Etape 1

Ensuite, je dois retirer le gros cercle "épais" qui entoure les plus petits cercles. Finalement, je veux connaître le volume total des gouttes à l’intérieur de ce cercle (donc détection de ceux-ci puis trouver le rayon de chaque et sommer les volumes).

Procédure - Etape 2
Procédure - Etape 2

Dès qu’une goutte d’huile+eau (grosse goutte) est analysée, passer à une autre image (j’en ai une centaine de chaque type).

Est-ce un peu plus clair ? N’hésite pas à me dire :)

Merci !!

Je comprends que ton problème, c’est en premier lieu d’importer des images TIFF.
As-tu exploité ce fil Working with TIFFs (import, export) in Python using numpy ?

etherpin

Merci mais je souhaite travailler avec Matlab qui a pas mal de fonction faites ce qui facilitera le travail je pense. Je pense utiliser la fonction imread, cependant je me demande si je peux mettre tout un dossier d’image (car j’aurai dans un dossier 100 images à traiter et pas une seule) avec une commande du style "C:/Users/Sotibio/Documents/…" (dossier des images).

Que pensez-vous de la stratégie et par rapport à mon code actuel ?

Merci

Salut,

Il faut absolument que l’aide de Matlab devienne ta meilleure amie, parce que ça t’aidera à trouver les fonctions dont tu as besoin. Matlab a une des meilleures documentations qu’il soit, il faut absolument savoir s’en servir ! Pour récupérer la liste de tes fichiers, la fonction dir te sera utile. Aussi, tu peux utiliser des mots-clés sur ton moteur de recherche pour trouver des gens avec des problèmes similaires sur les forums officiels de Matlab. Par exemple, il y a des idées pour le masquage.

Sinon, je pense que tu as en fait déjà en tête la structure générale de ton traitement :

  • pour chaque image d’un dossier

    • pour chaque grande sphère d’une image

      • calcul du volume des sphérules intérieures

C’est assez dur de t’aider si on ne sait pas exactement ce qui te gêne. Là, j’ai l’impression que tu as déjà tout en main pour finir.

Tu es débutant avec Matlab ou en programmation en général ? J’ai l’impression que tu tâtonnes pas mal sur les détails techniques et qu’il y a quelques maladresses.

Merci @Aabu. Je vais regarder les liens que tu m’as donné (fonction dir et masquage) et je reviendrai après avoir lu de la doc dessus.

Je suis débutant en Matlab / Programmation, en effet. J’ai une idée de comment faire comme je disais mais pour l’écrire (en code), je suis novice.

Hello,

Me revoilà. J’ai passé la journée dessus. J’ai laissé tombé la stratégie que j’avais expliqué car je n’arrive pas à la coder.

Je suis parti de zéro sans les petits bouts de code d’en haut. J’ai décidé de commencer avec une seule image (celle du dessus) et une fois que ça fonctionnera, le généraliser à tout le dossier (car je sais pas comment utiliser la fameuse fonction dir malgré la doc).

I=imread('myPicture.jpeg');
I1=rgb2gray(I);
I2=255-I1;
BW = imbinarize(I2,'adaptive','Sensitivity',0.51);

bw2=imcomplement(BW);
bw3=imfill(bw2,'holes');


[B,L] = bwboundaries(bw3,'noholes');
threshold=0.6;
stats = regionprops(L,'Area','Centroid');
for k = 1:length(B)

  % obtain (X,Y) boundary coordinates corresponding to label 'k'
  boundary = B{k};
  % compute a simple estimate of the object's perimeter
  delta_sq = diff(boundary).^2;    
  perimeter = sum(sqrt(sum(delta_sq,2)));
  % obtain the area calculation corresponding to label 'k'
  area = stats(k).Area;
  % compute the roundness metric
  metric = 4*pi*area/perimeter^2;
  
  % display the results
  metric_string = sprintf('%2.2f',metric);

  % mark objects above the threshold with a black circle
  if metric < threshold
   bw3(L==k)=0;
  end 
end
bw4=bwareaopen(bw3, 200);

bw5=BW.*bw3;
bw5=bwareaopen(bw5, 50);
SE = strel('disk',1,4);
bw5 = imdilate(bw5,SE);
bw5=imfill(bw5,'holes');
bw5=imcomplement(bw5);
final=bw4.*bw5;
final=imcomplement(final);
%imshow(final)

%Mask creation using bw4(complete droplets)
[B1,L1] = bwboundaries(bw4,'noholes');
s1 = regionprops(L1,'Area','Centroid');
imshow(bw4) 
hold on
for k = 1:numel(s1)
    c = s1(k).Centroid;
    text(c(1), c(2), sprintf('%d', k), ...
        'HorizontalAlignment', 'center', ...
        'VerticalAlignment', 'middle');
end
hold off
for i=1:numel(s1)
    mask=bw4;
    for j=1:numel(s1)
        if(j~=i)
       mask(L1==j)=0;  
        end
    end
    if(i==1)
    drop1=final.*mask; %stores information of droplet 1
    end
    if(i==2)
    drop2=final.*mask; %stores information of droplet 2
    end 
end

La première étape est la conversion en "gray scale" (même si je pense que pour cette image c’est pas nécessaire), puis "inverted" (255 - I1) et enfin mise en binaire pour n’avoir que du noir et blanc. Je cherche enfin les grosses sphères et je les numérotes pour pouvoir les traiter séparément après.

Je peux expliquer plus en détails mais je suppose que pour vous c’est assez trivial comme code (?).

Voici donc l’output.

Output
Output

À la fin de ma toute dernière boucle, si je révèle "drop2", je me retrouve avec (similaire avec la "drop1"):

Gouttes "2"
Gouttes "2"

C’est exactement ce que je veux. Après ça j’imagine que je peux utiliser imfindcircles, trouver l’aire de chaque puis le rayon et donc le volume.

Mon soucis c’est que ça à l’air de fonctionner mais c’est pas encore automatisé du tout. Je voudrais évidemment qu’automatiquement après avoir calculé un volume, il passe à l’autre et s’il y a plus de "droplet" à analyser passer à l’image suivante avant de donner au final la matrice avec tous les volumes.

Je sais pas si vous voyez ce que je veux dire.

J’espère avoir été plus clair et que je montre ma détermination à résoudre ce problème :p

PS: J’ai essayé avec d’autres images, ça a l’air de bien détecter. Exemple 2 avec cette fois 4 gouttes:

Exemple 2
Exemple 2

(Le soucis ici c’est que la goutte 4 est à coupée et pourtant prise en compte mais bon… ça on peut régler après en coupant l’image d’input simplement je suppose.)

+0 -0

Salut,

J’ai laissé tombé la stratégie que j’avais expliqué car je n’arrive pas à la coder.

C’est dommage, parce qu’elle semble être plus simple… C’est normal en étant débutant qu’un problème réel paraisse compliqué et de trouver des obstacles techniques sur le chemin. Tu étais clairement sur la bonne voie à mon avis.

J’ai décidé de commencer avec une seule image (celle du dessus) et une fois que ça fonctionnera, le généraliser à tout le dossier (car je sais pas comment utiliser la fameuse fonction dir malgré la doc).

Bonne stratégie. Pour la fonction dir le passage le plus intéressant pour toi est le paragraphe « Find Information in the Return Structure ». Je te conseille chaudement d’apprendre à t’en servir à titre d’exercice avant de tenter sur ton problème réel. Tu peux te faire un petit dossier de test à part, un petit script qui va avec, et tu essaies d’afficher les infos des fichiers par exemple.

Je cherche enfin les grosses sphères et je les numérotes pour pouvoir les traiter séparément après.

La manière dont tu les cherches est assez compliquée. Je ne sais pas pourquoi tu as choisis de faire ça (ou à quel endroit tu as trouvé ça). En gros, tu cherches des zones contiguës, puis tu sélectionnes celles qui ressemblent suffisamment à des cercles… Comme tes gouttelettes semblent extrêmement sphériques, je pense que tu pourrais chercher directement des cercles. Ce qui serait peut-être plus simple et plus clair. Et peut-être même que ça t’empêcherait de sélectionner des gouttes incomplètes.

Je peux expliquer plus en détails mais je suppose que pour vous c’est assez trivial comme code (?).

Ce n’est pas trivial, non. Tu utilises une méthode particulière pour résoudre un problème spécifique. Pourquoi ce serait trivial ?

Je voudrais évidemment qu’automatiquement après avoir calculé un volume, il passe à l’autre et s’il y a plus de "droplet" à analyser passer à l’image suivante avant de donner au final la matrice avec tous les volumes.

Deux boucles imbriquées font l’affaire. Je vois que tu en utilises, ça ne devrait pas être un gros problème pour toi.

(Le soucis ici c’est que la goutte 4 est à coupée et pourtant prise en compte mais bon… ça on peut régler après en coupant l’image d’input simplement je suppose.)

Tu as envie que ton script le fasse à ta place. Si tu fais son job à la main, ce n’est pas très intéressant de le programmer.


Je pense que tu devrais t’attacher à découper ton problème général en sous-problèmes, que tu résoudrais séparément. Ce n’est pas forcément facile quand on est débutant de le faire, mais je pense que tu devrais vraiment essayer de le faire. Le gain pour toi sera important :

  • tu obtiendras ainsi la structure de ton script (que tu pourras avantageusement découper en fonctions) ;
  • tu te concentreras sur des problèmes plus petits et plus facile à résoudre, que tu auras « juste » à assembler à la fin.

Pour chaque problème, tu dois définir correctement quelles sont les entrées et le résultat. Par exemple :

  • lister les fichiers d’un dossier :

    • entrée : le nom du dossier
    • sortie : la liste des fichiers
  • identifier toutes les grosses gouttes :

    • entrée : un fichier d’image
    • sortie : le centre et le rayon de chaque goutte
  • identifier les petites gouttes :

    • entrée : une image, et le centre et le rayon de la goutte visée
    • sortie : la liste des rayons des petites gouttes
  • calculer le volume total des petites gouttes dans une grosse goutte:

    • entrée : la liste des rayons
    • sortie : le volume total

La manière dont tu les cherches est assez compliquée. Je ne sais pas pourquoi tu as choisis de faire ça (ou à quel endroit tu as trouvé ça). En gros, tu cherches des zones contiguës, puis tu sélectionnes celles qui ressemblent suffisamment à des cercles… Comme tes gouttelettes semblent extrêmement sphériques, je pense que tu pourrais chercher directement des cercles. Ce qui serait peut-être plus simple et plus clair. Et peut-être même que ça t’empêcherait de sélectionner des gouttes incomplètes.

En fait, je n’ai trouvé ça nul part sauf la partie du code qui permet de numéroter chaque objet avec une certaine circularité. J’avais l’impression que c’était beaucoup plus simple… Donc toi tu penses que ça serait plus simple de chercher directement des cercles via la fonction imfindcircles ? Car si on regarde la toute dernière image, les objets "1" et "3" me semblent pas parfaitement circulaires par exemple…

Avoir binarisé l’image est quand même une bonne idée ou pas ?

Je vais essayer de suivre ta structure mais au pire sinon je ferai tout ça à la main via ImageJ et je prendrai moins de points (mon erreur sera bien plus grande mais bon au moins j’aurai des données à presenter à la réunion du groupe).

Surtout que je vois pas trop dans la structure que tu proposes pour les petites gouttes, en entrée j’ai une image, le centre et le rayon de la goutte visée mais toutes mes grosses gouttes sont de taille très similaire (officiellement d’après la théorie exactement identiques même)

Merci!

+0 -0

Donc toi tu penses que ça serait plus simple de chercher directement des cercles via la fonction imfindcircles ? Car si on regarde la toute dernière image, les objets "1" et "3" me semblent pas parfaitement circulaires par exemple…

imfindcircles est réglable. Il faut regarder la doc pour bien comprendre comment et si c’est bn pour ton problème.

Puis bon, tu as plein de choses qui pourraient t’aider dans la doc :

imfindcircles does not find circles with centers outside the domain of the image.
imfindcircles preprocesses binary (logical) images to improve the accuracy of the result. It converts truecolor images to grayscale using the function rgb2gray before processing them.

Documentation de Matlab

.

Avoir binarisé l’image est quand même une bonne idée ou pas ?

Probablement.

Je vais essayer de suivre ta structure mais au pire sinon je ferai tout ça à la main via ImageJ et je prendrai moins de points (mon erreur sera bien plus grande mais bon au moins j’aurai des données à presenter à la réunion du groupe).

Ton planning est une autre histoire, si tu veux présenter des résultats préliminaires, mais là tu serais entrain d’abandonner une deuxième fois très près du but…

Surtout que je vois pas trop dans la structure que tu proposes pour les petites gouttes, en entrée j’ai une image, le centre et le rayon de la goutte visée mais toutes mes grosses gouttes sont de taille très similaire (officiellement d’après la théorie exactement identiques même)

sotibio

Pourquoi un rayon similaire changerait quoi que ce soit ?

Je vais rester avec ce code pour mes résultats préliminaires mais continuer en parallèle pour l’automatiser et l’améliorer. Je reviendrai donc sûrement bientôt pour plein de questions (je vais essayer de comprendre comment utiliser dir déjà !). :)

Hello,

À mon avis ça serait effectivement mieux mais dans tous les cas de figures selon moi tu n’arriveras jamais à un résultat optimal sans recourir à du deep learning. Tout simplement car certaines de tes gouttes sont "out of focus". Il serait peut-être possible d’améliorer ça en prenant plusieurs images à différentes hauteurs puis de les sommer (z-stacking) mais ça demande de refaire l’expérience évidemment.

Un peu moins bien mais quand même efficace, une solution de machine learning avec ilastik qui crée des masques (que tu peux importer dans MATLAB je pense). Je sais pas si ça fonctionnerait ici mais pourquoi pas essayer.

Dernière solution, faire ce que tu fais ou l’autre solution (selon moi les deux se valent). Certes tu loupes des petites gouttes mais tu as aussi un rayon légèrement plus grand sur celles "out of focus". Donc qui sait, ça se compense peut-être. Calculer à la main pour une image n’est pas une mauvaise idée. Ça te permettra de comparer avec les rayons sortis par ton algo et de donner l’ordre de précision quand tu présentes tes résultats.

Je sais pas dans quel cadre tu effectues ce travail mais si c’est en Labo de recherche dans une Université, en général il y a un Centre de Microscopie et ils ont des personnes qui analysent des centaines d’images assez complexes. Si t’as l’opportunité, aller parler à des spécialistes de l’image peut-être utile (et parfois ils le font pour toi, ça les énerve que les données soient mal présentées et fausses :p )

Edit: Aucune idée si ça peut être utile mais cet article (critiqué par certains) est récemment paru. Je pense pas que ça t’aidera vu que tu est débutant en programmation et dans le domaine mais je le met pour les autres au cas où.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte