Page 1 of 1

Work on image in memory

Posted: Sun Jul 19, 2009 12:47 am
by abarkley
Still pretty new to PB.

I want to do some RGB or grayscale image Pixel data (image manipulation) work. I'd like these ops to work fast. This is probably best done by working directly on memory - and if necessary, using some simple assembly language routines (I did this for 8-bit MPU's many years ago, so I'd like to have another try). The alternative seems to be DRAWing on images using PLOT and POINT which I suspect will be too slow.

I see plenty of PB commands for allocating/manipulating memory addresses as well as CatchImage.

How do I load an image from disk into memory and then get it's memory start address?

Help appreciated.

Posted: Sun Jul 19, 2009 2:07 am
by idle
Assuming your on windows.

If you're intending to manipulate the image and save it back to file then it's probably better to use GDI methods.

The internal PB 2D functions are pretty fast, however if speed is really a concern then you will get a bit more speed from using a DIB.

This is generally the method I use found on the forum

Code: Select all

 
Procedure CopyImageToMemory(ImageNumber, Memory)
 
  Protected TemporaryDC, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
 
  TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
 
  GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
  
   
  TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
  TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
  TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
  TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
  TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
 
  GetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
 
  DeleteDC_(TemporaryDC)
 
EndProcedure 

Procedure CopyMemoryToImage(Memory, ImageNumber)
 
  Protected TemporaryDC, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
 
  TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
 
  GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
 
  TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
  TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
  TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
  TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
  TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
 
  SetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
 
  DeleteDC_(TemporaryDC)
 
EndProcedure

UsePNGImageDecoder()
UseJPEGImageDecoder()

