tintin02100 — 2015-12-09 22:53:14

Bonjour,

J'ai une image png qui contient plusieurs formes de couleurs différentes.

http://image.noelshack.com/minis/2015/50/1449697869-sans-titre.png

Je dois dans un premier temps ne garder que les formes de couleurs noirs et créer un fichier image pour chaque forme.

Je parse donc l'image et ne garde que les pixels de couleurs noirs avec cet algorithme :

public PImage DetectionFormesNoir(PImage img){
    PImage buf = createImage( img.width, img.height, RGB );
    buf.loadPixels(); 
    
    for(int x = 0; x < img.width; x++) {
      for(int y = 0; y < img.height; y++) {
				int loc = x + (y * img.width);
        color c = img.pixels[loc];
        
        float r = red(c);
        float v = green(c);
        float b = blue(c);
        
        if(r == 0 && v == 0 && b == 0 ) {
          color col = color(r, v, b);
          buf.pixels[loc] = col;
        } else{
          buf.pixels[loc] = color(255, 255, 255);
        }
        
  		}
    }
    
    buf.updatePixels();    
    return buf;

http://image.noelshack.com/minis/2015/50/1449697868-sans-titre1.png

Puis applique au résultat le filtre de sodel afin de récupérer les contours des différentes formes noirs.

Fonction Sodel : http://www.mon-club-elec.fr/pmwiki_mon_ … treSobel2D

http://image.noelshack.com/minis/2015/50/1449697869-sans-titre2.png

En soit cela fonctionne très bien. Mais je ne vois pas de là comment récupérer chaque forme et les enregistrer séparément. Auriez-vous une idée?



Merci d'avance,
Valentin

PS : Je n'ai pas le droit d'utiliser OpenCV ou autre librairie ;)

Mushussu — 2015-12-10 17:51:24

Bonjour,

Beau problème, j'avais un peu débroussaillé la vision par ordinateur il y a quelques temps, mais sans rien imlémenter.

Il faut faire une détection des coins après avoir fait les contours. Il y a ce lien :
http://www.developpez.net/forums/d32513 … is-imagej/

Sinon, un autre réalisé avec MathLab :
http://robotics.eecs.berkeley.edu/~sast … index.html

Je te souhaite plein de courage.

tintin02100 — 2015-12-10 17:58:04

Bonjour Mushussu,

Merci pour les liens :)
Je vais y regarder.
Ce qui est dommage c'est que j'aimerai ne pas toucher au code actuel car sobel récupère déjà les contours... Il faut juste réussir à charger chaque objet dans une image différente :/

Mushussu — 2015-12-10 23:54:42

Je n'avais pas bien lu ta demande. Pour récupérer les différentes formes dans des images, je n'ai pas eu besoin de Sobel. Dès que je trouve un point noir, je scrute son environnement pour en trouver d'autres. Je regarde le tas de pixel adjacents. Voici le code :

PImage origine, test;
ArrayList<PImage> liste; // Tableau de PImage qui contiendra les formes independantes

void setup() {
  size(1500, 500);
  origine = loadImage("IMG_1999.PNG");
  test = detectionFormesNoires(origine);
  liste = new ArrayList<PImage>();
  int i = 0;
  while (!imageBlanche(test)) {
    PImage forme = separation(test);
    liste.add(forme);
    //forme.save("forme" + i + ".png");
    i++;
  }
  println("Extraction de " + i + " formes");
}

void draw() {
  image(origine, 0, 0);
  image(test, 500, 0);
  image(liste.get(0), 1000, 0);
}

boolean imageBlanche(PImage img) {
  boolean test = true;
  for (int i = 0; i < img.width * img.height; i++) {
    if (img.pixels[i] == color(0)) {
      test = false;
    }
  }
  return test;
}

