Bild mit GetDIBits_ gelesen wird nicht richtig dargestellt

Anfängerfragen zum Programmieren mit PureBasic.
Thomas_freak
Beiträge: 4
Registriert: 07.10.2008 14:02
Wohnort: Homburg (Saar)

Bild mit GetDIBits_ gelesen wird nicht richtig dargestellt

Beitrag von Thomas_freak »

Hallo, ich bin neu hier.
Ich habe ein jpg mit GetDIBits_ pder Pointer in ein Array ausgelesen und möchte dieses weiterverarbeiten, leider habe ich bei der Überprüfung gesehen, dass es nicht richtig funktioniert. Das Bild wird verzerrt angezeigt und die Farbe rot scheint zu fehlen, zumindest ist eine rote Rose bzw. das Gewirr, dort wo sie sein müsste, jetzt blau.
Hat jemand eine idee?

Code: Alles auswählen

Procedure CopyImageToMem(Img.l, mem.l)
  Protected bmi.BITMAPINFO
  Protected w.l, h.l, hBmp.l, hDC.l
  
  w = ImageWidth(Img)
  h = ImageHeight(Img)
  hBmp = ImageID(Img)
 
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth       =  w
  bmi\bmiHeader\biHeight      = -h
  bmi\bmiHeader\biPlanes      =  1
  bmi\bmiHeader\biBitCount    = 32
  bmi\bmiHeader\biCompression = #BI_RGB
 
  hDC  = StartDrawing( ImageOutput(Img) )
  If GetDIBits_(hDC, hBmp, 0, h, mem, bmi, #DIB_RGB_COLORS)
    StopDrawing()
    ProcedureReturn #True
  Else
    StopDrawing()
    ProcedureReturn #False
  EndIf
EndProcedure 
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Wahrscheinlich sind Rot und Blau einfach nur vertauscht.

Außerdem nutzt du als Pointer besser '*mem', damit das Programm bei
64-Bit-Systemen auch funktoniert. Ein Long (.l) hat immer 32 Bit, während
sich Integer (.i) und Pointer (*) immer an das zugrunde liegende System
anpassen.
Thomas_freak
Beiträge: 4
Registriert: 07.10.2008 14:02
Wohnort: Homburg (Saar)

Beitrag von Thomas_freak »

Wie meinst du das mit *mem als Pointer?
Ich brauche das Bild nach dem Laden in einem Array, in dem ich auf Zeile und Spalte Zugriff habe.
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Poste mal den kompletten code und das Bild.
Windows 10 Pro, 64-Bit / Outtakes | Derek
Thomas_freak
Beiträge: 4
Registriert: 07.10.2008 14:02
Wohnort: Homburg (Saar)

Beitrag von Thomas_freak »

Code: Alles auswählen

OpenWindow(fenster,10,10,500,900,"Kantendetektion RGB")

bild1=LoadImage(#PB_Any,"E:\Hobby\Programmieren\BlitzBasic\3DBild\rosen1.bmp")

breite=ImageWidth(bild1)
hoehe=ImageHeight(bild1)


Dim bildarray1.l(breite,hoehe)
Dim bildarray2.l(breite,hoehe)

Procedure CopyImageToMem(Img.l, *mem)
  Protected bmi.BITMAPINFO
  Protected w.l, h.l, hBmp.l, hDC.l
  
  w = ImageWidth(Img)
  h = ImageHeight(Img)
  hBmp = ImageID(Img)
 
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth       =  w
  bmi\bmiHeader\biHeight      =  h
  bmi\bmiHeader\biPlanes      =  1
  bmi\bmiHeader\biBitCount    =  32
  bmi\bmiHeader\biCompression = #BI_RGB
 
  hDC  = StartDrawing( ImageOutput(Img) )
  If GetDIBits_(hDC, hBmp, 0, h, *mem, bmi, #DIB_RGB_COLORS)
    StopDrawing()
    ProcedureReturn #True
  Else
    OpenConsole()  
    StopDrawing()
    ProcedureReturn #False
  EndIf
EndProcedure 

ba1=@bildarray1()
CopyImageToMem(bild1,ba1)


StartDrawing(WindowOutput(fenster))
For y=1 To hoehe
For x=1 To breite
Plot(x,y,bildarray1(x,y))
Next x
Next y
Delay(4000)
End
Das Bild konnte ich leider nicht vom Bildschirm ins Clipboard bekommen, es sah so aus, als wäre das Programm gar nicht da.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

So funktionierts bei mir:

Code: Alles auswählen

#fenster = 1

UseJPEGImageDecoder()
bild1 = LoadImage(#PB_Any, "C:\Logorollo.jpg")

breite = ImageWidth(bild1)
hoehe = ImageHeight(bild1)
If OpenWindow(#fenster, 10, 10, breite, hoehe, "Kantendetektion RGB") = 0 : End : EndIf

Dim bildarray1.l(hoehe - 1, breite - 1)
Dim bildarray2.l(hoehe - 1, breite - 1)

Procedure CopyImageToMem(Img.l, *mem)
  Protected bmi.BITMAPINFO
  Protected w.l, h.l, hBmp.l, hDC.l
 
  w = ImageWidth(Img)
  h = ImageHeight(Img)
  hBmp = ImageID(Img)
 
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth       =  w
  bmi\bmiHeader\biHeight      =  h
  bmi\bmiHeader\biPlanes      =  1
  bmi\bmiHeader\biBitCount    =  32
  bmi\bmiHeader\biCompression = #BI_RGB
 
  hDC = StartDrawing(ImageOutput(Img))
  If GetDIBits_(hDC, hBmp, 0, h, *mem, bmi, #DIB_RGB_COLORS)
    StopDrawing()
    ProcedureReturn #True
  Else
    OpenConsole() 
    StopDrawing()
    ProcedureReturn #False
  EndIf
EndProcedure

If CopyImageToMem(bild1, @bildArray1())
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_Repaint
        If StartDrawing(WindowOutput(#fenster))
          For y = 0 To hoehe - 1
            For x = 0 To breite - 1
              Plot(x, y, bildarray1(y, x))
            Next x
          Next y
          StopDrawing()
        EndIf
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  Delay(4000)
EndIf
LCD
Beiträge: 107
Registriert: 23.01.2008 13:13
Wohnort: Wien

Beitrag von LCD »

Array ist langsamer als Memory access, das habe ich nämlich auch vor Jahren verwendet.

Code: Alles auswählen

Procedure FastColor(pccol)
  ProcedureReturn (pccol&255)<<16|(pccol&65280)|(pccol>>16&255)
EndProcedure
und dann so etwas in der Art:

Code: Alles auswählen

*Buffer=*mem
For y = 0 To hoehe - 1
  For x = 0 To breite - 1
    Plot(x, y, FastColor(PeekL(*Buffer))):*Buffer+4
   Next x
 Next y
Habe ich aus dem Gedächtnis geschrieben, aber so sieht es in etwa in meinem Programm aus.
PB 4.61Beta1 32/64Bit. AMD FX6100, 8 GB RAM, ATI Radeon 5750, Win7 64 (64 bit ist mist weil 16-Bit Programme wie MakeTZX nicht mehr darauf funktionieren).
Thomas_freak
Beiträge: 4
Registriert: 07.10.2008 14:02
Wohnort: Homburg (Saar)

Beitrag von Thomas_freak »

Den Fehler habe ich gefunden. Für das Array(x,y) ist x=höhe, y=breite. Bei mir war es umgekehrt. Nun sind nur noch die Farbkanäle für Rot und Blau vertauscht.

Wenn ich memory access benutze, kann ich doch nicht auf einzele Pixel, sprich zeile und spalte (x und y) zugreifen, oder? Wie gehe ich das am besten an?
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Die Datenelemente eines beliebig dimensionalen Arrays sind im Speicher ja
auch nur linear angeordnet. Wenn du also nur den Pointer zum ersten
Eintrag eines Arrays hast, kannst du auch Zeile für Zeile durch das Array
laufen, indem du nach jedem Pixel den Pointer um 'SizeOf(Elementtyp)'
erhöhst.

Hier der Code, wie er bei mir annehmbar schnell unter Wine läuft

Code: Alles auswählen

#fenster = 1

UseJPEGImageDecoder()
bild1 = LoadImage(#PB_Any, "C:\Logorollo.jpg")

breite = ImageWidth(bild1)
hoehe = ImageHeight(bild1)
If OpenWindow(#fenster, 10, 10, breite, hoehe, "Kantendetektion RGB") = 0 : End : EndIf

Structure Color
  r.b
  g.b
  b.b
  reserved.b
EndStructure

Macro SwapRB(Color)
  ((Color & $FF) << 16) | (Color & $FF00) | (Color >> 16)
EndMacro

*bild1 = AllocateMemory(hoehe * breite * SizeOf(Color))

Procedure CopyImageToMem(Img.l, *mem)
  Protected bmi.BITMAPINFO
  Protected w.l, h.l, hBmp.l, hDC.l
 
  w = ImageWidth(Img)
  h = ImageHeight(Img)
  hBmp = ImageID(Img)
 
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth       =  w
  bmi\bmiHeader\biHeight      =  -h
  bmi\bmiHeader\biPlanes      =  1
  bmi\bmiHeader\biBitCount    =  32
  bmi\bmiHeader\biCompression = #BI_RGB
 
  hDC = StartDrawing(ImageOutput(Img))
  If GetDIBits_(hDC, hBmp, 0, h, *mem, bmi, #DIB_RGB_COLORS)
    StopDrawing()
    ProcedureReturn #True
  Else
    OpenConsole()
    StopDrawing()
    ProcedureReturn #False
  EndIf
EndProcedure

If CopyImageToMem(bild1, *bild1)
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_Repaint
        If StartDrawing(WindowOutput(#fenster))
          *Pixel.Long = *bild1
          For y = 0 To hoehe - 1
            For x = 0 To breite - 1
              Plot(x, y, SwapRB(*Pixel\l))
              *Pixel + SizeOf(Color)
            Next x
          Next y
          StopDrawing()
        EndIf
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
  Delay(4000)
EndIf
Antworten