Résultat GetPixel sur PictureBox instable

Résolu
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 - 8 juin 2012 à 15:34
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 - 12 juin 2012 à 13:54
Bonjour à tous,

Ma petit appli propose de scanner chaque pixel d'une image d'un PictureBox et d'en faire la moyenne, ce que renvoie la fonction.
Ce PictureBox est dans un Formulaire autre que le Main.

Le souci, est que, selon la position de ce Form sur l'écran, le résultat de ma fonction (ci-dessous) varie considérablement.

Je ne suis pas sur de mon GetDC....

Mais peut-être pourriez-vous m'aider?

    Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Integer, ByVal X As Integer, ByVal Y As Integer) As Integer
    Private Declare Function GetDC Lib "user32" (ByVal hWnd As IntPtr) As Integer
    Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Integer, ByVal hdc As Integer) As Integer


----------------------------------------------------------

    Public Function ScanPict(ByVal Pict As PictureBox, ByVal SizePH As Long, ByVal SizePL As Long) As Integer

        Dim Aera As Long = 0
        Aera = SizePH * SizePL

        Dim Index As Long = 0
        Dim IndexCol As Long = 0
        Dim IndexLine As Long = 0
        Dim NivGray As Integer = 0
        Dim colorVal As Integer = 0
        Dim PRed As Integer = 0
        Dim PGreen As Integer = 0
        Dim PBlue As Integer = 0
        Dim GetDCInt As Integer = 0
        Dim SomPx As Long = 0

  
        GetDCInt = GetDC(Pict.Handle)  <-- C'est la que je doute!!!

        'Scan de l'image
        For IndexCol = 1 To SizePL
            For IndexLine = 1 To SizePH
                colorVal = GetPixel(GetDCInt, IndexCol, 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)
        Tab.LabNbPixel2.Visible = True
        Tab.LabNbPixel2.Text = "Opération terminée: " & Index.ToString & " pixels scannés par image."
        ScanPict = (SomPx / Index)

    End Function




Jimy

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

31 réponses

Utilisateur anonyme
8 juin 2012 à 22:27
Bonsoir jimy,

Je te rappelle qu'il existe des outils inclus dans le framework pour effectuer ce genre de tâche
Nous en avons discuté ici. Peut-être n'as-tu pas eu de bons résultats ?
3
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 220
8 juin 2012 à 16:10
Bonjour,
Ceci, déjà, est surprenant
colorVal = GetPixel(GetDCInt, IndexCol, IndexLine)

si, comme tout le donne à penser, indexcol est l'ordonnée et indexline est l'abscisse !
________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
8 juin 2012 à 16:23
Je ne comprends pas!

X abcisse Width = colonne
Y = Ordonnée= Height = ligne

Non?


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 220
8 juin 2012 à 16:26
aucun problème, mais à la seule condition (on ne le sait pas, mais toi, oui)à que indexcol soit bien l'abscisse


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
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
8 juin 2012 à 16:32
Oui, c'est bien le cas.

Mais ce que je ne comprends pas, c'est que si par exemple, je fais disparaitre une partie de mon form portant le picturebox à scanner dans
un coin de l'écran en le déplaçant, le résultat diffère, getpixel ne fonctionne-t-il que sur ce qui est visible à l'écran??

Je voudrais pouvoir scanner le contenu d'un picturebox, même si il n'est visible qu'en partie à l'écran...


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 220
8 juin 2012 à 16:37
Il te faut bien comprendre une chose :
autant le handle hwnd d'un contrôle ou d'un objet est bien immuable pendant toute sa durée de "vie", autant le hdc (device context handle) d'un objet est systématiquement recalculé.
Lis ceci :
The value of the hDC property can change while a program is running, so don't store the value in a variable; instead, use the hDC property each time you need it


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
8 juin 2012 à 18:10
Je te remercie pour ces précisions importantes Ucfoutu, mais je ne suis pas suffisamment expert pour comprendre le rapport avec mon problème expliqué dans mon précédent message et encore moins y percevoir une solution.

