GETPIXEL et WINDOWS SEVEN

Résolu
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 - 5 juin 2013 à 10:06
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 - 7 juin 2013 à 13:48
Salut à tous,

Depuis plus d'un an, j'ai une petite application que bon nombre de collégues utilisent pour comparer le niveaux de gris de deux zones d'une image ou de deux images.



L'idée est de placer un form / zone à scanner (rouge et verte) avec une opacité moindre, puis de scanner ce qu'il y a sous ces forms.
Cette appli fonction avec GETPIXEL.


    Public Function ScanZone(ByVal Zone As Windows.Forms.Form) As Integer

        Dim SizeH As Integer = Zone.Height
        Dim SizeL As Integer = Zone.Width
......		

  'Calcul de l'aire de la cible
        Aera = SizeH * SizeL

        'Ecriture du Handles
        GetDCInt = GetDC(0&)

        'Scan de l'image
        For IndexCol = 1 To SizeL
            For IndexLine = 1 To SizeH
                colorVal = GetPixel(GetDCInt, Zone.Left + IndexCol, Zone.Top + IndexLine)
                PRed = colorVal And &HFF
                PGreen = (colorVal And &HFF00) / 256
                PBlue = (colorVal And &HFF0000) / 65536
                'Rc = Color.FromArgb(PRed, PGreen, PBlue)
                NivGray = (77 * PBlue + 151 * PGreen + 28 * PRed) / 256
                Index = Index + 1
                Tab.ProgressScan2.Value = (Index * 100) / Aera
                SomPx = SomPx + NivGray
            Next
        Next
        Call ReleaseDC(0, GetDCInt)

....

End Function



Je n'ai jamais eu de soucis avec cette appli jusqu'au passage à SEVEN, depuis il faut compter 2 bonnes minutes pour scanner une zone de 50px/50px soit 2500px. Ce qui est ENORME par rapport à XP et rend l'appli laborieuse.

Auriez-vous une idée du problème.

Jimy

Pensez: Réponse acceptée
'**********************************************

19 réponses

Utilisateur anonyme
7 juin 2013 à 12:48
Bonjour,

Tu as deux conversions de Double en Integer qui sont susceptibles de poser problème un jour ou l'autre:
'NivGray = (77 * PBlue + 151 * PGreen + 28 * PRed) / 256
NivGray = CInt((77 * PBlue + 151 * PGreen + 28 * PRed) / 256)
'Et:
'ScanPicts = (SomPx / Index)
ScanPicts = CInt(SomPx / Index)


