Récupérer les coordonnées d'une couleur a l'ecran

Résolu
Dudul86 Messages postés 2 Date d'inscription dimanche 14 février 2010 Statut Membre Dernière intervention 15 février 2010 - 14 févr. 2010 à 18:38
Dudul86 Messages postés 2 Date d'inscription dimanche 14 février 2010 Statut Membre Dernière intervention 15 février 2010 - 15 févr. 2010 à 18:27
Bonjour à tous.
J'ai comme idée de faire un programme qui détecte la présence d'une couleur à l'écran (par exemple du vert) et renvoi les coordonnées du 1er pixel de cette couleur qu'il a rencontré. Je n'ai pas de langage particulier en vue, j'aime bien le java et le c++ mais d'autres propositions sont les bienvenues (du moment que c'est une application locale et pas web ^^).

J'ai déjà pensé a une solution simple: prendre tout les pixel un par un grâce a deux boucles, et comparer leur couleur avec la couleur désirée. J'ai deux programmes qui marchent, un en C++ et un en java:

Java :

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Robot;
import java.lang.Object;

public class Main {

    
    public static void main(String[] args) throws AWTException {
        // TODO code application logic here
       Robot rob1 = new Robot();
       Color couleur = null;
       int i=0, j=0;
       while (i < 100 /*&& (couleur == null || couleur.getGreen() != 254)*/)
       {
           j = 0;
           while (j < 100 /*&& (couleur == null || couleur.getGreen() != 254)*/)
           {
               couleur = rob1.getPixelColor(i,j);
               System.out.println(couleur+" x "+i+"  y "+j);
               j++;
           }
           i++;
       }
       System.out.println(couleur);
       System.out.println(i+" "+j);
    }
}



C++:

#include <stdio.h>
#include <stdafx.h>
#include <stdlib.h>
#include <windows.h>
#include <richedit.h>

int main(int argc, char *argv[])
{long R,G,B;
 HDC dc = GetDC(NULL);
COLORREF pix;
int x = 200;
int y = 100;
bool stop = false;
while (x < 1480 && stop != true)
{
y = 100;
while (y < 1000 && stop != true)
{
pix = GetPixel(dc, x, y);
R = GetRValue(pix);
G = GetGValue(pix);
B = GetBValue(pix);
if(R 255 && G 255 && B == 255)
{
stop = true;
}
y++;
printf("ROUGE :%ld\n",R);
printf("VERT :%ld\n",G);
printf("BLEU :%ld\n\n",B);
printf("X :%d\n",x);
printf("Y :%d\n",y);
}
x++;
}
system("pause");
return (0);  
} 



Le principal soucis de ces deux codes, c'est qu'ils sont très lents, je m'explique, dans l'idéal j'aimerai pouvoir scanner tout l'écran en moins de 10 secondes, voir quasi instantanément. La ça prend plusieurs minutes, d'autant que je suis en 1680*1100. Quelqu'un aurait une idée, par exemple si il existe une manière de trouver directement une couleur a l'écran de manière instantanée, ou s'il y a une manière de récupérer la couleur de chaque pixel beaucoup plus rapidement...


J'espère que mon problème est clairement expliqué et que mon code n'est pas trop brouillon ^^ Merci d'avance.

3 réponses

cs_jojolemariole Messages postés 519 Date d'inscription mercredi 21 mars 2007 Statut Membre Dernière intervention 19 décembre 2016 25
15 févr. 2010 à 10:19
Re, voilà j'ai fait un petit code rapide.

J'ai intégré la notion de marge d'erreur (on ne cherche pas la couleur exacte mais on tolère une petite différence), de plus pour booster la vitesse de traitement on peut tester seulement une partie des pixel en quadrillant. Le traitement se fait non pas sur l'écran mais sur une capture faite en début d'algo. Si tu cherches un objet qui fait 4 x 4 pixels de large tu peux mettre le paramètre step à 4, tu le louperas pas et de plus tes performances seront considérablement améliorées (16x moins de pixels à tester).

Fais-moi un retour, c'est le genre de trucs qui m'intéressent.



package bot;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Set;


/**
 * @author GUEHENNEUX
 */
public class ColorFinder {

    private Robot robot;

    private Toolkit toolkit;

    /**
     * @throws AWTException
     */
    public ColorFinder() throws AWTException {

        robot = new Robot();
        toolkit = Toolkit.getDefaultToolkit();

    }

    /**
     * @param color
     * @param margin
     * @param step
     * @return
     */
    public Set getPixels(Color color, double margin, int step) {

        Dimension screenSize = toolkit.getScreenSize();

        int screenWidth = screenSize.width;
        int screenHeight = screenSize.height;

        /*
         * on fait une capture d'ecran afin d'optimiser le traitement
         */

        Rectangle zoneCapture = new Rectangle(screenSize);
        BufferedImage capture = robot.createScreenCapture(zoneCapture);

        int x, y;

        Color pixelColor;

        Set pixels = new HashSet();

        double colorDistance;

        for (x = 0; x < screenWidth; x += step) {

            for (y = 0; y < screenHeight; y += step) {

                pixelColor = new Color(capture.getRGB(x, y));

                /*
                 * on regarde si la couleur du pixel est proche de celle
                 * attendue
                 */

                colorDistance = getDistance(color, pixelColor);

                if (colorDistance <= margin) {
                    pixels.add(new Point(x, y));
                }

            }

        }

        return pixels;

    }

    /**
     * @param color1
     * @param color2
     * @return the distance between the two colors
     */
    public static double getDistance(Color color1, Color color2) {

        int r1 = color1.getRed();
        int r2 = color2.getRed();
        int g1 = color1.getGreen();
        int g2 = color1.getGreen();
        int b1 = color1.getBlue();
        int b2 = color2.getBlue();

        int rDistance = Math.abs(r1 - r2);
        int gDistance = Math.abs(g1 - g2);
        int bDistance = Math.abs(b1 - b2);

        double rDistanceCube = Math.pow(rDistance, 3);
        double gDistanceCube = Math.pow(gDistance, 3);
        double bDistanceCube = Math.pow(bDistance, 3);

        double distance = Math.pow(rDistanceCube + gDistanceCube + bDistanceCube, 1.0 / 3);

        return distance;

    }

    /**
     * methode de test
     * 
     * @param args
     * @throws AWTException
     */
    public static void main(String[] args) throws AWTException {

        ColorFinder colorFinder = new ColorFinder();

        System.out.println("Il y a " + colorFinder.getPixels(Color.BLUE, 2, 2).size()
            + " pixel(s) dont la couleur est proche de celle demandée.");

    }

}


Jonathan
2
cs_jojolemariole Messages postés 519 Date d'inscription mercredi 21 mars 2007 Statut Membre Dernière intervention 19 décembre 2016 25
15 févr. 2010 à 09:46
Salut,

Ça sent le cheat, graçon!
D'ores et déjà, ce qui plombe tes chronos sont les sorties sur la console (System.out.print...). Refais un test sans pour voir, je regarde de mon côté.
0
Dudul86 Messages postés 2 Date d'inscription dimanche 14 février 2010 Statut Membre Dernière intervention 15 février 2010
15 févr. 2010 à 18:27
Merci de ta réponse, en effet ton algorithme est bien plus rapide... plus que les affichages, je pense que ce qui me retardait principalement c'était le fait de traiter l'immage telle qu'elle apparaissait a l'écran au lieu de faire un screenshot et de le traiter ensuite. Je vais adapter ta solution a mon idée et je posterai ici une solution plus détaillée ^^.
0
Rejoignez-nous