PImage separation(PImage img) {
  PImage retour = createImage(img.width, img.height, RGB);
  for (int i = 0; i < img.width * img.height; i++) {
    retour.pixels[i] = color(255);
  }
  img.loadPixels();
  boolean vierge = true;
  int debut = 0;
  int tt = 0;
  for (int i = 0; i < img.width; i++) {
    for (int j = 0; j < img.height; j++) {
      int loc = j + (i * img.width);
      tt++;
      if (img.pixels[loc] == color(0)) {
        vierge = false;
        debut = loc;
        break;
      }
    }
    if (!vierge) {
      break;
    }
  }
  IntList liste = new IntList();
  IntList nouveau = new IntList();
  IntList nouveauP = new IntList();
  liste.append(debut);
  nouveau.append(debut);
  do {
    nouveauP.clear();
    // Pour chaque nouveau pixel, recherche dans les 4 directions s'il y en a un nouveau noir
    for (int i : nouveau) {
      if (img.pixels[i - img.width] == color(0)) {
        nouveauP.append(i - img.width);
        img.pixels[i - img.width] = color(255);
      }
      if (img.pixels[i + img.width] == color(0)) {
        nouveauP.append(i + img.width);
        img.pixels[i + img.width] = color(255);
      }
      if (img.pixels[i - 1] == color(0)) {
        nouveauP.append(i - 1);
        img.pixels[i - 1] = color(255);
      }
      if (img.pixels[i + 1] == color(0)) {
        nouveauP.append(i + 1);
        img.pixels[i + 1] = color(255);
      }
    }
    nouveau.clear();
    for (int i : nouveauP) {
      liste.append(i);
      nouveau.append(i);
    }
  } while (nouveauP.size() != 0); // Arrete si aucun pixel noir n'est trouve
  for (int i : liste) {
    retour.pixels[i] = color(0, 0, 0);
  }
  retour.updatePixels();
  return retour;
}

public PImage detectionFormesNoires(PImage img) {
  PImage buf = createImage( img.width, img.height, RGB );
  buf.loadPixels(); 

  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++) {
      int loc = x + (y * img.width);
      color c = img.pixels[loc];

      float r = red(c);
      float v = green(c);
      float b = blue(c);

      if (r <= 10 && v <= 10 && b <= 10 ) {
        buf.pixels[loc] = color(0);
      } else {
        buf.pixels[loc] = color(255, 255, 255);
      }
    }
  }

  buf.updatePixels();    
  return buf;
}
tintin02100 — 2015-12-11 09:17:24

*-* Tu es fabuleux @Mushussu.
Ton code est juste magnifique !!!
Un grand merci à toi :D

Mushussu — 2015-12-11 10:06:52

N'exagérons rien, il y a plein d'optimisation à réaliser. Ne pas repartir de zéro pour trouver un nouveau point noir. Change le test de l'image blanche.

Je m'y collerais ce week-end si j'ai le temps.

Feras-tu une détection de coin pour trouver les formes rectangulaires ?

tintin02100 — 2015-12-11 13:55:47

Le système détecte tous les objets qu'ils soient rond ou carré ou en étoile alors pourquoi détecter les contours? C'est peut être moins gourmand?
Il me manquait que ta partie pour finir le programme. Je dois juste le modifier pour qu'il puisse dans un deuxième cas enregistrer tous les objets dans des fichiers différents aussi :)

tintin02100 — 2015-12-11 16:38:34

Comment modifierais tu ta fonction séparation mais pour des objets de n'importe quelle couleur?

Mushussu — 2015-12-13 11:01:37

Voilà, j'ai tout empaqueter dans une classe.
Avec la souris tu peux sélectionner la couleur dans l'image principale.

tintin02100 — 2015-12-13 23:20:17

Waouw tu as sacrement bien réduit le code. Un grand merci :D

Je vais essayer d'implanter une fonction pour qu'il recherche toutes les couleurs affichées sur l'écran et les enregistres direct. Comme dit sur le sujet.

:)

tintin02100 — 2015-12-14 09:29:13

Ca m'énerve XD

J'essaye d'automatiser la recherche des couleurs  présent sur l'image.
Je veux stocker les couleurs dans un tableau.

color[] colorArray = new color[1000];

