AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Randomly pixeling in an image

 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Zippo



Joined: 21 Apr 2006
Posts: 56
Location: East Coast, USA

PostPosted: Wed Feb 07, 2007 10:27 pm    Post subject: Randomly pixeling in an image Reply with quote

I put this script together to see how well the Generating unique random integers script posted by Laszlo performed.

This script breaks up a 300x300 .jpg image and draws it back randomly, pixel by pixel, in real-time.

Even though this isn't really the best test for this type of code (a lot of overhead is added in every time a new random number is generated by the DLL call to paint a pixel to the screen...etc), it does give a visual idea of how fast this runs.

Remember, 90k pixels here. All done in an avg. of about 14 seconds on my machine.

Thanks Laszlo for the great code Smile

Code:
;  I put together this script to give me a visual idea
;  of how well AHK would run Lazlo's random number generation
;  code, linked below:
;
;  'Generating unique random integers' by Laszlo
;  http://www.autohotkey.com/forum/viewtopic.php?t=3004



SetBatchLines -1
PicX := A_ScreenWidth-300
PiCY := A_ScreenHeight-300

Gui, +AlwaysOnTop -Caption
Gui, Add, Picture, w300 h300 x%PicX% y%PicY%, 300x300.jpg
Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%

DrwArea := DllCall("GetDC", "uint", Null)



MIN = 0
MAX = 90000
N   = 90001

StartTime := A_TickCount

Loop %N%
{
  i := A_Index
  loop
  {
    Random R, %MIN%, %MAX%     ; R = random number
    j := Index_%R%             ; get value from Indexes
    If j is number
      If j between 1 and % i - 1
        If (R_%j% = R)
          continue             ; repetition found, try again
    Index_%R% := i             ; store index
    R_%i% := R                 ; store in R_1, R_2...
    break                      ; different number
  }


  CurrY := Floor(R_%i%/300)

  CurrX := R_%i%-(CurrY*300)

  PixelGetColor, CurrClr, PicX+CurrX, PicY+CurrY

  DllCall("SetPixel", "uint", DrwArea, "int", CurrX, "int", CurrY, "uint", CurrClr)
}


StopTime := A_TickCount
TotalTime := StopTime-StartTime
ToolTip, %TotalTIme%

Return

F1::Reload
Esc::ExitApp


Use F1 to restart the script, Esc to exit.



Script and sample image zipped

Sample image alone

Edit: I can't spell
_________________
____________________


Last edited by Zippo on Fri Feb 09, 2007 3:11 am; edited 1 time in total
Back to top
View user's profile Send private message
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Wed Feb 07, 2007 11:53 pm    Post subject: Reply with quote

At first I thought you meant it drew each pixel in a random place, to get a jumbled picture. Very Happy

This is much nicer. Very neat effect. It reminds of a BASIC program I wrote when I was 12, that drew random colors on random pixels. I think it was supposed to be a screensaver.

Too bad it isn't faster. Maybe you could draw 3x3 chunks with each iteration, or compute the random order beforehand and then loop only the DllCall... of course, that could potentially use a lot of memory for the storage of each position.
Back to top
View user's profile Send private message
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Thu Feb 08, 2007 12:27 am    Post subject: Reply with quote

Alright, here's my version that first determines the random order in full, and then uses it to draw the picture. The good news is that it draws it very fast, and at a consistent speed since the repetitions don't take longer to get over as the picture fills up more. The bad news is that it still takes just as long to compute, so you're sitting there staring at a blank screen until it's done. This might not be a problem, if you preload it while you do something else and then draw it when it's called for later on, but I doubt that would be the normal situation.

Added lines are in violet.

Code:
;  I put together this script to give me a visual idea
;  of how well AHK would run Lazlo's random number generation
;  code, linked below:
;
;  'Generating unique random integers' by Laszlo
;  http://www.autohotkey.com/forum/viewtopic.php?t=3004



SetBatchLines -1
PicX := A_ScreenWidth-300
PiCY := A_ScreenHeight-300

Gui, +AlwaysOnTop -Caption
Gui, Add, Picture, w300 h300 x%PicX% y%PicY%, 300x300.jpg
Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%

