Comment modifier une image en mémoire

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Comment modifier une image en mémoire

Message par Lord Nelson »

Salut,

Comment je peux me servir du résultat de retour de LoadImage qui est un Handle pour manipuler / modifier l'image en mémoire svp :)
Sur un autre poste ou j'ai demander à quoi servais se résultat, Nico m'as guidé vers les API SetDIBits et GetDIBits.

Seulement, je n'est aucune idée de comment me servir de ses Api !

Voici le poste en question:
http://www.purebasic.fr/french/viewtopi ... =1&t=14283
Dernière modification par Lord Nelson le mar. 11/mars/2014 9:31, modifié 1 fois.
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Comment modifier une image en mémoire

Message par Fig »

Code : Tout sélectionner

Enumeration 1
    #ImageChargement
    #ImageReproduction
EndEnumeration
; Procedure de chargement d'une image
Procedure.l ChargementImage(NumeroImage, FiltreDefaut)
    Filtre$ = "Image Bmp (*.Bmp)|*.Bmp|Image Png (*.Png)|*.Png|Image Jpeg (*.Jpg)|*.Jpg|Image Tga (*.Tga)|*.Tga|Image Tiff (*.Tiff)|*.Tiff"
    FichierImage$ = OpenFileRequester("Choisissez un fichier à charger", GetHomeDirectory() + "Bureau\", Filtre$, FiltreDefaut)
    If FichierImage$
        If FindString(LCase(GetFilePart(FichierImage$)), ".bmp", 1)
            ; Ok
        ElseIf FindString(LCase(GetFilePart(FichierImage$)), ".png", 1)
            UsePNGImageDecoder()
           
        ElseIf FindString(LCase(GetFilePart(FichierImage$)), ".jpeg", 1)
            UseJPEGImageDecoder()
           
        ElseIf FindString(LCase(GetFilePart(FichierImage$)), ".tga", 1)
            UseTGAImageDecoder()
           
        ElseIf FindString(LCase(GetFilePart(FichierImage$)), ".tiff", 1)
            UseTIFFImageDecoder()
        Else
            MessageRequester("Fichier invalide !", "      Veuillez choisir un fichier d'image invalide !", 48)
            ProcedureReturn 0
        EndIf
        image=LoadImage(NumeroImage, FichierImage$)
        If image   
            ProcedureReturn LoadImage(NumeroImage, FichierImage$)
           
        Else
            MessageRequester("Erreur de chargement !", "      Impossible de charger le fichier " + Chr(34) + GetFilePart(FichierImage$) + Chr(34) + " !", 16)
            ProcedureReturn 0
        EndIf
    EndIf
    ProcedureReturn 0
EndProcedure

Procedure AfficherImage(NumeroImage)
    FenetreImage = OpenWindow(#PB_Any, 0, 0, 1980, 1080, "Fenêtre windows",  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_TitleBar)
    If FenetreImage
        If IsImage(NumeroImage)
            ImageFenetreImage = ImageGadget(#PB_Any, 10, 10, 1, 1, ImageID(NumeroImage))
        EndIf
        Repeat ; Départ des évènements de boucle
           
            EventFenetreImage = WaitWindowEvent(1) ; Cette ligne attend pendent (Minuteur) qu'un évènement soit recus par la fenêtre
           
        Until EventFenetreImage = #PB_Event_CloseWindow ; Fin des évènements de boucle
       
        CloseWindow(FenetreImage)
    EndIf
EndProcedure


; Procedure pour lire l'image
Procedure LireImage()
    ; Lecture de l'image
    If ChargementImage(#ImageChargement, 1)
        LargeurImage = ImageWidth(#ImageChargement)
        HauteurImage = ImageHeight(#ImageChargement)
        Debug HauteurImage
        Profondeur = ImageDepth(#ImageChargement) ;32 ou 24 bits
        Bytes=profondeur/8 ;3 octets pour du 24 bts ou 4 octets pour du 32 bts
        ;initial, timer=60-64ms
        timer1.i=ElapsedMilliseconds()
        StartDrawing(ImageOutput(#ImageChargement))
        pitch=DrawingBufferPitch()
        Dim MonTableauDeCouleurs.a(pitch*HauteurImage) ;LxHx3 ou x4 octets
        *Buffer      = DrawingBuffer() ;adresse de début de l'image
        BGR24A=2:BGR24B=0 ;permet d'inverser l'ordre du Rouge et du bleu si besoin.
        If DrawingBufferPixelFormat() & #PB_PixelFormat_24Bits_BGR Or DrawingBufferPixelFormat() & #PB_PixelFormat_32Bits_BGR:Swap BGR24A,BGR24B:EndIf ;inverse en BGR
        If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY:reverse=1:EndIf ;test si le buffer est inversé en Y

        CopyMemory(*Buffer,@MonTableauDeCouleurs(),hauteurImage*pitch) ;on copie la totalité de l'image dans le tableau
        StopDrawing()
        timer1=ElapsedMilliseconds()-timer1
        ; Opération sur l'image...
        ; ...
        couleur=RGB(255,0,0) ;little-endian: en mémoire RGB est stocké dans l'ordre BGR
        If reverse ; si y est inversé...
            For y=0 To HauteurImage-1
                For x=0 To LargeurImage-1
                    MonTableauDeCouleurs(x*Bytes+((HauteurImage-1)-y)*pitch+BGR24A)=Red(couleur)
                    MonTableauDeCouleurs(x*Bytes+((HauteurImage-1)-y)*pitch+1)=Green(couleur)
                    MonTableauDeCouleurs(x*Bytes+((HauteurImage-1)-y)*pitch+BGR24B)=Blue(couleur)
                Next x
            Next y
;                 ;exemple d'écriture d'un point vert en x=10 et y=20 
         MonTableauDeCouleurs(10*Bytes+((HauteurImage-1)-20)*pitch+BGR24A)=$00 ;rouge
         MonTableauDeCouleurs(10*Bytes+((HauteurImage-1)-20)*pitch+1)=$ff ;vert
         MonTableauDeCouleurs(10*Bytes+((HauteurImage-1)-20)*pitch+BGR24B)=$00 ;bleu
        Else ;si Y est dans l'ordre
            For y=0 To HauteurImage-1
                For x=0 To LargeurImage-1
                    MonTableauDeCouleurs(x*Bytes+y*pitch+BGR24A)=Red(couleur)
                    MonTableauDeCouleurs(x*Bytes+y*pitch+1)=Green(couleur)
                    MonTableauDeCouleurs(x*Bytes+y*pitch+BGR24B)=Blue(couleur)
                Next x
            Next y
                    ;exemple d'écriture d'un point vert en x=10 et y=20
        MonTableauDeCouleurs(10*Bytes+20*pitch+BGR24A)=$00                       
        MonTableauDeCouleurs(10*Bytes+20*pitch+1)=$ff
        MonTableauDeCouleurs(10*Bytes+20*pitch+BGR24B)=$00
       EndIf
       
        ; Reproduction de l'image
        If CreateImage(#ImageReproduction, LargeurImage, HauteurImage, Profondeur)
            timer2.i=ElapsedMilliseconds()
            StartDrawing(ImageOutput(#ImageReproduction))
            *Buffer=DrawingBuffer()
            CopyMemory(@MonTableauDeCouleurs(),*Buffer,hauteurImage*pitch)
            StopDrawing()
            timer2=ElapsedMilliseconds()-timer2
            AfficherImage(#ImageReproduction)
        EndIf
       
    EndIf
    MessageRequester("timer","Lecture de l'image en "+Str(timer1)+" ms.  Ecriture de l'image en "+Str(timer2)+" ms.")
EndProcedure

LireImage()
regarde ce code qui est issu du tient, tout y est clair.
Dernière modification par Fig le mar. 11/mars/2014 15:27, modifié 2 fois.
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Re: Comment modifier une image en mémoire

Message par Lord Nelson »

Oui merci, je connais se code déjà :)
Mais je voudrait me servir directement du résulta (Handle) de LoadImage :)
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Comment modifier une image en mémoire

Message par Fig »

Dis nous ce qui te tracasse vraiment, ce que tu veux faire au final, parce que j'ai l'impression qu'on tourne un peu en rond avec tes questions. :wink:
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Comment modifier une image en mémoire

Message par falsam »

Fig a écrit :Dis nous ce qui te tracasse vraiment, ce que tu veux faire au final, parce que j'ai l'impression qu'on tourne un peu en rond avec tes questions. :wink:
Ce n'est pas qu'une impression :mrgreen:
Lord Nelson a écrit :Comment je peux me servir du résultat de retour de LoadImage qui est un Handle pour manipuler / modifier l'image en mémoire svp :)
Tu as bien dit manipulation de l'handle de l'image :)

■ Premier exemple très très simple. [PB 5.22]
-Chargement d'une image et visualisation de l'image en se servant du handle de l'image chargée.

Code : Tout sélectionner

Enumeration
  #Mainform
  #Image
EndEnumeration

Global Event, HandleImageID

Global WindowStyle.i=#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget

Procedure Open_MainForm()
  OpenWindow(#Mainform, 0, 0, 800, 600, "New Form", WindowStyle)
EndProcedure

Open_MainForm()

UseJPEGImageDecoder()
HandleImageID = LoadImage(#PB_Any, #PB_Compiler_Home+"Examples\3D\Data\Textures\ValetCoeur.jpg")
ImageGadget(#image, 5, 5, 0, 0, ImageID(HandleImageID))    
 
Repeat
  Event  = WaitWindowEvent(10)
  
  Select Event        
    Case #PB_Event_CloseWindow
      End
  EndSelect
ForEver
Les variables sont suffisamment explicites.

■ Ce deuxième exemple de code est le même que le premier mais l'image sera affiché en dégradé de gris. [PB 5.22]

Code : Tout sélectionner

Enumeration
  #Mainform
  #Image
EndEnumeration

Global Event, HandleImageID

Global WindowStyle.i=#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget

Procedure GreyScale(HandleImageID)
  Protected x.i, y.i, color.i, Gris.i
  
  StartDrawing(ImageOutput(HandleImageID))
  
  For x = 0 To ImageWidth(HandleImageID)-1
    For y = 0 To ImageHeight(HandleImageID)-1
      Color=Point(x, y)
      Gris=Red(Color)*299/1000 + Green(Color)*587/1000 + Blue(Color)*114/1000
      Plot(x, y, RGB(Gris, Gris, Gris))
     Next y
   Next x
   
   StopDrawing()
EndProcedure


Procedure Open_MainForm()
  OpenWindow(#Mainform, 0, 0, 800, 600, "New Form", WindowStyle)
EndProcedure

Open_MainForm()

UseJPEGImageDecoder()
HandleImageID = LoadImage(#PB_Any, #PB_Compiler_Home+"Examples\3D\Data\Textures\ValetCoeur.jpg")
GreyScale(HandleImageID)
ImageGadget(#image, 5, 5, 0, 0, ImageID(HandleImageID))    
 
Repeat
  Event  = WaitWindowEvent(10)
  
  Select Event        
    Case #PB_Event_CloseWindow
      End
  EndSelect
ForEver
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Re: Comment modifier une image en mémoire

Message par Lord Nelson »

Je suis dessoler de vous ennuyer avec ça :oops:
Je m'y connais pas trop mais je me débrouille quand même.

Déjà faut bannir je pense les Point et Plot qui sont trop couteux en terme de performances ok ?
Le but est de créer une fonction ou plusieurs pour pouvoir charger l'image et la modifier et l'afficher le plus vite possible.

Je sais que on a déjà fait un code sur ça, enfin vous quoi :)
Met je me disais que...

Voila, LoadImage charge déjà l'image dans la mémoire alors il ne faut pas en plus la mettre dans un tableau ou je ne sais quoi car elle est déjà en mémoire !
Donc le but est de manipuler l'image directement depuis cette même mémoire ou se trouve cette image et ne pas faire d’opération inutile.

- Je charge l'image avec LoadImage ou alors une autre fonction qui pourrais être encore plus rapide que celle-ci.
- Je modifie cette image depuis directement cette mémoire ou se trouve l'image
- J'affiche cette image dans une fenêtre

Le but étant d'être le plus rapide possible, mais vraiment le plus rapide possible.

C'est pour ça que je me suis dit que on allais directement se servir de la mémoire ou est stoker cette image car LoadImage la met déjà en mémoire donc si
en plus de ça on met cette image dans un tableau, ça prends encore plus de temps qui est inutile car on charge l'image deux fois en quelque sorte !

Je me suis dit que se Handle que renvoie LoadImage étais le début de la mémoire ou étais stoker l'image, mais en vain !
Si c’était le cas, j'avais juste à lire et modifier les valeurs voulue directement depuis cette mémoire, puis de tout reprendre et afficher et paf !

Comment fonctionne LoadImage, comment il charge l'image en mémoire, comment il la stock et comment il la gère
Comment y accéder pour manipuler ses informations et les modifier si nécessaire ?
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Comment modifier une image en mémoire

Message par falsam »

Dans le 2eme exemple que je donne je ne passe par aucun tableau pour transformer l'image chargée en dégradé de gris. !
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Comment modifier une image en mémoire

Message par Mesa »

Refabriquer LoadImage() pour le rendre plus rapide est vraiment un très gros travail et en plus je ne suis même pas sûr qu'on y gagnerait en vitesse car c'est une "vieille" fonction qui a été optimisée depuis longtemps.

Une image n'est qu'un fichier, donc charger un fichier en mémoire avec OpenFile() est la première étape.
Mais, là où ça se gâte, c'est qu'il faudra interpréter l'entête du fichier.
Car c'est dans cet entête que se trouve toutes les infos pour décoder et afficher l'image correctement.
Si c'est une image non compressée comme un bmp, c'est faisable mais avec une image compressée comme le jpg, ça devient... gargantuesque.
Voir un exemple ici http://sylvain.fish.free.fr/JPEG_SIZE/R ... g_size.htm

Le mieux, à mon avis, est d'utiliser le buffer comme dans le code de fig.
Ne pas utiliser de tableau intermédiaire n'est pas forcément une bonne chose car le buffer est probablement utilisé en temps réel par le système d'exploitation et intervenir en même temps risque de donner des artefacts d'affichage, du scintillement, ou autre.

Pour avoir une vitesse max, il faut trouver le moyen d'utiliser la mémoire et le processeur de la carte graphique. Tous deux sont bien plus rapide que la dram et le cpu. Les "technologies" CUDA et OPENCL sont ces moyens, entre autre.

Fait des recherches sur le forum anglais avec CUDA ou OPENCL comme mot clés.

M.
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Comment modifier une image en mémoire

Message par Fig »

Lord Nelson a écrit : Le but étant d'être le plus rapide possible, mais vraiment le plus rapide possible.
Ce n'est pas un but en soit, la rapidité, explique nous qu'est ce que c'est "rapide" pour toi (mon code traite ton image entière en moins d'une 10ene de ms-4 sur mon pc-) et pourquoi tu as besoin que ça soit "rapide".
Et puis, quel traitement tu veux appliquer à ton image ? Si on savait ça, ça serait plus simple aussi.

Ou encore mieux, tu nous dis sur quel forum VB tu es en train d'essayer d’impressionner quelqu'un et nous on y va pour donner un vrai code compréhensible en PB.
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Re: Comment modifier une image en mémoire

Message par Lord Nelson »

falsam a écrit :Dans le 2eme exemple que je donne je ne passe par aucun tableau pour transformer l'image chargée en dégradé de gris. !
Oui mais tu passe par un plot :wink:

Merci mesa pour ton explication, donc on est obliger de passer par un tableau, dommage :(
J'ai pas compris cette partie là par contre:
Ne pas utiliser de tableau intermédiaire n'est pas forcément une bonne chose car le buffer est probablement utilisé en temps réel par le système d'exploitation et intervenir en même temps risque de donner des artefacts d'affichage, du scintillement, ou autre.
Pour avoir une vitesse max, il faut trouver le moyen d'utiliser la mémoire et le processeur de la carte graphique. Tous deux sont bien plus rapide que la dram et le cpu. Les "technologies" CUDA et OPENCL sont ces moyens, entre autre.

Fait des recherches sur le forum anglais avec CUDA ou OPENCL comme mot clés.
Je ferais une recherche, merci encore :)
Ce n'est pas un but en soit, la rapidité, explique nous qu'est ce que c'est "rapide" pour toi (mon code traite ton image entière en moins d'une 10ene de ms-4 sur mon pc-) et pourquoi tu as besoin que ça soit "rapide".
Et puis, quel traitement tu veux appliquer à ton image ? Si on savait ça, ça serait plus simple aussi.
Oui ton code est très rapide c'est vraie :wink:

Non mais en faite tu as raison Fig, sinon après trop compliqué et puis c'est assez rapide comment ça
mais je voulais savoir s'il avais moyen de faire encore plus rapide :)

J'aurais aussi voulus aussi savoir utiliser le Handle de l'image pour récupérer les information en mémoire mais bon
peut être trop compliquer ensuite.
Dernière modification par Lord Nelson le mar. 11/mars/2014 16:01, modifié 3 fois.
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: Comment modifier une image en mémoire

Message par Fig »

Fig a écrit :Ou encore mieux, tu nous dis sur quel forum VB tu es en train d'essayer d’impressionner quelqu'un et nous on y va pour donner un vrai code compréhensible en PB.
:mrgreen:
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Re: Comment modifier une image en mémoire

Message par Lord Nelson »

Fig a écrit :
Fig a écrit :Ou encore mieux, tu nous dis sur quel forum VB tu es en train d'essayer d’impressionner quelqu'un et nous on y va pour donner un vrai code compréhensible en PB.
:mrgreen:
Lol :lol:
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Comment modifier une image en mémoire

Message par nico »

Répondre