Peut-être que je n'utilise pas la bonne méthode pour obtenir le résultat que je souhaite?

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 220
8 juin 2012 à 18:23
La lecture en diagonale de ton code me conduit à ne pas l'incriminer vraiment.
La position de la picturebox n'est nullement concernée, dès lors que le hdc sur lequel tu travailles est le sien (et son extraction dans ton code n'appelle aucune remarque de ma part).
Ce que je tenterais, à ta place, juste pour le cas où le hdc serait "touché" en chemin :
Placer :
GetDCInt = GetDC(Pict.Handle)
au début de ta boucle après le For ...
et
Call ReleaseDC(0, GetDCInt)
juste avant le next
Le mieux serait toutefois de tenter d'envoyer d'un seul coup les données de ton bitmap dans un buffer (tableau) et de travailler ensuite en boucle sur ce tableau.
Essaye d'utiliser la fonction GetDIBits de la librairie gdi32 de l'Api de Windows. Tu trouveras un exemple de son utilisation sur le site de AllApi
Ce serait là ma préférence.
Bon courage.
________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
8 juin 2012 à 18:26
Merci beaucoup Ucfoutu, je regarde de suite. ;)

Jimy

Pensez: Réponse acceptée
'**********************************************
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
8 juin 2012 à 22:16
Le placement du getHC entre le For Next ne change rien, je pense maintenant qu'il n'est pas en cause.

Après plusieurs essais, plus je fais disparaitre par "glisser" le Form portant la piturebox derrière le bord de l'écran, plus la mesure tends vers 255...

Je vais tenter la bufferisation...
En attendant si tu as une idée?...

PS: Tu as raison de me souhaiter "Bon courage", l'exemple de GetDIBits sur AllAPI est ... comment dire....



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 220
8 juin 2012 à 22:25
Comment ton image est-elle chargée dans la picturebox ? d'où vient-elle, exactement ?
A partir de là, je te guiderai, mais uniquement sur le mécanisme, ou avec du code VB6 qu'il te faudra un peu transformer, car VB.Net et moi sommes fâchés (je le suis en fait surtout à l'égard de Microsoft et du "forcing" qu'il a fait, pour être précis. Je m'érige donc sans scrupules en rebelle).


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
10 juin 2012 à 14:23
Salut les amis,

Et bien Banana, et fait, j'aivais zappé ta proposition, et bien fait pour moi, j'ai perdu pas mal de temps, parce que c'était la solution!

Module GetPixel
    'Declaration
    Public Function GetPixel( _
     ByVal x As Integer, _
     ByVal y As Integer _
    ) As Color

    End Function

    Public Function ScanPicts(ByVal DirPict As String) 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
        Dim myBitmap As New Bitmap(DirPict)

        'Scan de l'image
        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
                '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
        Tab.LabNbPixel2.Visible = True
        Tab.LabNbPixel2.Text = "Opération terminée: " & Index.ToString & " pixels scannés par image."
        ScanPicts = (SomPx / Index)

    End Function
End Module


Alors merci à toi, et aussi à Ucfoutu qui est toujours à l'écoute, même en prennant de gros risque à flirter avec du NET!

Encore merci!

Marc


Jimy

Pensez: Réponse acceptée
'**********************************************
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
10 juin 2012 à 18:33
Petite conclusion (mais je peux le louper! ):
J'ai repris le code avec les API GetDC et GetPixel, apparemment, tout pixel non visible à l'écran se voit attribué la valeur 255, même si le GetDC pointe un picturebox!


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 220
10 juin 2012 à 18:58
Je ne vois pas pourquoi.
J'ignore par contre si, comme sous VB6, ta picturebox a une propriété Autoredraw et une propriété image. Car si "perte", cela veut dire que l'image est "volatile" (je ne trouve pas le terme exact). Ce sera par exemple le cas si tu réduis le Form puis le réaffiches en mode normal et que l'image n'y est plus visible.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
cs_ShayW Messages postés 3258 Date d'inscription jeudi 26 novembre 2009 Statut Membre Dernière intervention 3 décembre 2019 56
10 juin 2012 à 21:30
Salut

pourquoi déclares tu la fonction
Module GetPixel
    'Declaration
    Public Function GetPixel( _
     ByVal x As Integer, _
     ByVal y As Integer _
    ) As Color

    End Function