DrwArea := DllCall("GetDC", "uint", Null)



MIN = 0
MAX = 90000
N   = 90001

StartTime := A_TickCount

Draw_Order := ""

Loop %N%
{
  i := A_Index
  loop
  {
    Random R, %MIN%, %MAX%     ; R = random number
    j := Index_%R%             ; get value from Indexes
    If j is number
      If j between 1 and % i - 1
        If (R_%j% = R)
          continue             ; repetition found, try again
    Index_%R% := i             ; store index
    R_%i% := R                 ; store in R_1, R_2...
    break                      ; different number
  }


  CurrY := Floor(R_%i%/300)

  CurrX := R_%i%-(CurrY*300)

  PixelGetColor, CurrClr, PicX+CurrX, PicY+CurrY

  Draw_Order .= CurrX . "," . CurrY . "," . CurrClr . ";"
}

Loop,Parse,Draw_Order,;
{
  StringSplit,CurrentField,A_LoopField,`,
  DllCall("SetPixel", "uint", DrwArea, "int", CurrentField1, "int", CurrentField2, "uint", CurrentField3)
}



StopTime := A_TickCount
TotalTime := StopTime-StartTime
ToolTip, %TotalTIme%

Return

F1::Reload
Esc::ExitApp
Back to top
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Thu Feb 08, 2007 4:13 pm    Post subject: Reply with quote

I first tested jonny's version, and thought it was broken, as I saw an image on bottom left and nothing happened.
Then I tried Zippo's version and saw what it was supposed to do.
So I came back to jonny's, waited more, and saw the result!
Suggestion: do like I did and add:
Code:
  If (Mod(A_Index, 1000) = 0)
  ToolTip %A_Index%
before the end of the first loop, so we have some feedback.

I knew this function has some use, but I forgot which one. That's the one I was searching! Smile Great for screen savers or just image transitions.
Thanks.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
Zippo



Joined: 21 Apr 2006
Posts: 56
Location: East Coast, USA

PostPosted: Fri Feb 09, 2007 3:28 am    Post subject: Reply with quote

This script is a bit slow towards the end. But all-in-all, for its size and complexity, Laszlo's function is really great.

If you quote out all the extra math/dll calls, it goes thru all 90k random numbers in about 8 seconds on my system.

But like I said.. for its size it is hard to beat Smile
_________________
____________________
Back to top
View user's profile Send private message
skrommel



Joined: 30 Jul 2004
Posts: 180

PostPosted: Sun Feb 11, 2007 10:59 pm    Post subject: Sort,list,Random Reply with quote

Smile May I suggest using
Sort,list,Random
to speed things up?

Skrommel
Back to top
View user's profile Send private message Visit poster's website
skrommel



Joined: 30 Jul 2004
Posts: 180

PostPosted: Mon Feb 12, 2007 1:18 am    Post subject: RandomSplash Reply with quote

Smile Here's a different approach, with no delays!

It seems the slowest command of the scritps above is the PixelGetColor.
I tried BitBlt and StrechBlt, but they were even slower.

I ended up using two windows, one with the picture, and one transparent one above it.
By painting on the topmost window, the bottom one is revealed!
I was actually surprised that it worked!

You can make any kind of transition, just paint with a black brush on the topmost window!

Skrommel

Code:
;RandomSplash.ahk
; Shows a picture one pixel at a time
;Skrommel @2007


;Settings
image=300x300.jpg   ;Path to your picture
w=                  ;Optionally set the image width
h=                  ;Optionally set the image height, or use -1 to keep the aspect ratio


;Program
#SingleInstance,Force
#NoEnv
SetBatchLines,-1
DetectHiddenWindows,On

Gui,2:-Caption +ToolWindow +AlwaysOnTop
Gui,2:Margin,0,0
Gui,2:Add,Picture,X0 Y0 W%w% H%h%,%image%
Gui,2:Show,Hide
Gui,2:+LastFound
guiid2:=WinExist()
WinGetPos,guix,guiy,guiw,guih,ahk_id %guiid2%

Gui,3:-Caption +ToolWindow +AlwaysOnTop
Gui,3:Margin,0,0
Gui,3:Color,FFFFFF
Gui,3:Show,NoActivate X%guix% Y%guiy% W%guiw% H%guih%
Gui,3:+LastFound
guiid3:=WinExist()
WinSet,TransColor,000000 255,ahk_id %guiid3%
hDC:=DllCall("GetDC","uint",guiid3)

Gui,2:Show,NoActivate

starttime:=A_TickCount

Loop,% guiw
{
  x:=A_Index-1
  Loop,% guih
  {
    y:=A_Index-1
    list=%list%%x%,%y%`n
  }
}
Sort,list,Random