Et aussi un Return manquant (bon c'est pas bien méchant), une fonction en VB.Net fonctionne comme par exemple:
Public Function MaSomme(ByVal ValA As Integer, ByVal ValB As Integer) As Integer
      Return ValA + ValB
End Function
'Et pour l’appeler: 
 Dim MaValeur As Integer = MaSomme(4, 2)
 MessageBox.Show(MaValeur.ToString)



Cordialement


CF2i - Guadeloupe
Ingénierie Informatique
3
Utilisateur anonyme
7 juin 2013 à 13:06
Salut acive,

Pour se faire une idée du problème, il faut lire ces deux sujets associés datant d'un an déjà :
sujet 1
sujet 2
Depuis, jimy a préféré revenir aux API et l'on ne sait pas trop pourquoi.
Bonne lecture
3
Utilisateur anonyme
5 juin 2013 à 12:52
Salut,

Les API bof! On a déjà discuté de tout ceci jadis il me semble
C'est vrai que le net regorge d'exemples avec API et peu avec les outils natifs du framework mais ce n'est pas une excuse pour ne pas les utiliser
0
Utilisateur anonyme
5 juin 2013 à 13:05
Bonjour,

A première vue ton code vient déjà du VB6.
A mon avis il faudrait refaire l'appli à nouveau.
Tiens j'ai vu CE CODE ça pourrait t'inspirer...


Cordialement


CF2i - Guadeloupe
Ingénierie Informatique
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
5 juin 2013 à 13:35
Merci à vous deux!

@Banana: Oui, les APIs "BOF!", mais je cherche justement une autre solution.

@Active: Cette exemple travail sur un .JPG, ici, je travail sur l'écran, je ne vois vraiment pas comment adapter le code.

Jimy

Pensez: Réponse acceptée
'**********************************************
0
Bonjour jimy proton.

En vb.net, la classe System.Drawing.Bitmap possède une fonction GetPixel.
Cela pourrait vous faciliter l'exploitation des conseils donnés par banana32 et acive, que je salue amicalement au passage.


Étant illettré, je signe d'une croix : ×
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
5 juin 2013 à 14:01
Merci Zermelo (Pour mon Pseudo aussi! ), mais encore une fois cette classe travaille sur un fichier Bitmap, et non sur l'écran.
Je pourrais faire une capture d'une partie de l'écran, la sauvegarder temporairement en JPEG puis l'analyser avec cette classe, mais avant de tout casser, je voudrais m'assurer qu'il n'y ait pas d'autres solutions.

Jimy

Pensez: Réponse acceptée
'**********************************************
0
Vous pouvez exploiter le fait qu'un bitmap peut être mis dans un formulaire ou un PictureBox. Je ne pense pas que dans votre cas une capture d'écran soit nécessaire.

Atomiquement votre.


Étant illettré, je signe d'une croix : ×
0
Utilisateur anonyme
5 juin 2013 à 14:37
Bonjour à toi aussi Zermelo,
Vous pouvez exploiter le fait qu'un bitmap peut être mis dans un formulaire ou un PictureBox

Oui c'est ce que j'allais dire...

Par exemple:
        Dim Image1 As New Form
        Image1.BackgroundImage = Image.FromFile("c:\users\toto\desktop\test.jpg")
        Image1.BackgroundImageLayout = ImageLayout.Center
        Image1.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Image1.Show()
        Image1.BringToFront()


Ou encore une autre solution, utiliser un panel et y charger une image...


Cordialement


CF2i - Guadeloupe
Ingénierie Informatique
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
5 juin 2013 à 15:35
Merci à tous, mais je craint de ne bien m'expliquer.

Mon application propose aussi l'analyse de fichiers images (onglet "Sur IMAGES"), et cela fonctionne tres bien.

Mais pour la fonction "Sur ZONES" qui me pose problème, je n'ai pas de fichier image, bitmap, jpeg ou autre à traiter.
Je viens scanner les pixels SOUS les deux mires (verte et rouge)d'où l'utilisation du

GetDCInt = GetDC(0&)
...
colorVal = GetPixel(GetDCInt, Zone.Left + IndexCol, Zone.Top + IndexLine)



dans le GETPIXEL, pour scanner le bureau en quelques sortes. Et c'est ici que le bas blesse.

Jimy

Pensez: Réponse acceptée
'**********************************************
0
Vu! Alors, effectivement, dans votre cas, l'utilisation normale de vb.net conduit à faire une capture d'écran partielle.
J'aurais dû faire attention à votre GetDC(0&).

Cordialement.


Étant illettré, je signe d'une croix : ×
0
Utilisateur anonyme
5 juin 2013 à 19:17
Il y a un exemple trouvé ici qui permet d'analyser les composantes de la couleur pointée par le curseur. En élargissant la zone et en utilisant une boucle pour parcourir toute cette zone, tu devrais pouvoir t'en sortir. Et sans passer par ces API.
Voici le code :
Public Class Form1

    Private WithEvents timer1 As New Windows.Forms.Timer

    Private Sub Form1_Load(ByVal sender As System.Object, _
                    ByVal e As System.EventArgs) Handles MyBase.Load

        timer1.Interval = 10
        timer1.Start()

    End Sub


    Private Sub Timer1_Tick(ByVal sender As System.Object, _
                    ByVal e As System.EventArgs) Handles timer1.Tick

        Using bmp As New Bitmap(1, 1)
            Using g As Graphics = Graphics.FromImage(bmp)
                g.CopyFromScreen(Windows.Forms.Cursor.Position, _
                                          New Point(0, 0), New Size(1, 1))
            End Using
            Me.Text = bmp.GetPixel(0, 0).ToString
            Me.Invalidate()
        End Using
       
    End Sub

End Class
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
5 juin 2013 à 20:03
Bonjour,

1) Je ne vois absolument pas ce que le fait de passer de XP à Win 7 viendrait changer quoi que ce soit à la vitesse d'exécution d'une boucle !
2) Je ne vois pas non plus en quoi un langage de développement plutôt qu'un autre serait d'une exécution plus rapide de celle de l'utilisation des fonctions de l'Api de Windows (fonctions qui, au demeurant, sont de toutes manières utilisées par les langages de développement Microsoft "évolués")
3) d'une machine à l'autre (et pour une même "zone", ce ne sera pas l'OS, qui sera responsable d'une différence de temps d'exécution, mais d'autres facteurs, parmi lesquels :
- le processeur (ses performances)
- la carte graphique (ses performances)
- la mémoire vive restant disponible à un instant t
4) en mon point 3, j'ai_ bien précisé "pour une même zone". Car il est claire que le temps de traitement est proportionnel à celui du nombre de pixels à traiter dans la surface de cette zone
5) ces remarques se veulent limitées au seul exemple ici donné et aux seules constatations dénoncées
6) je regrette de constater (mais cette remarque n'est qu'accessoire, au passage) que l'on force à relire en boucle une valeur, comme ici :
colorVal = GetPixel(GetDCInt, Zone.Left + IndexCol, Zone.Top + IndexLine)
Le processeur préfèrerait deux variables toto zone.left et titi Zone.top (et donc déterminées une seule fois)
7) Il serait nettement plus adroit de ne pas travailler sur tout l'écran (GetDC(0&)) mais sur la seule surface qui intéresse (un createdc serait le bienvenu)
Voilà l'ensemble de mes réflexions. Je vais suivre la suite avec intérêt, mais en tant que simple spectateur.