ce n'est pas la peine puisque c'est une méthode
de la class bitmap
et aussi il manque
return ScanPicts 

à la fin de ta fonction ScanPicts

J'ai repris le code avec les API GetDC et GetPixel,



dommage Banana32 (Salut )
t'avais montré le bon chemin
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
11 juin 2012 à 07:35
Salut ShayW,

Ok pour le Return, mais cela fonctionne très bien aussi sans!
Tu dis avoir repris le code....Et??

Jimy

Pensez: Réponse acceptée
'**********************************************
0
cs_ShayW Messages postés 3258 Date d'inscription jeudi 26 novembre 2009 Statut Membre Dernière intervention 3 décembre 2019 56
11 juin 2012 à 09:57
Tu dis avoir repris le code....Et??


pas moi c'était plutot une citation de ton poste
précedent

je n'ai pas compris pourquoi tu as repris avec
API GetDC
peux tu faire la mise au point
comprend vite quand on explique longtemps
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 220
11 juin 2012 à 17:51
Coucou, Jimy neutron.

J'avais du temps libre et me suis donc amusé avec VB6.
Amusé à quoi ? à faire en sorte d'avoir tous mes pixels de la picturebox, qu'elle soit visible ou non, en autoredraw ou non. Mieux, même : à les avoir tous y compris à partir du fichier image (sans même la picturebox, donc, si tu le souhaitais).

Le tout en moins de 20 lignes de code.

Si tu es intéressé, je te montre ce bout de code, qu'il te faudra ensuite transposer en VB.Net.
Tu dis
________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
jimy neutron Messages postés 491 Date d'inscription mercredi 1 février 2006 Statut Membre Dernière intervention 18 novembre 2016 1
11 juin 2012 à 18:11
ShayW, j'ai repris le code avec les API pour essayer de comprendre pourquoi les pixels qui ne sont plus visibles sur l'écran sont mesurés à 255. Par curiosité quoi!

UcFoutu, cette même curiosité accepte bien volontiers ta proposition!

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 220
11 juin 2012 à 18:22
Voilà donc du VB6
Option Explicit
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function TranslateColor Lib "olepro32.dll" Alias "OleTranslateColor" (ByVal clr As OLE_COLOR, ByVal palet As Long, col As Long) As Long
Private Sub Command1_Click()
    Dim toto As New StdPicture, i As Long, j As Long, couleur As Long
    Dim hdc As Long, R As Byte, G As Byte, B As Byte
    'Picture1.Picture = LoadPicture("d:\bateau.bmp") ' <<<<===== ton image à toi ici, si tu traite picturebox et décommente
    'Set toto = Picture1.Picture ' si tu veux partir d'une picturebox - et décommente
    Set toto = LoadPicture("d:\bateau.bmp") ' si tu veux partir d'un fichier . Inhibe sinon
    hdc = CreateCompatibleDC(0)
    SelectObject hdc, toto.Handle
    For i = 0 To toto.Width
      For j = 0 To toto.Height
        couleur = GetPixel(hdc, i, j)
        Dim RealColor As Long
        TranslateColor couleur, 0, RealColor
        R = RealColor And &HFF&
        G = (RealColor And &HFF00&) / 2 ^ 8
        B = (RealColor And &HFF0000) / 2 ^ 16
        MsgBox "R " & R & "   G " & G & "   B = " & B ' sors de cette boucle par CTRL + PAUSE
      Next j
    Next i
End Sub

Regarde les commentaires (à propos du basculage entre direct ou via picturebox).
Si via picturebox, donc ===>> lignes commentées à inverser ainsi ===>>
Picture1.Picture = LoadPicture("d:\bateau.bmp") ' <<<<===== ton image à toi ici, si tu traite picturebox et décommente
    Set toto = Picture1.Picture ' si tu veux partir d'une picturebox - et décommente
   ' Set toto = LoadPicture("d:\bateau.bmp") ' si tu veux partir d'un fichier . Inhibe sinon

Rappelle-toi : sous VB.Net : longs ===>> integer


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
Rejoignez-nous