public void DetectionCouleurs(PImage img){
  for(int x = 0; x < img.width; x++) {
    for(int y = 0; y < img.height; y++) {
      
      int loc = x + (y * img.width);
      color c = img.pixels[loc];
      float r = red(c);
      float g = green(c);
      float b = blue(c);
      
      if(r != 255 && g != 255 && b != 255 ){
        for(int i = 0; i < colorArray.length; i++){
          color c_old = colorArray[i];
          float r_old = red(c_old);
          float g_old = green(c_old);
          float b_old = blue(c_old);

          if(c != c_old){
              colorArray[i] = color(r, g, b);
          }
       }
    }
  }
}

Cependant il enregistre quand même toutes les couleurs en double malgré toutes les if... Saurais tu d'ou vient mon erreur? Comment toi ferais tu?

Le but du jeu étant qu'en suite je parse le tableau et enregistre les images automatiquement pour chaque couleur

void setup() {
  origine = loadImage("0.png");
  size(1600, 500);
  liste = new ArrayList<PImage>();
  t = new Traitement(10); // Initialise avec une tolerance pour les couleurs
  DetectionCouleurs(origine);
  for(int i = 0; i < colorArray.length; i++){
    color c = colorArray[i];
    float r = red(c);
    float g = green(c);
    float b = blue(c);
    println(red(c) + " : " + green(c) + " : " + blue(c));
    liste = t.process(origine, color(0, 0, 0));
  }
  frameRate(1);
  compteur = 0;
}
Mushussu — 2015-12-14 10:34:19

Tu n'es pas obligé de passer par la décomposition en RGB. Le type color est un entier :
https://processing.org/reference/color_datatype.html

Il "suffit" de comparer les deux entiers.

Il est possible de faire ainsi :

  IntList listeCouleur = new IntList();
  for (int i = 0; i < origine.pixels.length; i++) {
    boolean correspondance = false;
    for (int element : listeCouleur) {
      if (origine.pixels[i] == element) {
        correspondance = true;
        break;
      }
    }
    if (!correspondance) {
      listeCouleur.append(origine.pixels[i]);
    }
  }

Le problème, c'est que l'on obtient plus de 2000 couleurs. Parce que les couleurs rouges ne sont pas franches. Il y a de micro-variations et le bords sont un peu flous.
Il serait préférable de passer l'image à travers la moulinette d'un filtre de seuil.

Ce n'est peut-être pas la bonne approche du problème. Peux-tu donner l'énoncé de l'exercice ?

tintin02100 — 2015-12-14 10:43:27

Ci-joint le sujet :)

Mushussu — 2015-12-14 11:23:06

C'est bien cela, l'approche n'est pas la bonne. Puisque c'est un fond uniforme, il faut distinguer les couleurs qui ne sont pas semblables au fond.

De plus, il faudra recadrer les images pour qu'elles soient au plus proche de la forme.

Il faut poser un postulat pour le fond. On peut dire que si la couleur des points de la première ligne est uniforme alors cette couleur est la couleur du fond. Sinon, on teste la dernière ligne, première colonne, dernière colonne.
Une fois le couleur du fond définie, on transforme dans une image tampon le fond en blanc et tout ce qui n'est le fond en noir, pour avoir ce que l'on connait.

tintin02100 — 2015-12-14 11:50:38

Ca me parle pas du tour :p

Olivier — 2015-12-14 12:04:16

citation :

Ca me parle pas du tour :p

Mushussu te décris juste un moyen de repérer le fond de l'image, compte tenu du fait que les couleurs des objets ne sont, elles, pas parfaitement uniformes.
L'idée est de remplacer le fond par du blanc et le reste par du noir.

tintin02100 — 2015-12-14 12:24:07

Oui je dois passer par niveau de gris :)

tintin02100 — 2015-12-14 14:44:50

J'ai réussi à stocker les pixels avec ta fonction. Et à récupérer certaines images. Il ne me les récupères pas toutes.
J'ai le droit a un jolie message d'erreur de java :P

An OutOfMemoryError means that your code is either using up too much memory
because of a bug (e.g. creating an array that's too large, or unintentionally
loading thousands of images), or that your sketch may need more memory to run.
If your sketch uses a lot of memory (for instance if it loads a lot of data files)
you can increase the memory available to your sketch using the Preferences window.
Olivier — 2015-12-14 23:18:39

Est-ce que tu as essayé de faire ce que le message te suggère ?

citation :

you can increase the memory available to your sketch using the Preferences window

Mushussu — 2015-12-15 00:23:47

C'est une fuite en avant Olivier, c'est comme un bol de noix de cajou dans une réunion de la fête des 0 et des 1. Tu auras beau en rajouter il sera toujours vide.
C'est à la racine qu'il faut attaquer. Si tu cherches toutes les couleurs disponibles, il y en a beaucoup, trop pour la mémoire. Dans un post précédent j'en avais plus de 2000 donc si tu créé 2000 images il va râler le processeur.
Il faut distinguer ce qui est le fond et ce qui ne l'ai pas.
J'ai créé une méthode pour transformer les couleurs en noir et en blanc :