________________________
Réponse exacte ? => "REPONSE ACCEPTEE" facilitera les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement répéter son contenu. Je n'interviendrai que si nécessité de la compléter.
0
Utilisateur anonyme
5 juin 2013 à 20:44
J'ai oublié de saluer les collègues tout à l'heure.

C'est pour faciliter l'écriture du code qu'on utilise les fonctions natives du framework. Tu ne constateras aucune amélioration de la vitesse d'exécution.

Je suis de l'avis d'ucfoutu, le code est à revoir.
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
5 juin 2013 à 21:50
@ UcFoutu, merci de ton avis.


1) Je ne vois absolument pas ce que le fait de passer de XP à Win 7 viendrait changer quoi que ce soit à la vitesse d'exécution d'une boucle !


Moi non plus mais c'est un fait, mon client vient de migrer en seven, et l'application montre cette même faiblesse sur toutes.

3) d'une machine à l'autre (et pour une même "zone", ce ne sera pas l'OS, qui sera responsable d'une différence de temps d'exécution, mais d'autres facteurs, parmi lesquels :
- le processeur (ses performances)
- la carte graphique (ses performances)
- la mémoire vive restant disponible à un instant t S


Sur ce point, je te suit, mais seven étant plus gourmand, n'y a-t-il pas cause à effet?

6) je regrette de constater (mais cette remarque n'est qu'accessoire, au passage) que l'on force à relire en boucle une valeur, comme ici :
colorVal = GetPixel(GetDCInt, Zone.Left + IndexCol, Zone.Top + IndexLine)
Le processeur préfèrerait deux variables toto zone.left et titi Zone.top (et donc déterminées une seule fois)


Merci pour cette remarque pertinente.

7) Il serait nettement plus adroit de ne pas travailler sur tout l'écran (GetDC(0&)) mais sur la seule surface qui intéresse (un createdc serait le bienvenu)


Je ne vois pas encore comment, mais je vais y travailler.






Jimy

Pensez: Réponse acceptée
'**********************************************
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
6 juin 2013 à 01:16
Je ne vois pas encore comment, mais je vais y travailler.

ouvre ^par exemple (entre autres possibilités) cette page :
Tapez le texte de l'url ici.
regarde le code VB6 de l'exemple Create Picture
Sa transposition en VB.Net devrait être un jeu d'enfant ===> les seules modifs à y apporter pour VB.Net sont
- les typages (à modifier)
- la toute dernière ligne (Set Me.Picture = hDCToPicture(GetDC(0), 0, 0, Screen.Width / Screen.TwipsPerPixelX, Screen.Height / Screen.TwipsPerPixelY))
pour ce qui est de l'attribution d'une image à un Form.

Lorsque tu auras passé cette étape ===>>
- envoies vers une picturebox plutôt que sur le Form (Me)
- fais un essai avec par exemple ces paramètres : = hDCToPicture(GetDC(0), 50, 80, 100, 90)
l'image de la picturebox sera tout simplement celle d'une zone de ton écran, de largeur 100 et de hauteur 90, dont le coin supérieur gauche sera aux coordonnées 50,80 de ton écran.
Là s'arrête mon intervention (je ne suis pas VB.Nettiste).
Si tu décides d'utiliser les fonctions de l'Api de Windows, tu as là tout ce qu'il te faut pour ne traiter qu'une portion et non tout ton écran.
Bonne chance.
________________________
Réponse exacte ? => "REPONSE ACCEPTEE" facilitera les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement répéter son contenu. Je n'interviendrai que si nécessité de la compléter.
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
6 juin 2013 à 16:42
Bonjour à tous,

J'ai soldé mon problème, avec cette nouvelle fonction qui n'utilise pas GETPIXEL, le temps de traitement d'une image de 1024x768 prend en moyenne 1.5s, donc très satisfait.

J'ai donc suivi certains de vos conseils, en l'occurence de coder en NET et de ne pas utiliser les API.