If OpenWindow(0,0,0,800,600,"test",#PB_Window_SizeGadget | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget |#PB_Window_MaximizeGadget | #PB_Window_ScreenCentered)

  If FileSize("legion.jpg")= -1
   InitNetwork()
   ReceiveHTTPFile("http://www.idlearts.com/images/legion.jpg","legion.jpg")
  EndIf

  img1 = LoadImage(#PB_Any,"legion.jpg")

  If img1
  
    width = ImageWidth(img1)
    height = ImageHeight(img1)
    ResizeWindow(0,0,0,width,height)
    ImageGadget(0,0,0,width,height,ImageID(img1))
    
    *mem = AllocateMemory(width*height*4) ;32 bit image 
    CopyImageToMemory(img1,*mem) 
    
    Global *px.long, color.i 
    
    For x = 0 To width-1 
       For y = 0 To height-1 
           *px = *mem + ((x + (y * width)) << 2 )
             ;(BGR format)
             B= *px\l & FF
             G = *px\l >> 8 & $FF
             R = *px\l >> 16 & $FF
             
             *px\l = r << 16 ;set the pixel red     
    
        Next 
    Next 
    
    copymemorytoimage(*mem,img1) 
    SetGadgetState(0,ImageID(img1))
    
    If *mem 
      FreeMemory(*mem)
     *mem=0
    EndIf
  
  EndIf 
EndIf 

MessageRequester("DSA test","Image is now red")   
[/code]

Posted: Sun Jul 19, 2009 2:36 am
by netmaestro
Also assuming Windows: here's another sample to study and play with. Note the speed of using a structured pointer to manipulate the color bits vs. point/plot:

Code: Select all

Declare Swap24(*bmp.BITMAP) 
Declare Swap24_POINT_PLOT(img) 

; Load the image into memory 
UseJPEGImageDecoder() 
LoadImage(0, #PB_Compiler_Home+"examples\sources\data\r2skin.jpg") 

; Get information about the image 
GetObject_(ImageID(0), SizeOf(BITMAP), @bmp.BITMAP) 

With bmp 
  Debug \bmWidth 
  Debug \bmHeight 
  Debug \bmWidthBytes 
  Debug \bmBitsPixel 
  Debug \bmBits 
EndWith 

OpenWindow(0,0,0,bmp\bmWidth,bmp\bmHeight+70,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
ImageGadget(0,0,0,0,0,ImageID(0)) 
ButtonGadget(1,250,522,200,20,"Swap via structured pointer") 
ButtonGadget(2,50,522,200,20,"Swap via point/plot") 
ProgressBarGadget(3, 0,552,512,20,0,ImageWidth(0)*ImageHeight(0))

disabledebugger

Repeat 
  ev=WaitWindowEvent() 
  Select ev 
    Case #PB_Event_Gadget 
      Select EventGadget() 
        Case 1 
          Swap24(@bmp) 
          SetGadgetState(0,ImageID(0)) 
        Case 2
          Swap24_POINT_PLOT(0) 
          SetGadgetState(0,ImageID(0))
      EndSelect 
  EndSelect 
Until ev=#PB_Event_CloseWindow 

Procedure Swap24(*bmp.BITMAP) 
   SetGadgetState(3,0) : cc=0
   *buffer.RGBTRIPLE = *bmp\bmBits 
   While *buffer <= *bmp\bmBits+*bmp\bmWidthBytes**bmp\bmHeight-SizeOf(RGBTRIPLE) 
     Swap *buffer\rgbtBlue, *buffer\rgbtRed 
     *buffer+SizeOf(RGBTRIPLE) : cc+1
     If cc%1000=0:SetGadgetState(3, cc):EndIf
   Wend 
EndProcedure 

Procedure Swap24_POINT_PLOT(img) 
  SetGadgetState(3,0) : cc=0
  StartDrawing(ImageOutput(img))
    For j=0 To ImageHeight(img)-1
      For i=0 To ImageWidth(img)-1
        color = Point(i,j)
        Plot(i,j, RGB(Blue(color),Green(color),Red(color)))
        cc+1
        If cc%1000=0:SetGadgetState(3, cc):EndIf
      Next
    Next
  StopDrawing()
EndProcedure 

Posted: Sun Jul 19, 2009 4:27 pm
by abarkley
Thanks for that. A bit complex for this noob - useful for me to try to work through it though.

Can I rephrase the question?

Is it realistic for me to work on a bitmap in memory without making any operating system calls? You say that the native PB commands are pretty quick.

The app is fairly simple - sort of very limited Photoshop - and I'm thinking about it running on a basic netbook (altho, I know zip about Linux at the moment).

Posted: Sun Jul 19, 2009 6:29 pm
by netmaestro
My example employs only one API call, GetObject_(), used to get the address of the color bits. Surely you can live with that?

Re:

Posted: Wed Jan 18, 2017 2:18 pm
by coder14
idle wrote:

Code: Select all

 Procedure CopyImageToMemory(ImageNumber, Memory)
 
  Protected TemporaryDC, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
 
  TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
 
  GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
  
   
  TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
  TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
  TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
  TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
  TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
 
  GetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
 
  DeleteDC_(TemporaryDC)
 
EndProcedure 

Procedure CopyMemoryToImage(Memory, ImageNumber)
 
  Protected TemporaryDC, TemporaryBitmap.BITMAP, TemporaryBitmapInfo.BITMAPINFO
 
  TemporaryDC = CreateDC_("DISPLAY", #Null, #Null, #Null)
 
  GetObject_(ImageID(ImageNumber), SizeOf(BITMAP), TemporaryBitmap.BITMAP)
 
  TemporaryBitmapInfo\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth       = TemporaryBitmap\bmWidth
  TemporaryBitmapInfo\bmiHeader\biHeight      = -TemporaryBitmap\bmHeight
  TemporaryBitmapInfo\bmiHeader\biPlanes      = 1
  TemporaryBitmapInfo\bmiHeader\biBitCount    = 32
  TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
 
  SetDIBits_(TemporaryDC, ImageID(ImageNumber), 0, TemporaryBitmap\bmHeight, Memory, TemporaryBitmapInfo, #DIB_RGB_COLORS)
 
  DeleteDC_(TemporaryDC)
 
EndProcedure
Sorry to bump an old topic but is there any way to convert these two functions for Mac OSX? :?:

Re: Work on image in memory

Posted: Wed Jan 18, 2017 3:07 pm
by Keya
here is an example of reading every pixel in an image, in memory, no Point()/Plot(), all OS:

Code: Select all

Structure RGB
  r.a
  g.a
  b.a
EndStructure

Procedure ReadImage(hImg)
  Protected *imgbuf, *pixel.RGB, Pixbytes, Rowbytes, x,y, width, height
  If StartDrawing(ImageOutput(hImg))
    width = ImageWidth(hImg)
    height = ImageHeight(hImg)
    Pixbytes = ImageDepth(hImg)/8
    Rowbytes = DrawingBufferPitch()
    *imgbuf = DrawingBuffer()
    For y = 0 To height-1
      *pixel = *imgbuf + (y * Rowbytes)
      For x = 0 To width-1      
        Debug "RGB = " + Hex(*pixel\r)+" "+Hex(*pixel\g)+" "+Hex(*pixel\b)  ;RGB on Linux/Mac, BGR on Windows      
        *pixel + Pixbytes
      Next x
    Next y    
    StopDrawing()  
  EndIf
EndProcedure

UsePNGImageDecoder(): UseJPEGImageDecoder()
Define hImg = LoadImage(#PB_Any,"c:\test.jpg")
If hImg = 0: MessageRequester("Error","Couldnt load image"): End: EndIf
ReadImage(hImg)

Re: Work on image in memory

Posted: Fri Jan 20, 2017 1:53 am
by coder14
Keya wrote:here is an example of reading every pixel in an image, in memory, no Point()/Plot(), all OS:

Code: Select all

Structure RGB
  r.a
  g.a
  b.a
EndStructure

Procedure ReadImage(hImg)
  Protected *imgbuf, *pixel.RGB, Pixbytes, Rowbytes, x,y, width, height
  If StartDrawing(ImageOutput(hImg))
    width = ImageWidth(hImg)
    height = ImageHeight(hImg)
    Pixbytes = ImageDepth(hImg)/8
    Rowbytes = DrawingBufferPitch()
    *imgbuf = DrawingBuffer()
    For y = 0 To height-1
      *pixel = *imgbuf + (y * Rowbytes)
      For x = 0 To width-1      
        Debug "RGB = " + Hex(*pixel\r)+" "+Hex(*pixel\g)+" "+Hex(*pixel\b)  ;RGB on Linux/Mac, BGR on Windows      
        *pixel + Pixbytes
      Next x
    Next y    
    StopDrawing()  
  EndIf
EndProcedure

UsePNGImageDecoder(): UseJPEGImageDecoder()
Define hImg = LoadImage(#PB_Any,"c:\test.jpg")
If hImg = 0: MessageRequester("Error","Couldnt load image"): End: EndIf
ReadImage(hImg)
Which function is that? :?