Fastest way to "learn" an image's pixels?

Just starting out? Need help? Post your questions and find answers here.
Seymour Clufley
Addict
Addict
Posts: 1264
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Fastest way to "learn" an image's pixels?

Post by Seymour Clufley »

I'm working on an image distortion routine, which needs every pixel's RGBA value for processing. The way I've got it just now is that the image is simply scanned beforehand, and its pixels' values stored in a 2-dimensional array. This takes time!

Unfortunately, using Point() during the distorting is not appropriate (nor possible), because at that time a completely new image is being drawn, based on the original.

Does anyone know of a "shortcut" to achieve what I want to achieve?

Also, would the prospects of a solution change if I didn't need every pixel's RGBA value? Distortion being as it is, the image is squashed, meaning that some of its original pixels are just irrelevant. Is there a way to handle two different images at once, and use Point() on the original image only when a pixel value is needed for the new image?
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Fastest way to "learn" an image's pixels?

Post by idle »

Code: Select all

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

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



then you call it like

Code: Select all

 
global mem = allocatememory(imagewidth(img)*imagheight(img) << 2)

copyImageToMemory(img,mem) 

;create a pointer to the memory *px.long 
define *px.long 
   x=0
    while x<width  
      x=y
       while y<height  
           *px = *mem + ((x + (y * width)) << 2 )
           R=*px\l & $FF
           G=*px\l >> 8 & $FF
           B=*px\l >> 16 & $FF
          y+1
      wend 
    x+1
 wend 

;to set a pixel 

 *px\l = RGB(R,G,B)  



maybe syntax errors in that as I just typed it direct in the box and it looks funny with the new theme :oops:
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Re: Fastest way to "learn" an image's pixels?

Post by Kaeru Gaman »

some of its original pixels are just irrelevant.
if you do it right, none of the original pixels are ever irrelevant.
you need to calculate a new pixel's color from a weighted average of the surrounding source pixels, quite like antialias or smoothing.

... from what I see at first glance, idle's routines should help you best to directly access the images' mem. that's fast as fast can.
oh... and have a nice day.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Fastest way to "learn" an image's pixels?

Post by djes »

By pity Idle, don't do that to me. My tears are flowing when I see that:

Code: Select all

global mem = allocatememory(imagewidth(img)*imagheight(img) << 2)

copyImageToMemory(img,mem)

;create a pointer to the memory *px.long
define *px.long
   x=0
    while x<width 
      x=y
       while y<height 
           *px = *mem + ((x + (y * width)) << 2 )
           R=*px\l & $FF
           G=*px\l >> 8 & $FF
           B=*px\l >> 16 & $FF
          y+1
      wend
    x+1
wend

;to set a pixel

*px\l = RGB(R,G,B)  
Get outside the main loop all this unneeded calculations. It doesn't have to be there. Our poor processor is working for nothing. Please. Do it for me!
Edit> I'm sorry, i didn't see that
maybe syntax errors in that as I just typed it direct in the box and it looks funny with the new theme :oops:
Forget what I said ;)
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Fastest way to "learn" an image's pixels?

Post by idle »

well I did say might be errors but I couldn't see them, the result of being dyslexic.
Seymour Clufley
Addict
Addict
Posts: 1264
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Fastest way to "learn" an image's pixels?

Post by Seymour Clufley »

Thanks, Idle. The code works great!
all this unneeded calculations. It doesn't have to be there
What doesn't have to be there? Could the code be simplified?
Seymour Clufley
Addict
Addict
Posts: 1264
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Fastest way to "learn" an image's pixels?

Post by Seymour Clufley »

Sorry, one more thing...

Code: Select all

           *px = *mem + ((x + (y * width)) << 2 )
           R=*px\l & $FF
           G=*px\l >> 8 & $FF
           B=*px\l >> 16 & $FF
What about the alpha channel?

And would this line

Code: Select all

TemporaryBitmapInfo\bmiHeader\biCompression = #BI_RGB
need to be changed to

Code: Select all

TemporaryBitmapInfo\bmiHeader\biCompression = #RGBA
?
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Fastest way to "learn" an image's pixels?

Post by djes »

It's not a premature optimisation to see that this line

Code: Select all