@Ucfoutu: Merci pour ton dernier message, mais je ne l'ai consulté qu'après avoir trouver cette solution. Je vais m'y pencher quand même.

    
' FONCTION PERMETTANT DE CAPTURER UNE IMAGE DU BUREAU SOUS UN FORMULAIRE *************************************************************
    Public Sub FormShoot(ByVal mZone As Windows.Forms.Form, ByVal Fname As String)
        Try
            Dim bmpSS As Bitmap
            Dim gfxSS As Graphics
            Dim mFileName As String = Application.StartupPath & "\TEMP" & Fname & ".jpg"

            'Si le fichier temporaire existe -> Delete
            If System.IO.File.Exists(mFileName) Then
                System.IO.File.Delete(mFileName)
            End If

            'mZone, rectangle à capturer
            bmpSS = New Bitmap(mZone.Width, mZone.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
            gfxSS = Graphics.FromImage(bmpSS)
            gfxSS.CopyFromScreen(mZone.Location, New Point(0, 0), mZone.Size, CopyPixelOperation.SourceCopy)

            'mFileName, pour le nom du fichier de destination
            bmpSS.Save(mFileName, System.Drawing.Imaging.ImageFormat.Jpeg)

            gfxSS.Dispose()
            bmpSS.Dispose()

        Catch ex As Exception
            WriteLog("Error: Function - " & System.Reflection.MethodBase.GetCurrentMethod().Name & " - " & Date.Now & " - " & ex.Message)
        End Try
    End Sub

' FONCTION PERMETTANT DE SCANNER UNE IMAGE PIXEL/PIXEL *********************************************************************************
'Declaration
    Public Function GetPixel( _
     ByVal x As Integer, _
     ByVal y As Integer _
    ) As Color

    End Function

    Public Function ScanPicts(ByVal DirPict As String, ByVal PctDest As PictureBox) As Integer


        Dim Aera As Long = 0
        Dim Index As Long = 0
        Dim NivGray As Integer = 0
        Dim PRed As Integer = 0
        Dim PGreen As Integer = 0
        Dim PBlue As Integer = 0
        Dim SomPx As Long = 0
        Dim MyColor As Color

        Try

            'Ouvrir le fichier et afficher l'apercu
            Using reader As New IO.FileStream(DirPict, IO.FileMode.Open)
                PctDest.BackgroundImage = Image.FromStream(reader)
            End Using

            Dim myBitmap As New Bitmap(DirPict)

            Dim Width As Int32 = myBitmap.Width
            Dim Height As Int32 = myBitmap.Height
            Aera = Width * Height

            For y As Int32 = 0 To Height - 1
                For x As Int32 = 0 To Width - 1
                    MyColor = myBitmap.GetPixel(x, y)
                    PRed = MyColor.R
                    PGreen = MyColor.G
                    PBlue = MyColor.B
                    NivGray = (77 * PBlue + 151 * PGreen + 28 * PRed) / 256
                    Index = Index + 1
                    Tab.ProgressScan2.Value = (Index * 100) / Aera
                    SomPx = SomPx + NivGray
                Next
            Next
            myBitmap.Dispose()
            myBitmap = Nothing

            ScanPicts = (SomPx / Index)

        Catch ex As Exception
            WriteLog("Error: Function - " & System.Reflection.MethodBase.GetCurrentMethod().Name & " - " & Date.Now & " - " & ex.Message)
            ScanPicts = 0
        End Try
    End Function



Vos remarques et propositions d'améliorations sont toujours les bienvenues.

Encore merci, ainsi qu'à ceux qui ont eu la générosité de partager leur code dont je me suis inspiré.

Jimy

Pensez: Réponse acceptée
'**********************************************
0
Utilisateur anonyme
7 juin 2013 à 13:45
Salut Banana32,

Ah ok merci,
C'est donc une histoire ancienne alors..


Cordialement


CF2i - Guadeloupe
Ingénierie Informatique
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
7 juin 2013 à 13:48
Depuis, jimy a préféré revenir aux API et l'on ne sait pas trop pourquoi.


Salut Banana, non, je n'ai pas préféré re"venir aux API. Mon appli à deux fonctions principales:
1) Scanner une partie du bureau. Celle-ci a toulours utilisé l'API GETPIXEL
2) Scanner une image entière, et là, j'avais suivi tes conseils des postes précédents en codant avec les fonctions du FrameWork.

Pour la première fonction, une projet pro en poussant un autre, je m'en étais satisfait.
Aujourd'hui, tout vient du framework et c'est très bien.

Encore merci à tous
Jimy

Pensez: Réponse acceptée
'**********************************************
0
Rejoignez-nous