 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Zippo
Joined: 21 Apr 2006 Posts: 56 Location: East Coast, USA
|
Posted: Wed Feb 07, 2007 10:27 pm Post subject: Randomly pixeling in an image |
|
|
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
| 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 |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Wed Feb 07, 2007 11:53 pm Post subject: |
|
|
At first I thought you meant it drew each pixel in a random place, to get a jumbled picture.
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 |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Thu Feb 08, 2007 12:27 am Post subject: |
|
|
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 |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6721 Location: France (near Paris)
|
Posted: Thu Feb 08, 2007 4:13 pm Post subject: |
|
|
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! 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 |
|
 |
Zippo
Joined: 21 Apr 2006 Posts: 56 Location: East Coast, USA
|
Posted: Fri Feb 09, 2007 3:28 am Post subject: |
|
|
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  _________________ ____________________ |
|
| Back to top |
|
 |
skrommel
Joined: 30 Jul 2004 Posts: 180
|
Posted: Sun Feb 11, 2007 10:59 pm Post subject: Sort,list,Random |
|
|
May I suggest using
Sort,list,Random
to speed things up?
Skrommel |
|
| Back to top |
|
 |
skrommel
Joined: 30 Jul 2004 Posts: 180
|
Posted: Mon Feb 12, 2007 1:18 am Post subject: RandomSplash |
|
|
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 |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Mon Feb 12, 2007 1:48 am Post subject: |
|
|
| 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 |
|
 |
skrommel
Joined: 30 Jul 2004 Posts: 180
|
Posted: Mon Feb 12, 2007 9:31 am Post subject: Radeon |
|
|
What graphics card are you using? I've got a Radeon 9600SE.
Skrommel |
|
| Back to top |
|
 |
skrommel
Joined: 30 Jul 2004 Posts: 180
|
Posted: Mon Feb 12, 2007 9:37 am Post subject: |
|
|
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 |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Tue Feb 13, 2007 12:38 am Post subject: |
|
|
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 |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Tue Feb 13, 2007 1:10 am Post subject: |
|
|
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 |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Tue Feb 13, 2007 3:13 am Post subject: |
|
|
And yet another version.
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 |
|
 |
svi
Joined: 09 Oct 2006 Posts: 126 Location: Finland
|
Posted: Mon Jul 30, 2007 11:58 pm Post subject: |
|
|
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 |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|