PImage detectionFond(PImage img) {
  PImage travail = img.get();
  color fond = img.pixels[0];
  // 
  boolean test = true;
  for (int i = 0; i < img.width; i++) {
    if (img.pixels[i] != fond) {
      test = false;
    }
  }
  if (!test) {
    println("Pas de couleur de fond");
    return null;
  }
  println(red(fond) + " " + green(fond) + " " + blue(fond));
  // Elaboration de la copie de travail
  for (int i = 0; i < img.pixels.length; i++) {
    if (img.pixels[i] == fond) {
      travail.pixels[i] = color(255);
    } else {
      travail.pixels[i] = color(0);
    }
  }
  return travail;
}

Ensuite tu peux appliquer la moulinette. Pour finir j'ai fait la méthode pour sauvegarder les images.
Attention, dans l'image des carrés noirs, rouges et bleus le fond n'est pas uniforme. Des micro-variations empêchaient de sortir un résultat. Donc j'ai lissé le fond.

Si tu as des questions, n'hésite pas.

Olivier — 2015-12-15 00:38:08

citation :

C'est une fuite en avant Olivier, c'est comme un bol de noix de cajou dans une réunion de la fête des 0 et des 1. Tu auras beau en rajouter il sera toujours vide.

True. :P

Tu m'accorderas tout de même qu'il existe une taille de bol théorique suffisamment  grand pour contenir exactement le nombre de noix de cajous ingérables par les convives... :D

Mushussu — 2015-12-15 00:48:35

Entres-tu dans les paramètres de cette équation ?

Mais une brillante démonstration a déjà été réalisée avec des cacahuètes. Je pense que les noix de cajou sont plus addictives que les cacahuètes :
https://books.google.fr/books?id=yKc-BA … mp;f=false

tintin02100 — 2015-12-15 06:38:14

Bonjour les gars,

Après avoir bien fait râler le processeur en effet en supprimant les fond, ça passe mieux :p
Je n'ai regardé que ton code après... ça se rejoint xD Comment fais tu ton recadrage? Tu regardes la ou ce n'est pas blanc en fond et prends le minimum et le maximum?

Je dois réaliser un petit rapport xD

Le simple fait de supprimer le fond permet en fait de réduire la taille en mémoire. Mais si je lui donne une image en 4K (c'est juste un exemple), même en retirant le fond, la mémoire pourrait elle cracher?

Sinon à part ca je dois avouer que ton code fonctionne très bien xD
Je vais ajouter le fait de pouvoir choisir de soit garder les couleurs de fond ou toutes les couleurs.

Encore un grand merci à vous deux ^^

A très bien tôt ;)

Mushussu — 2015-12-15 08:17:43

citation :

Comment fais tu ton recadrage? Tu regardes la ou ce n'est pas blanc en fond et prends le minimum et le maximum?

Je balaye l'image, les lignes les unes après les autres. Le premier point que je rencontre me donne le y du point de départ du rectangle ensuite je regarde le point le plus à gauche (min) et le point le plus à droite(max) pour le x et la largeur. à chaque fois que je vois un point noir je dit que c'est le dernier, comme cela quand je n'en vois plus la coordonnée y est stockée ce qui me donne la hauteur du rectangle.


citation :

Le simple fait de supprimer le fond permet en fait de réduire la taille en mémoire. Mais si je lui donne une image en 4K (c'est juste un exemple), même en retirant le fond, la mémoire pourrait elle cracher?

A toi de voir l'algorithme le plus robuste.

tintin02100 — 2015-12-15 09:03:33

Ton algo  est bien plus robuste xD

Comme tu l'as fait pour la fonction recadrage, pourrais tu décrire décomposition et séparation?

Décomposition analyse pour chaque pixels, si y les pixels à ses contours sont de la même couleurs. c'est la méthode d'Harrys il me semble?
Séparation lui crée des nouvelles images pour chaque forme et les renvoies?

Mushussu — 2015-12-15 09:53:25

La méthode décomposition n'a plus lieu d'être puisque l'image de travail à été réalisée avec la méthode decompositionFond().

J'ai ajouté des commentaires dans le corps des méthodes pour t'aider.

Olivier — 2015-12-15 12:22:07

tintin02100 a écrit:

Encore un grand merci à vous deux

Oui. Merci.
T'aider autant n'a pas été de tout repos pour moi mais, je suis vraiment content du résultat. :rolleyes:

Mussushu a écrit:

Entres-tu dans les paramètres de cette équation ?

Je ne vois absolument pas pourquoi tu poses cette question. :D