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

C++ Discussion :

GetPixel est très lente


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 92
    Points : 96
    Points
    96
    Par défaut GetPixel est très lente
    Bonjour,

    J'ai besoin de vos lumières pour optimiser la vitesse d'exécution d'un programme.

    - But du programme :

    Mon programme est un OCR, il scanne certains pixels de l'écran par exemple les pixels en (100;100), (103;98) et (105;101) avec ça je suis capable de savoir si il s'agit d'un caractère 1 à 9 qui est inscrit dans cette partie d'écran. Ces caractères ne faisant pas partis de mon programme lui-même mais d'un programme écrit en java tournant dans une page html.
    Le but c'est de récupérer les données d'un autre logiciel. Et ça marche. Sauf que...

    Il est très lent sur mon nouveau PC (résolution native 3200x1080) alors qu'avec mon ancien PC tous était immédiat (1600x900)... En réduisant la résolution ça ne résout même pas mon problème!
    J'ai déterminé que c'était la fonction GetPixel() qui était très lente en Ultra Haute Définition. Si je la met en remarques // tout le reste redevient fluide...

    Bon avant d'utilise GetPixel() il faut appeler une fonction telle que GetDC(NULL) qui fournit un handle sur un Device Context, un Device context contient entre autre un bloc de bits avec les couleurs de chaque pixels, et ça c'est énorme en 3200x1080.
    Ce bloc de bits est forcément réactualisé lors de l'appel de GetPixel, d'où sa lenteur évidente.

    Le soucis c'est que mon Device Context est appliqué sur la totalité de l'écran donc 3200x1080 alors que je sais exactement où pointer sur les bons caractères. Un Device Context sur un bloc de pixels de 100x200 me suffirait amplement, sauf que je ne sais pas comment isolé seulement cette zone plutôt que l'écran en entier.

    Il y a bien un moyen d'accéder à une zone restreinte mais il faut connaitre le handle de la fenêtre cible, et ça je ne peux pas. C'est un programme java affiché par une page html.
    Le mieux serait de délimiter une zone sans aucun rapport avec une fenêtre en particulier, mais je sèche.

    Avez vous de conseils ou suggestions ?

    Merci

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 196
    Points : 17 165
    Points
    17 165
    Par défaut
    Bonjour,
    Si tu ne dis pas de quelle bibliothèque tu tire ton GetPixel(), ca va être délicat de t'aider.

    Cependant, c'est typiquement le cas où je me demande si l'OCR est le bon choix.
    La donnée transite forcément puisque l'applet java l'affiche. Il suffit d'écouter au bon endroit.
    L'écran n'est pas le meilleur.

    Il y a plusieurs autres pistes explorables:
    • englober l'applet dans une autre, qui enregistrerait ce que tu veux (sorte de keylogger)
    • sniffer le réseau
    • sniffer la RAM
    • utiliser un jre modifié pour enregistrer les chaines de caractères affichées.
    • utiliser un meilleur service web.
    • éventuellement, faire de l'OCR sur une image réduite (telle qu'obtenue avec Alt+PrintScreen)


    Mais vraiment, l'OCR n'est pas une bonne solution pour obtenir une information fournie par un programme.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 92
    Points : 96
    Points
    96
    Par défaut
    Oui je me suis tourné vers un OCR par défaut d'autres solutions.

    Le Keylogger aurait été la meilleur solution forcément, j'en ai déjà écrit 2 ou 3 mais qui écoutaient les messages provenant d'une application Win32 pas d'une applet Java, ça j'ignore vraiment comment faire.

    Par contre j'ai pensé à une solution pour mon OCR. Je pense savoir comment créer une zoneDC quelconque indépendante de dimensions voulues et de positions voulues.

    J'ai créé un programme tiers qui n'est autre qu'un rectangle vide (Background transparent) avec une bordure de 1 pixel.
    Mon programme principal va lancer ce second programme avec CreateProcess() ou ShellExecuteExA() puis retrouver son handle avec FindWindow et son ClassName, je pourai ainsi le manipuler et le déplacer où bon me chante mais surtout je pourrai créer un Device Context à partir de cette petite zone et non à partir de l'écran entier en utilisant : GetDC(hProgZoneDC) au lieu de GetDC(0); La fenêtre étant transparente, les pixels sous cette fenêtre resteront ceux du vrai programme cible situé sous-elle.

    Voilà l'idée, je suis en train...
    Je vous dirai si ça fonctionne....

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Si c'est le GetPixel() Win32, la bonne solution c'est de copier les pixels que tu veux en gros vers un bitmap spécial pour lequel tu as un accès direct au buffer des pixels: Un tel bitmap s'obtient avec la fonction CreateDIBSection() (qui permet également de spécifier le format dudit bitmap).

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 196
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 196
    Points : 17 165
    Points
    17 165
    Par défaut
    Dans le cadre de Win32, il me semble avoir lu que GetPixel sur le contexte de l'écran attends que l'image en cours de calcul soit terminée avant d'y accéder.
    Sur une malchance, il attend alors une frame à chaque pas de la boucle de lecture.
    soit une seconde par 60 pixels...

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 92
    Points : 96
    Points
    96
    Par défaut
    Ahhhh !!!

    Mon idée ne fonctionne pas !
    Ma fenêtre transparente est en fait crée de la façon suivante, une image Bitmap avec une couleur 0xFF0000 considérée comme un mask pour lequel ces pixels sont affichés en transparent.

    Et donc, bien que ma zoneDC soit transparente (à l'écran), en fait son Device Context ne l'est pas lui ! il reste en 0xFF0000 ! et forcément mon programme principal ne détecte pas les caractères souhaités car la fenêtre transparente agit en fait comme une fenêtre opaque.



    Bon je change de solution, je vais étudier la piste CreateDIBSection()

    Merci. Je continuerai ce thread quand j'aurai avancé dans mes tests.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 92
    Points : 96
    Points
    96
    Par défaut
    Je reviens vers vous avec un code qui me parait prometteur, il permet de faire une copie (imge Bitmap) d'un zone d'écran. Donc à un moment ou un autre les pixels sont traités quelque part.
    http://www.experts-exchange.com/Prog...-an-image.html

    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
    BOOL Capture(HDC hDC, LPRECT lpRect, LPCWSTR lpszFile)
    {
    	HDC hMemDC;
    	HBITMAP hBitmap;
    	HGDIOBJ hOld;
    	BITMAPINFO bmi;
    	LPBYTE pBits;
    	DWORD nImageSize;
    	DWORD nWritten;
    	BITMAPFILEHEADER header;
    	HANDLE hFile;
     
    	ZeroMemory((LPVOID)&bmi, sizeof(BITMAPINFO));
    	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	bmi.bmiHeader.biWidth = lpRect->right - lpRect->left;
    	bmi.bmiHeader.biHeight = lpRect->bottom - lpRect->top;
    	bmi.bmiHeader.biPlanes = 1;
    	bmi.bmiHeader.biBitCount = 24;
    	bmi.bmiHeader.biCompression = BI_RGB;
     
    	pBits = NULL;
     
    	hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);
     
    	hMemDC = CreateCompatibleDC(hDC);
    	hOld = SelectObject(hMemDC, hBitmap);
    	BitBlt(hMemDC, 0, 0, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, hDC, lpRect->left, lpRect->top, SRCCOPY);
    	SelectObject(hMemDC, hOld);
    	DeleteDC(hMemDC);
     
    	nImageSize = ((((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) + 31) & ~31) >> 3) * bmi.bmiHeader.biHeight;
     
    	ZeroMemory((LPVOID)&header, sizeof(BITMAPFILEHEADER));
    	header.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); 
    	header.bfSize = nImageSize + sizeof(BITMAPFILEHEADER) +	sizeof(BITMAPINFOHEADER);
    	header.bfType = 0x4D42;
     
    	hFile = CreateFile(lpszFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);   
     
    	if (hFile != INVALID_HANDLE_VALUE) {
    		WriteFile(hFile, (LPVOID)&header, sizeof(BITMAPFILEHEADER), &nWritten, NULL);
    		WriteFile(hFile, (LPVOID)&bmi, sizeof(BITMAPINFOHEADER), &nWritten, NULL);
    		WriteFile(hFile, (LPVOID)pBits, nImageSize, &nWritten, NULL);
    		CloseHandle(hFile);
    	}
     
    	return TRUE;
    }

    Je pense que c'est le membre pBits de la fonction suivante qui pointe sur le bloc de pixels (un pointeur de pointeur si j'ai bien compris)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    hBitmap = CreateDIBSection(hDC, &bmi, 	DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);
    Cependant je n'arrive toujours pas à en sortir une couleur. Est-ce que quelqu'un pourrait m'aiguiller pour pointer correctement sur cet endroit ?
    Je vous remercie.

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Ça dépend ce qui est mis dans la BITMAPINFO. La configuration actuelle est 24bpp, ce qui est n'est pas pratique pour lire les pixels individuellement. Je te conseille de monter biBitCount à 32, puis tu pourras simplement caster pBits en DWORD* (voire en RGBQUAD*)...

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 92
    Points : 96
    Points
    96
    Par défaut
    Bon j'ai avancé mais ce n'est pas plus rapide.
    Voici mon code :

    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
    COLORREF GetPixel2(HDC hDC, int px, int py) {
    	BITMAPINFO bmi = { 0 };
     
    	LPBYTE pBits = NULL;
    	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);                // taille de la structure BITMAPINFOHEADER
    	bmi.bmiHeader.biWidth = 1;                                      // Largeur de l'Image en pixels (1 seul pixel)
    	bmi.bmiHeader.biHeight = 1;                                     // Hauteur de l'image en pixels
    	bmi.bmiHeader.biPlanes = 1;                                     // Nombre de calques (toujours 1 pour les Bitmaps)
    	bmi.bmiHeader.biBitCount = 32;                                  // Image en 32 Bits
    	bmi.bmiHeader.biCompression = BI_RGB;                           // BI_RGB (Aucune compression d'image)
    	bmi.bmiHeader.biSizeImage = 0;                                  // Taille en Bytes de l'image, doit être mis à 0 pour des bitmaps en BI_RGB.
     
    	HBITMAP hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (LPVOID*)&pBits, NULL, 0);    // Création d'un fichier mappé (vide) en mémoire DIB (device-independent bitmap)
                                                                                                    // une zone mémoire où seront placés les données constituants l'image et ses caractéristiques (entête)
    	HDC hMemDC = CreateCompatibleDC(hDC);                           // The CreateCompatibleDC function creates a memory device context (DC) compatible with the specified device.
     
     
    	HGDIOBJ hOld = SelectObject(hMemDC, hBitmap);                   // Seléctionne un objet, un stylo, un pinceau etc... ici en l'occurence on sélectionne la zone mémoire (vide) où sera recopiée l'image bitmap.
    	BitBlt(hMemDC, 0, 0, 1, 1, hDC, px, py, SRCCOPY);               // copie du bitmap (affiché à l'écran, en fait 1 seul pixel aux coordonnées px,py) dans la zone mémoire DIB.
    	SelectObject(hMemDC, hOld);                                     // Déselectionne la zone mémoire.
    	DeleteDC(hMemDC);                                               // Destruction du Handle de cette zone mémoire.
     
                                                                        // pBits est un pointeur sur le début des couleurs Resrvé+RVB des pixels placés les uns à la suites des autres.
        DWORD *pPixel;                                                  // pPixel = pointeur sur la couleur du pixel aux coordonnées (px; py)
        pPixel = (DWORD*) (pBits);                                      //
        int plexiP;                                                     //
        plexiP = (*pPixel&0xFF)<<16 | (*pPixel&0xFF00) | (*pPixel&0xFF0000)>>16 ;   // inversion de l'ordre des octets, ex : 45EF19 devient 19EF45
     
        //wsprintf (buffer, formatDeci, pixelID); MessageBoxA (0, buffer, buffer, 0);
        return (COLORREF) plexiP;
    }

    Cette fonction remplace GetPixel() sans l'utiliser mais elle est tout aussi lente que l'originale. Je suppose que le fait d'utiliser GetHDC(0) avec 0 comme argument faisant que ça s'applique à la totalité de l'écran fait que ça ne peut pas être rapide. Je pense qu'il faudrait utiliser GetHDC(HandleDeLaFenêtreCible) pour limiter grandement la zone de pixels à étudier.


    Par contre pointer sur les éléments d'une application Java me paraît être un défit.

    Je crois me souvenir d'avoir déjà testé des hooks pour afficher les valeurs des handles des ChildControls d'applications Win32 et d'applications Java, et que pour les application Java je ne parvenais pas à retrouver les handles tant convoités.
    Cette voie me paraît compliquée.... Avez vous des suggestions, pensez-vous que cette voie est viable quand même ? ou dois-je me tourner vers une toute autre solution.

    Je suis dans l'impasse pour l'instant. Merci.

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Tu chopes toute l'image à chaque appel pour UN pixel

    Tu dois séparer ta fonction en deux: Une qui récupère l'image dans un buffer une fois pour toutes, et l'autre, appelée dans ta boucle, qui lit un pixel du buffer.

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 92
    Points : 96
    Points
    96
    Par défaut
    Je sais bien, mais justement je ne peux pas faire ça, car l'image n'est pas une image fixe.

    Le but c'est identifier des nombres qui évoluent rapidement dans le temps. En Fait ce sont les chiffres d'un système de trading que je veux récupérer, c'est un tableau de prix qui évolue de seconde en seconde, voir plus vite que ça à certains moments. Je suis donc obligé en permanence de raffraichir l'image pour en extraire les nouvelles couleurs des pixels à étudier.

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 588
    Points
    41 588
    Par défaut
    Rafraichir l'image oui, mais pas entre chaque pixel...

    Tu rafraichis l'image, PUIS tu lis tous ses pixels (mais plus vite qu'avec GetPixel, cette fois), tu les traites, puis tu rafraichis l'image, lis ses pixels, les traite... etc.

Discussions similaires

  1. mon programme est très lent
    Par kawther dans le forum Images
    Réponses: 4
    Dernier message: 08/04/2010, 13h28
  2. [Hijackthis] Internet est très lent
    Par adn56 dans le forum Sécurité
    Réponses: 0
    Dernier message: 19/10/2008, 19h37
  3. Réponses: 12
    Dernier message: 24/07/2007, 12h09
  4. [WS2003] Mon serveur est très lent
    Par beegees dans le forum Windows Serveur
    Réponses: 13
    Dernier message: 29/03/2007, 14h53

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