*px = *mem + ((x + (y * width)) << 2 )
in a two levels loop will be damn slow, and is totally useless, as its parts are coming directly from the loops.
So, without fully optimising, we try to have all the multiplications replaced by additions/substractions (as mul are really slow!) and we can get something like that :

Code: Select all

;create a pointer to the memory *px.long
Define *px.long
   x=0
   *px = *mem 
   width2=width+width

    While x<width 
      *opx=*px
       While y<height         
           R=*px\l & $FF
           G=*px\l >> 8 & $FF
           B=*px\l >> 16 & $FF       
          *px+width2
      Wend
      *px = *opx+2
Wend

;to set a pixel

*px\l = RGB(R,G,B)  
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Fastest way to "learn" an image's pixels?

Post by idle »

yes that much better for 2d access.

As for the alpha channel I don't think it's preserved in the dib, gdi doesn't support alpha channels.
if it did then its would just be a case of
A=*px\l >> 24 & $FF

Think you need another solution!
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Fastest way to "learn" an image's pixels?

Post by djes »

Why doesn't anybody uses gdi+? Is there some issue?
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Fastest way to "learn" an image's pixels?

Post by idle »

in my case because I don't know the API, perhaps Netmaestro would be better to ask.
Seymour Clufley
Addict
Addict
Posts: 1264
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Fastest way to "learn" an image's pixels?

Post by Seymour Clufley »

we try to have all the multiplications replaced by additions/substractions (as mul are really slow!)
I've followed this advice, but it doesn't seem to speed up the process at all. 62ms either way!
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Fastest way to "learn" an image's pixels?

Post by idle »

is that with the debugger off, djes method should be faster.
you could also try to switch the loop order in case it's causing it to page the memory.
it's no good asking a dyslexic for advice given two choices.

why don't you post what your trying to do exactly like are you trying to morph an image or deform an image and do you need it to have transparency
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: Fastest way to "learn" an image's pixels?

Post by Mistrel »

Here is a method which is about 8% faster on my machine, idle. :P

Code: Select all

Procedure CopyImageToMemory(ImageID, Memory)
  Output=ImageOutput(ImageID)
  hDC=StartDrawing(Output)
  TemporaryBitmapInfo.BITMAPINFO
  TemporaryBitmapInfo\bmiHeader\biSize=SizeOf(BITMAPINFOHEADER)
  TemporaryBitmapInfo\bmiHeader\biWidth=ImageWidth(ImageID)
  TemporaryBitmapInfo\bmiHeader\biHeight=ImageHeight(ImageID)
  TemporaryBitmapInfo\bmiHeader\biPlanes=1
  TemporaryBitmapInfo\bmiHeader\biBitCount=Imagedepth(ImageID)
  TemporaryBitmapInfo\bmiHeader\biCompression=#BI_RGB
  GetDIBits_(hDC,ImageID(ImageID),0,ImageHeight(ImageID),Memory,TemporaryBitmapInfo,#DIB_RGB_COLORS)
  StopDrawing()
EndProcedure
Seymour Clufley
Addict
Addict
Posts: 1264
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Fastest way to "learn" an image's pixels?

Post by Seymour Clufley »

It's a while ago now, but here is the final version I came up with:

Code: Select all

Procedure.b ImageIntoPixelArray(img.i,Array arr.i(2),free.b) ; final version for an independent 2D array
  
  If Not IsImage(img) : ProcedureReturn #False : EndIf
  
  iw = ImageWidth(img)
  ih = ImageHeight(img)
  
  *mem = AllocateMemory(iw*ih << 2)
  CopyImageToMemory(img,*mem)
  If free
      FreeImage(img)
  EndIf
  
  *px.LONG = *mem
  
  For x = 0 To iw-1
      ycounter = 0
      For y = 0 To ih-1
          calc = x+ycounter
          *px = *mem + (calc<<2)
          ;If *px\l
              arr(x,y) = RGBA(*px\l >> 16 & $FF, *px\l >> 8 & $FF, *px\l & $FF, *px\l >> 24 & $FF)
          ;EndIf
          ycounter+iw
      Next y
  Next x
  
  FreeMemory(*mem)
  
  ProcedureReturn #True
  
EndProcedure
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
Post Reply