Loop,Parse,list,`n
{
  StringSplit,part_,A_LoopField,`,
  DllCall("SetPixel","uint",hDC,"int",part_1,"int",part_2,"uint",000000)
}

ToolTip,% A_TickCount-starttime
Return

F1::Reload
Esc::ExitApp
Back to top
View user's profile Send private message Visit poster's website
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Mon Feb 12, 2007 1:48 am    Post subject: Reply with quote

It's not as smooth, though. I suspect it takes some more time for the OS to grab the alpha channels and compute transparency in the background. It could also just be that this computer is slower, but it isn't that slow. With the transparent version, it seems to draw them in groups of several dozen pixels at a time, whereas with the per-pixel version it clearly drew each one separately even under load (after the list is computed).
Back to top
View user's profile Send private message
skrommel



Joined: 30 Jul 2004
Posts: 180

PostPosted: Mon Feb 12, 2007 9:31 am    Post subject: Radeon Reply with quote

Confused What graphics card are you using? I've got a Radeon 9600SE.

Skrommel
Back to top
View user's profile Send private message Visit poster's website
skrommel



Joined: 30 Jul 2004
Posts: 180

PostPosted: Mon Feb 12, 2007 9:37 am    Post subject: Reply with quote

Smile To speed things up in your script, jonny, the pixel list could be saved to a file, or included in the script itself. Then you wouldn't have to include the picture, either.

Skrommel
Back to top
View user's profile Send private message Visit poster's website
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Tue Feb 13, 2007 12:38 am    Post subject: Reply with quote

This is not the kind of effect that should require a good graphics card. It's not even using transparency (not unless you use that other method) or anything advanced, just pixel drawing.

And I thought of generating the list beforehand and storing it, but then it wouldn't be a true randomized effect.
Back to top
View user's profile Send private message
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Tue Feb 13, 2007 1:10 am    Post subject: Reply with quote

Alright, done. Still not usable, just proof-of-concept. You can process the image once with the first script and then use the effect instantly with the second one. I also added a progress bar, which makes it easy to see that it slows down a lot near the end, when you have to go through a lot of duplicates before getting to an unclaimed spot.
Code:
;kudos: laszlo, zippo
#NoEnv

Progress,x60 y60 r0-1000 b,,Initializing

SetBatchLines -1
PicX := A_ScreenWidth-300
PiCY := A_ScreenHeight-300

Gui, -Caption
Gui, Add, Picture, w300 h300 x%PicX% y%PicY%, 300x300.jpg
Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%

MIN = 0
MAX = 90000
N   = 90001
Prog_Scale := MAX / 1000

Draw_Order := ""

Progress,,,Processing image

Loop %N%
{
  i := A_Index
  loop
  {
    Random R, %MIN%, %MAX%     ; R = random number
    j := Index_%R%             ; get value from Indexes
    If j is number
      If j between 1 and % i - 1
        If (R_%j% = R)
          continue             ; repetition found, try again
    Index_%R% := i             ; store index
    R_%i% := R                 ; store in R_1, R_2...
    break                      ; different number
  }


  CurrY := Floor(R_%i%/300)
  CurrX := R_%i% - (CurrY*300)
  PixelGetColor,CurrClr,PicX+CurrX,PicY+CurrY
  Draw_Order .= CurrX . "," . CurrY . "," . CurrClr . "`n"

  Progress % A_Index / Prog_Scale
}

Progress,,,Writing to file

FileDelete 300x300.txt
FileAppend,%Draw_Order%,300x300.txt

Progress,,,Done
Return

F1::Reload
Esc::ExitApp
Code:
#NoEnv

