Seite 1 von 1

Bild mit GetDIBits_ gelesen wird nicht richtig dargestellt

Verfasst: 07.10.2008 14:14
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 

Verfasst: 07.10.2008 17:01
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.

Verfasst: 07.10.2008 17:10
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.

Verfasst: 07.10.2008 18:04
von Fluid Byte
Poste mal den kompletten code und das Bild.

Verfasst: 07.10.2008 18:28
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.

Verfasst: 07.10.2008 19:17
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

Verfasst: 07.10.2008 19:24
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.

Verfasst: 08.10.2008 01:37
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?

Verfasst: 08.10.2008 14:24
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