Speed of Image manipulation

Everything else that doesn't fall into one of the other PB categories.
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Speed of Image manipulation

Post by fsw »

Hi all,
I have a image with the size of 2048 x 1536 pixel.
Now I like to rotate it 90 degrees and I use this function:

Code: Select all

      Image2DC = StartDrawing(ImageOutput())
  
      For y = 0 To Image\bmHeight
        For x = 0 To Image\bmWidth  
          BitBlt_(Image2DC,y,Image\bmWidth-x-1,1,1,Image1DC,x,y,#SRCCOPY)
        Next
      Next

      StopDrawing()
All works fine but what I find interesting is the fact that this loop takes about 5 seconds from start to the end (CPU 100%), and IrfanView takes for the same function (rotate left/right) approximatly 1 second (CPU 66%).

How is that possible :?:

Is the double FOR/NEXT loop so slow under PureBasic :?:
(I suppose that Irfan also uses the BitBlt API function for the rotation...)

How can I accellerate the rotation ?

BTW:
For now I start 3 threads (Rotate Original Right / Rotate Original Left / Rotate Original Twice - each one waits for the prior started one) right when a image is chosen by the user.

When the user after 5 seconds clicks the function Rotate Original Right OR after 10 seconds Rotate Original Left OR after 15 seconds Rotate Original Twice, the pictures show up immediately after a mouse click (way faster as IrfanView hint, hint, hint... - supposed the user looks at a image at least for a few seconds before he decides to do something...).

But if he clicks right after choosing one, it takes 5 seconds for Right + 5 for Left and + 5 for Twice (rotate 180 degrees) which ends up to 15 seconds.

I can't use the 3 threads on the same time because of some PB functions used (StartDrawing, StopDrawing, CreateImage, UseImage) and on the other hand I don't know if it would speed up a bit (1 CPU anyway)...

I am to provide the public with beneficial shocks.
Alfred Hitshock
Blade
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Aug 06, 2003 2:49 pm
Location: Venice - Italy, Japan when possible.
Contact:

Post by Blade »

BitBlt perhaps is meant for large screen area...
For single pixel I'd use peeks/pokes.
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

Found out what's misleading my measurements:

IrfanView always resizes the Image the way you can see it to the full.
So my 2048 x 1536 image was always resized to 840x630 (for a 1024x768 desktop resolution) and then rotated.

And I didn't. I always rotated with the original size.

If I do it with my routine the image (resized to 840x630 first) needs also 1 second to do it.

So it seems all is OK.

But if anybody has a faster way to do it, please let me know.

I am to provide the public with beneficial shocks.
Alfred Hitshock
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

have you had a look at PlgBlt_() ?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
freak
PureBasic Team
PureBasic Team
Posts: 5946
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Yes, PlgBlt_() is very fast. In my test, was about 12x faster than BitBlt_()
with the For/Next.

Unfortunately PlgBlt_() is only supported on Windows NT/2K/XP.

Some code:

Code: Select all

      Image2DC = StartDrawing(ImageOutput())

        ; These 3 points represent 3 points of the old image, and the values you assign
        ; to them are their positions in the new image.
        ;
        ; first:  top/left corner of old image
        ; second: top/right corner of old image
        ; third:  bottom/left corner of old image
        
        Dim Points.Point(2) 
        
        Points(0)\x = 0   
        Points(0)\y = Image\bmWidth
                      
        Points(1)\x = 0  
        Points(1)\y = 0
        
        Points(2)\x = Image\bmHeight 
        Points(2)\y = Image\bmWidth
        
        PlgBlt_(Image2DC, @Points(), Image1DC, 0, 0, Image\bmWidth, Image\bmHeight, 0, 0, 0)
        
      StopDrawing() 
My test was 12 seconds with BitBlt_() and not even 1 second with this
code. (2560x1024 image)

btw: rotating by any angle and any rotation point is possible like this.
You just have to write a routine to calculate the corner points.

Timo
quidquid Latine dictum sit altum videtur
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

Thank you all.
Will try it out.

I am to provide the public with beneficial shocks.
Alfred Hitshock
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

damn, i must be stupid or what, but i can't get plgblt_ to work, anybody who can see what's wrong with the following code?

Code: Select all


main_whnd = OpenWindow(0,0,0,660,500,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"Test")
main_dc = GetDC_(main_whnd)
  ; 
bitmap_hnd.l = LoadImage(0,"c:\software\purebasic\_projects\1.bmp")
bitmap_w = ImageWidth()
bitmap_h = ImageHeight()
;
Structure corners
  x1.l            ; left upper corner
  y1.l            
  x2.l            ; right upper corner
  y2.l
  x3.l            ; left lower corner
  y3.l
EndStructure

new.corners
new\x1 = 0
new\y1 = 0
new\x2 = bitmap_w
new\y2 = 0
new\x3 = 0
new\y3 = bitmap_h

StartDrawing(WindowOutput())
source_dc = CreateCompatibleDC_(main_dc)
 
SelectObject_(source_dc,bitmap_hnd)
PlgBlt_(main_dc,@new\x1,source_dc,0,0,bitmap_w,bitmap_h,0,0,0) 
; BitBlt_(main_dc,0,0,bitmap_w,bitmap_h,source_dc,0,0,#SRCCOPY)

StopDrawing() 
; 
DeleteDc_(source_dc)
ReleaseDC_(main_whnd,main_dc)
;     
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Fred
Administrator
Administrator
Posts: 18350
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

StartDrawing() returns the DC, may be it could help you..
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

fred, i think it's a bug (sorry)

if i comment out any of the last three lines (that have nothing to do with the rest of this code) it doesn't display the image

is there something of a cache in the compiler that isn't cleared?

Code: Select all

main_whnd = OpenWindow(0,0,0,660,500,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"Test")
main_dc = GetDC_(WindowID(0))
; 
bitmap_hnd.l = LoadImage(0,"..\_projects\1.bmp")
bitmap_w = ImageWidth()
bitmap_h = ImageHeight()
;
Structure corners
  x1.l            ; left upper corner
  y1.l            
  x2.l            ; right upper corner
  y2.l
  x3.l            ; left lower corner
  y3.l
EndStructure
; 
new.corners
new\x1 = bitmap_w
new\y1 = 0
new\x2 = bitmap_w
new\y2 = bitmap_h
new\x3 = 0
new\y3 = 0
;  
source_dc = CreateCompatibleDC_(main_dc)
SelectObject_(source_dc,bitmap_hnd)
;  
StartDrawing(WindowOutput())
PlgBlt_(main_dc,@new\x1,source_dc,-10,10,bitmap_w,bitmap_h,0,0,0) 
StopDrawing() 
;
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
;
Debug bitmap1_hnd
Debug main_nr
bitmap2_hnd.l = LoadImage(1,"..\_projects\2.bmp")
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Fred
Administrator
Administrator
Posts: 18350
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

There is something wrong for sure. I will take a closer look.
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

I was not able to get plgblt_ to work either.
But I said nothing because I thought: It's me again :cry:
Fred
Administrator
Administrator
Posts: 18350
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Try to disable the debugger to see if the problem is gone..
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

Fred wrote:Try to disable the debugger to see if the problem is gone..
YES, IT'S GONE...

I am to provide the public with beneficial shocks.
Alfred Hitshock
Fred
Administrator
Administrator
Posts: 18350
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Ok, as pointed by Danilo on IRC, painting directly on the Window is bad as the debugger erase it... Use an ImageGadget() to get a refresh persistent image...
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

following works...

*** edit *** but only with the debugger off

Code: Select all


main_whnd = OpenWindow(0,200,100,660,500,#PB_Window_SystemMenu,"Test")
main_dc = GetDC_(WindowID(0))
; 
bitmap1_hnd.l = LoadImage(0,"..\_projects\1.bmp")
bitmap_w = ImageWidth()
bitmap_h = ImageHeight()bitmap_h = ImageHeight()
;
bitmap2_hnd = CreateImage(1,bitmap_w,bitmap_h)
;
Structure corners
  x1.l            ; left upper corner
  y1.l            
  x2.l            ; right upper corner
  y2.l
  x3.l            ; left lower corner
  y3.l
EndStructure
; 
new.corners
new\x1 = bitmap_w
new\y1 = 0
new\x2 = bitmap_w
new\y2 = bitmap_h
new\x3 = 0
new\y3 = 0
;  
source_dc = CreateCompatibleDC_(main_dc)
SelectObject_(source_dc,bitmap1_hnd)
dest_dc = CreateCompatibleDC_(main_dc)
SelectObject_(dest_dc,bitmap2_hnd)
PlgBlt_(dest_dc,@new\x1,source_dc,0,0,bitmap_w,bitmap_h,0,0,0) 
deletedc_(source_dc)
deletedc_(dest_dc)
;
UseWindow(0)
StartDrawing(WindowOutput())
DrawImage(bitmap2_hnd,10,10)
StopDrawing()
;
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
;
Last edited by blueznl on Sat Nov 01, 2003 12:12 am, edited 1 time in total.
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Post Reply