FileRead,Draw_Order,300x300.txt
DrwArea := DllCall("GetDC", "uint", Null)

Loop,Parse,Draw_Order,`n,`r
{
  StringSplit,CurrentField,A_LoopField,`,
  DllCall("SetPixel", "uint", DrwArea, "int", CurrentField1, "int", CurrentField2, "uint", CurrentField3)
}
Back to top
View user's profile Send private message
jonny



Joined: 13 Nov 2004
Posts: 3004
Location: Minnesota

PostPosted: Tue Feb 13, 2007 3:13 am    Post subject: Reply with quote

And yet another version. Very Happy
I realize that this was originally written to demonstrate Laszlo's code, but I can't resist doing a better version of the effect itself.

This one processes linearly rather than the run time increasing exponentially as N increases (this only happens because we need to check for and re-process duplicates). Also facilitated by this version is the much faster 'Sort,,Random', probably better suited to this task than a generic randomizing algorithm.

Code:
#NoEnv

SetBatchLines -1

SIZE = 300
PicX := A_ScreenWidth-SIZE
PiCY := A_ScreenHeight-SIZE

Gui, -Caption
Gui, Add, Picture, w%SIZE% h%SIZE% x%PicX% y%PicY%, 300x300.jpg
Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%

Progress,x40 y40 r1-%SIZE% b,,Processing image
Loop %SIZE%
{
   CurrY := A_Index - 1
   Progress % A_Index
   Loop %SIZE%
   {
      CurrX := A_Index - 1
      PixelGetColor,CurrClr,PicX+CurrX,PicY+CurrY
      Draw_Order .= CurrX . "," . CurrY . "," . CurrClr . "`n"
   }
}

Progress,,,Randomizing
Sort,Draw_Order,Random

Progress,,,Writing to file
FileDelete 300x300.txt
FileAppend,%Draw_Order%,300x300.txt

Progress,,,Done
Return

F1::Reload
Esc::ExitApp
Code:
#NoEnv

FileRead,Draw_Order,300x300.txt
DrwArea := DllCall("GetDC", "uint", Null)

Loop,Parse,Draw_Order,`n,`r
{
  StringSplit,CurrentField,A_LoopField,`,
  DllCall("SetPixel", "uint", DrwArea, "int", CurrentField1, "int", CurrentField2, "uint", CurrentField3)
}


Now all that's left is to combine them and use arrays rather than a long string and a parse loop.
Back to top
View user's profile Send private message
svi



Joined: 09 Oct 2006
Posts: 126
Location: Finland

PostPosted: Mon Jul 30, 2007 11:58 pm    Post subject: Reply with quote

I made a modification to Zippo's code, to use arrays to not have to cast lots (randomize) more than the amount of pixels, as the original one made about a million randomizes for 90 000 pixels.
It's nearly five times faster and doesn't slow down towards the end, still slower than Skrommel's version, but I think fast enough.

Code:
SetBatchLines -1
picX := A_ScreenWidth-300
picY := A_ScreenHeight-300

Gui, +AlwaysOnTop -Caption
Gui, Add, Picture, w300 h300 x%picX% y%picY%, 300x300.jpg
Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight%

DrwArea := DllCall("GetDC", "uint", Null)

width=300
height=300
pixels:=width*height

StartTime := A_TickCount

x=0
y=0
index=0
Loop %height%
{
   Loop %width%
   {
      x%index%:=x
      y%index%:=y
      index++
      x++
   }
   x=0
   y++
}

Loop %pixels%
{
   pixels--
   Random r, 0, pixels
   currX:=x%r%
   currY:=y%r%
   x%r%:=x%pixels%
   y%r%:=y%pixels%
   PixelGetColor, currClr, picX+currX, picY+currY
   DllCall("SetPixel", "uint", DrwArea, "int", currX, "int", currY, "uint", currClr)
}

StopTime := A_TickCount
TotalTime := StopTime-StartTime
ToolTip, %TotalTIme%

Return

F1::Reload
Esc::ExitApp


Since the original image seems to be anavailable, here's my one (put it in the same folder as the script).
_________________
Pekka Vartto
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group