IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Traitement d'images Discussion :

Extraire le nombre de pixels par classe de couleur


Sujet :

Traitement d'images

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 25
    Points : 10
    Points
    10
    Par défaut Extraire le nombre de pixels par classe de couleur
    Bonjour à tous!
    Je travaille avec deux collégues américains sur un projet complexe qui consiste à définir des méthodes de traitements d'images permettant de faire le distingo entre les photographies et les images générées par ordinateur (CGI).
    Pour cela, deux critères de sélection ont été retenus: les critères de texture, traités par les filtres de Gabor, et les critères visuels, déclinés en 4 catégories.
    Je m'intéresse actuellement plus particulièrement à la première d'entre elles: le nombre de couleurs uniques.
    Trois chercheurs universitaires canadiens ont déjà travaillé sur ce projet et ont conclu que les CGI contenaient de manière générale 25% de moins de couleurs uniques que les véritables photographies. A moi d'arriver à la même conclusion!!

    Il s'agit en fait pour moi d'écrire un programme (Java ou même Ruby/ImageMagick) me permettant à partir d'une image RGB d'extraire le nombre de couleurs différentes de cette image et de les classer par nombre de pixels.
    Ainsi, la richesse "U" de la palette de couleurs d'une image peut être calculée en normalisant le nombre total de couleurs uniques par le nombre total de pixels (en sachant que dans une image, avec un triplet R,G,B pour chaque pixel, deux pixels ont la même couleur si et seulement si ils ont les mêmes composants R, G et B).
    De plus, pour compliquer la chose afin de réduire l'impact du bruit, un triplet est comptabilisé seulement s'il apparaît plus de dix fois dans la même couleur.
    U=Ndifférents triplets/Npixels.

    En cherchant dans les archives, j'ai trouvé un sujet où il était question de cette extraction des classes de couleurs, mais par "catégories" et non par couleurs uniques.
    http://www.developpez.net/forums/sho...d.php?t=289003

    Merci pour votre aide, qui me serait bien utile!

  2. #2
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 084
    Points
    16 084
    Par défaut
    Vu que j'avais eclipse d'ouvert, j'ai testé tes hypotheses:

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
     
    import javax.imageio.ImageIO;
     
    public class ColorCounter {
     
    	public static void main(String[] args) {
     
    		// lecture de l'image
    		BufferedImage image = null; 
    		try {
    			image = ImageIO.read(new File("lena512.jpg"));
    		} catch (IOException e) {
    			e.printStackTrace();
    			return;
    		}
     
    		// Map (rgb)=>count
    		Map<Integer, Integer> rgbmapcount = new HashMap<Integer, Integer>();
     
    		// parcours des pixels de l'image, et creation/mise a jour de la Map
    		for(int y=0;y<image.getHeight();y++) {
    			for(int x=0;x<image.getWidth();x++) {
    				// valeur [a]rgb, codé sur un entier (4 octets)
    				int rgb = image.getRGB(x,y);
     
    				// recherche dans la map
    				if (!rgbmapcount.containsKey(rgb)) {
    					rgbmapcount.put(rgb, 1); // n'existe pas => creation
    				} else {
    					int previouscount = rgbmapcount.get(rgb);
    					rgbmapcount.put(rgb, previouscount+1); // existe deja => mise a jour (increment)
    				}
    			}
    		}
     
    		// Combien de couleurs apparaissent plus de 10 fois ?
    		int distinctcolor=0;
    		for(int rgb:rgbmapcount.keySet()) {
    			int rgbcount = rgbmapcount.get(rgb);
    			if (rgbcount<10) continue;
    			distinctcolor++;
    		}
    		System.out.println("nombre de couleurs distinctes: "+distinctcolor);
     
    		// Richesse de la palette
    		double U =  (double)distinctcolor / (image.getWidth()*image.getHeight());
    		System.out.println("Richesse de la palette: "+U);
    	}
     
    }

    Perso, je trouve qu'une image de synthese a 10 fois (!) plus de couleurs qu'une photographie. Cela vient du fait que les images de synthese ont des dégradés qui font apparaitre enormément de triplets r,g,b differents.

    Tu es sûr de ta methode ? Est-ce qu'il ne faut pas juste considerer les teintes (hue) plutot que les triplets r,g,b ?

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    Merci Pseudocode pour ta réponse!
    Je ne fait que tenter de reproduire l'expérience des trois chercheurs. Ils ont utilisés + de 1000 CGI et + de 1000 photos pour leur travail, dont 200 pour chaque classe pour vérifier la validité de leur théorie.
    Je veux bien essayer avec les hues, mais la proportion CGI/photos sera t'elle inversée par rapport aux couleurs? Je n'en suis pas sûr.
    Ton code me semble adéquat, cependant j'oubliais de préciser que le comptage des pixels dans la formule (Npixels) ne concerne pas l'image dans son ensemble, mais uniquement ceux rencontrés plus de dix fois dans chacune des couleurs différentes.
    Pour être plus clair, je vais prendre un exemple:
    Prenons l'image 26.jpg


    Après application du code Java de mes amis américains, nous avons une série résumée dans un tableau Excel:

    Avec le nombre total de couleurs différentes de l'image, sa taille (ici 240000 pixels) et le nombre de couleurs différentes (2nde colonne) rencontrès 1 fois (soit 66909 pixels ici) puis 2 fois (soit 12980*2 pixels ici) etc.....jusqu'à N>10=1891 ce qui signifie donc que 1891 couleurs différentes sont rencontrées plus de dix fois.
    Donc, dans notre formule "U", "Ndifférents triplets"= 1891 dans mon exemple.
    Quand à "Npixels", il s'obtient ainsi: Total des pixels de l'image - somme des pixels pour chaque couleur différente jusqu'au rang 10 soit:
    Npixels= [240000-(66909*1)+(12980*2)+(3988*3)......]=111130 (>10 count).
    Donc pour appliquer ma formule dans mon exemple "U"= 1891/111130=0.017
    Le résultat se situe dans la moyenne des résultats des chercheurs (inter-class 0.0143 et intra-class 0.1667, distance Euclidéenne)

    Je ne sais pas si une réécriture avec les hues changera fondamentalement les données (on peut essayer!!)

  4. #4
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 084
    Points
    16 084
    Par défaut
    Citation Envoyé par onzeaout Voir le message
    Ton code me semble adéquat, cependant j'oubliais de préciser que le comptage des pixels dans la formule (Npixels) ne concerne pas l'image dans son ensemble, mais uniquement ceux rencontrés plus de dix fois dans chacune des couleurs différentes.
    Ah. C'est sur que ca marche mieux comme ca.

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
     
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
     
    import javax.imageio.ImageIO;
     
    public class ColorCounter {
     
    	public static void main(String[] args) {
     
    		// lecture de l'image
    		BufferedImage image = null; 
    		try {
    			image = ImageIO.read(new File("26.jpg"));
    		} catch (IOException e) {
    			e.printStackTrace();
    			return;
    		}
     
    		// Map (rgb)=>count
    		Map<Integer, Integer> rgbmapcount = new HashMap<Integer, Integer>();
     
    		// parcours des pixels de l'image, et creation/mise a jour de la Map
    		for(int y=0;y<image.getHeight();y++) {
    			for(int x=0;x<image.getWidth();x++) {
    				// valeur [a]rgb, codé sur un entier (4 octets)
    				int rgb = image.getRGB(x,y);
     
    				// recherche dans la map
    				if (!rgbmapcount.containsKey(rgb)) {
    					rgbmapcount.put(rgb, 1); // n'existe pas => creation
    				} else {
    					int previouscount = rgbmapcount.get(rgb);
    					rgbmapcount.put(rgb, previouscount+1); // n'existe => mise a jour
    				}
    			}
    		}
     
    		// Combien de couleurs apparaissent plus de 10 fois ?
    		int distinctcolor=0;
    		int pixelcount=0;
    		for(int rgb:rgbmapcount.keySet()) {
    			int rgbcount = rgbmapcount.get(rgb);
    			if (rgbcount<10) continue;
    			distinctcolor++;
    			pixelcount+=rgbcount;
    		}
    		System.out.println("nombre de couleurs distinctes: "+distinctcolor);
    		System.out.println("nombre de pixels: "+pixelcount);
     
    		// Richesse de la palette
    		double U =  (double)distinctcolor / pixelcount;
    		System.out.println("Richesse de la palette: "+U);
    	}
     
    }

    Effectivement, je retombe sur tes chiffres:

    nombre de couleurs distinctes: 1891
    nombre de pixels: 111130
    Richesse de la palette: 0.0170161072617655

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    Magnifique Pseudocode! Merci pour ton aide, tout fonctionne pour ce critère-là.

    Pour ce qui concerne le second critère visuel, Voilà la définition qu'en donnent les trois chercheurs canadiens:
    VARIATION SPATIALE DES COULEURS
    Nous avons utilisé l'observation que les changements de couleurs se produisent dans une moindre mesure de pixels en pixels dans les CGIs que dans les photographies.
    La raison est probablement parce que les photographies contiennent de vrais scènes et objets avec beaucoup de changements de couleurs naturelles, tandis que les CGIs n'ont pas un tel luxe en raison des limitations inhérentes au dessin avec une palette de couleur limitée.
    Afin de mesurer la variation spatiale des couleurs, pour chaque pixel des images, nous avons déterminé l'orientation du plan le mieux adapté à un voisinage 5*5 centré sur le pixel concerné. Après normalisation des triplets <R, G, B> vers nR, nG, nB, alors une variation alpha peut être obtenu par:

    là où la distance Euclidienne de chaque Pixel dans le voisinage 5*5 du pixel central se résume et est normalisée par le chiffre 25.
    j'ai écrit un petit code Ruby pour tenter de traduire cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    require 'RMagick'
    include Magick
     
    #Sanity check to make sure we have a filename
    if ARGV.length < 1
      puts "Filename needed"
      exit
    end
     
    #Read the input image and get its pixels
    #Array contains three entries for pixel, red then green then blue
    image_filename = ARGV.first
    img_orig = Image.read(image_filename).first
    pixels = img_orig.export_pixels
     
     
     
     
    r = Array.new(img_orig.rows, Array.new(img_orig.columns,Float(0)))
    g = Array.new(img_orig.rows, Array.new(img_orig.columns,Float(0)))
    b = Array.new(img_orig.rows, Array.new(img_orig.columns,Float(0)))
    avg_distance = Array.new(img_orig.rows, Array.new(img_orig.columns,Float(0)))
     
    print "start ", image_filename, " ", Time.new, "\n"
    0.upto(img_orig.rows - 1) do |i|  
      0.upto(img_orig.columns - 1) do |j|
        red_location = 3 * (i * img_orig.columns + j) #0 at (0,0), 3 at (0,1) 
        r[i][j] = pixels[red_location] 
        g[i][j] = pixels[red_location + 1] 
        b[i][j] = pixels[red_location + 2]
     
        # normalize rgb to unit vector
        vector_length = Math.sqrt(r[i][j] ** 2 + g[i][j] ** 2 + b[i][j] ** 2)
        r[i][j] = r[i][j] / vector_length
        b[i][j] = b[i][j] / vector_length
        g[i][j] = g[i][j] / vector_length
      end
    end
     
    output_filename = ARGV.first + ".txt"
    outfile = open(output_filename, "w")
     
    (2).upto((img_orig.rows) - 3) do |x0|
      (2).upto((img_orig.columns) -3) do |y0|
        (x0-2).upto(x0+2) do |x|
          (y0-2).upto(y0+2) do |y|
            avg_distance[x0][y0] = avg_distance[x0][y0] + Math.sqrt( (r[x][y] - r[x0][y0]) **2 +  (g[x][y] - g[x0][y0]) **2 + (b[x][y] - b[x0][y0]) **2 )
          end
        end
        avg_distance [x0][y0] = avg_distance[x0][y0] / 25
        outfile.print(image_filename, ",", x0, ",", y0, ",", avg_distance[x0][y0], "\n")
      end
    end
    outfile.close
    print "end ", Time.new, "\n"
    Il semble que j'ai buggé quelquepart, car ce code reproduit la dernière rangée dans toute l'image, comment puis-je corriger cela?
    Par ailleurs, je préférerais travailler sous JAVA, plus facile pour moi et plus rapide.
    Merci pour votre aide!

  6. #6
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 084
    Points
    16 084
    Par défaut
    Ton code m'a l'air bien. En meme temps, je ne maitrise pas trop ruby.

    Moi j'ai fait ca, en java:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    // retourne un triplet de couleur normé
    public static double[] getRGB(BufferedImage image, int x, int y) {
    	int argb = image.getRGB(x,y);
    	int a = (argb >>24 ) & 0xFF;
    	int r = (argb >>16 ) & 0xFF;
    	int g = (argb >> 8 ) & 0xFF;
    	int b = argb & 0xFF;
    	double norme = Math.sqrt(r*r + g*g + b*b);
    	return new double[] {r/norme, g/norme, b/norme};
    }
     
    public static double getAlpha(BufferedImage image, int x, int y) {
    	double alpha=0;
     
    	// triplet central
    	double[] rgb_0 = getRGB(image,x,y); 
     
    	// pour tout le voisinage 5x5 = [-2,-1,0,1,2]x[-2,-1,0,1,2]
    	for(int dy=-2;dy<=2;dy++) {
    		for(int dx=-2;dx<=2;dx++) {
     
    			// coordonnées du voisin
    			int y_i = y+dy;
    			int x_i = x+dx;
     
    			// gestion des bords
    			if (y_i<0) y_i=0;
    			if (y_i>=image.getHeight()) y_i=image.getHeight()-1;
    			if (x_i<0) x_i=0;
    			if (x_i>=image.getWidth()) x_i=image.getWidth()-1;
     
    			// triplet du voisin
    			double[] rgb_i = getRGB(image,x_i,y_i);
     
    			// calcul de alpha
    			double delta_r = rgb_i[0]-rgb_0[0];
    			double delta_g = rgb_i[1]-rgb_0[1];
    			double delta_b = rgb_i[2]-rgb_0[2];
    			alpha+=Math.sqrt( delta_r*delta_r + delta_g*delta_g + delta_b*delta_b );
    		}
    	}
     
    	return alpha/25;
    }

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par pseudocode Voir le message
    Ton code m'a l'air bien. En meme temps, je ne maitrise pas trop ruby.
    Merci pseudocode pour ton aide précieuse; effectivement mon code semble correct mais, il y a un problème quelquepart cependant
    M'enfin bon, c'est pas grave, je vais continuer en JAVA. (même si je ne suis pas un "foudre de guerre")
    Selon le même procédé d'évaluation des critères que pour le "nombre des couleurs uniques", les chercheurs ont trouvé pour la "variation spatiale des couleurs" une Intra-class de 0.0044 et une Inter-class de 0.0002.
    Reste plus qu'à tester quelques images pour voir si les résultats sont cohérents.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    Euh, juste une petite précision avant de clore définitivement ce sujet, à l'éxecution, la console d'Eclipse me marque:
    javax.imageio.IIOException: Can't read input file!
    at javax.imageio.ImageIO.read(Unknown Source)
    at color.colorcounter.main(colorcounter.java:18)
    Cela provient peut-être du fait que mon image est mal placée, où dois-je la mettre?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 30/03/2015, 16h29
  2. [MySQL] Extraire un nombre d'enregistrements par catégorie
    Par stelsej dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 02/11/2008, 19h19
  3. nombres de bit par pixel
    Par hassiba_45 dans le forum C++Builder
    Réponses: 4
    Dernier message: 13/04/2008, 12h51
  4. [RegEx] Extraire des nombres séparés par des caractères spéciaux
    Par GouKen dans le forum Langage
    Réponses: 2
    Dernier message: 29/01/2008, 16h49
  5. nombre de bits par pixel
    Par madjidri dans le forum C++Builder
    Réponses: 1
    Dernier message: 24/05/2007, 16h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo