Image noise
Generate a random black and white 320x240 image continuously, showing FPS (frames per second).
You are encouraged to solve this task according to the task description, using any language you may know.
Sample image:
Ada
noise.ads: <lang Ada>with Lumen.Image;
package Noise is
function Create_Image (Width, Height : Natural) return Lumen.Image.Descriptor;
end Noise;</lang>
noise.adb: <lang Ada>with Ada.Numerics.Discrete_Random;
package body Noise is
type Color is (Black, White); package Color_Random is new Ada.Numerics.Discrete_Random (Color); Color_Gen : Color_Random.Generator;
function Create_Image (Width, Height : Natural) return Lumen.Image.Descriptor is Result : Lumen.Image.Descriptor; begin Color_Random.Reset (Color_Gen); Result.Width := Width; Result.Height := Height; Result.Complete := True; Result.Values := new Lumen.Image.Pixel_Matrix (1 .. Width, 1 .. Height); for X in 1 .. Width loop for Y in 1 .. Height loop if Color_Random.Random (Color_Gen) = Black then Result.Values (X, Y) := (R => 0, G => 0, B => 0, A => 0); else Result.Values (X, Y) := (R => 255, G => 255, B => 255, A => 0); end if; end loop; end loop; return Result; end Create_Image;
end Noise;</lang>
test_noise.adb: <lang Ada>with Ada.Calendar; with Ada.Text_IO; with System.Address_To_Access_Conversions; with Lumen.Window; with Lumen.Image; with Lumen.Events.Animate; with GL; with Noise;
procedure Test_Noise is
package Float_IO is new Ada.Text_IO.Float_IO (Float);
Program_End : exception;
Win : Lumen.Window.Handle; Image : Lumen.Image.Descriptor; Tx_Name : aliased GL.GLuint; Wide : Natural := 320; High : Natural := 240; First_Frame : Ada.Calendar.Time; Frame_Count : Natural := 0;
-- Create a texture and bind a 2D image to it procedure Create_Texture is use GL;
package GLB is new System.Address_To_Access_Conversions (GLubyte);
IP : GLpointer; begin -- Create_Texture -- Allocate a texture name glGenTextures (1, Tx_Name'Unchecked_Access);
-- Bind texture operations to the newly-created texture name glBindTexture (GL_TEXTURE_2D, Tx_Name);
-- Select modulate to mix texture with color for shading glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-- Wrap textures at both edges glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-- How the texture behaves when minified and magnified glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-- Create a pointer to the image. This sort of horror show is going to -- be disappearing once Lumen includes its own OpenGL bindings. IP := GLB.To_Pointer (Image.Values.all'Address).all'Unchecked_Access;
-- Build our texture from the image we loaded earlier glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, GLsizei (Image.Width), GLsizei (Image.Height), 0, GL_RGBA, GL_UNSIGNED_BYTE, IP); end Create_Texture;
-- Set or reset the window view parameters procedure Set_View (W, H : in Natural) is use GL; begin -- Set_View GL.glEnable (GL.GL_TEXTURE_2D); glClearColor (0.8, 0.8, 0.8, 1.0);
glMatrixMode (GL_PROJECTION); glLoadIdentity; glViewport (0, 0, GLsizei (W), GLsizei (H)); glOrtho (0.0, GLdouble (W), GLdouble (H), 0.0, -1.0, 1.0);
glMatrixMode (GL_MODELVIEW); glLoadIdentity; end Set_View;
-- Draw our scene procedure Draw is use GL; begin -- Draw -- clear the screen glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); GL.glBindTexture (GL.GL_TEXTURE_2D, Tx_Name);
-- fill with a single textured quad glBegin (GL_QUADS); begin glTexCoord2f (1.0, 0.0); glVertex2i (GLint (Wide), 0);
glTexCoord2f (0.0, 0.0); glVertex2i (0, 0);
glTexCoord2f (0.0, 1.0); glVertex2i (0, GLint (High));
glTexCoord2f (1.0, 1.0); glVertex2i (GLint (Wide), GLint (High)); end; glEnd;
-- flush rendering pipeline glFlush;
-- Now show it Lumen.Window.Swap (Win); end Draw;
-- Simple event handler routine for keypresses and close-window events procedure Quit_Handler (Event : in Lumen.Events.Event_Data) is begin -- Quit_Handler raise Program_End; end Quit_Handler;
-- Simple event handler routine for Exposed events procedure Expose_Handler (Event : in Lumen.Events.Event_Data) is pragma Unreferenced (Event); begin -- Expose_Handler Draw; end Expose_Handler;
-- Simple event handler routine for Resized events procedure Resize_Handler (Event : in Lumen.Events.Event_Data) is begin -- Resize_Handler Wide := Event.Resize_Data.Width; High := Event.Resize_Data.Height; Set_View (Wide, High); Draw; end Resize_Handler;
procedure Next_Frame (Frame_Delta : in Duration) is pragma Unreferenced (Frame_Delta); use type Ada.Calendar.Time; begin Frame_Count := Frame_Count + 1; if Ada.Calendar.Clock >= First_Frame + 1.0 then Ada.Text_IO.Put ("FPS: "); Float_IO.Put (Float (Frame_Count), 5, 1, 0); Ada.Text_IO.New_Line; First_Frame := Ada.Calendar.Clock; Frame_Count := 0; end if; Image := Noise.Create_Image (Width => Wide, Height => High); Create_Texture; Draw; end Next_Frame;
begin
-- Create Lumen window, accepting most defaults; turn double buffering off -- for simplicity Lumen.Window.Create (Win => Win, Name => "Noise fractal", Width => Wide, Height => High, Events => (Lumen.Window.Want_Exposure => True, Lumen.Window.Want_Key_Press => True, others => False));
-- Set up the viewport and scene parameters Set_View (Wide, High);
-- Now create the texture and set up to use it Image := Noise.Create_Image (Width => Wide, Height => High); Create_Texture;
First_Frame := Ada.Calendar.Clock;
-- Enter the event loop declare use Lumen.Events; begin Animate.Select_Events (Win => Win, Calls => (Key_Press => Quit_Handler'Unrestricted_Access, Exposed => Expose_Handler'Unrestricted_Access, Resized => Resize_Handler'Unrestricted_Access, Close_Window => Quit_Handler'Unrestricted_Access, others => No_Callback), FPS => Animate.Flat_Out, Frame => Next_Frame'Unrestricted_Access); end;
exception
when Program_End => null;
end Test_Noise;</lang>
C
<lang c>#include <stdlib.h>
- include <stdio.h>
- include <time.h>
- include <SDL/SDL.h>
unsigned int frames = 0; unsigned int t_acc = 0;
void print_fps () {
static Uint32 last_t = 0; Uint32 t = SDL_GetTicks(); Uint32 dt = t - last_t; t_acc += dt; if (t_acc > 1000) { unsigned int el_time = t_acc / 1000; printf("- fps: %g\n", (float) frames / (float) el_time); t_acc = 0; frames = 0; } last_t = t;
}
void blit_noise(SDL_Surface *surf) {
unsigned int i; long dim = surf->w * surf->h; while (1) { SDL_LockSurface(surf); for (i=0; i < dim; ++i) { ((unsigned char *)surf->pixels)[i] = ((rand() & 1) ? 255 : 0); } SDL_UnlockSurface(surf); SDL_Flip(surf); ++frames; print_fps(); }
}
int main(void) {
SDL_Surface *surf = NULL; srand((unsigned int)time(NULL)); SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO); surf = SDL_SetVideoMode(320, 240, 8, SDL_DOUBLEBUF | SDL_HWSURFACE); blit_noise(surf);
}</lang>
C#
Max 185 FPS on .NET 4.0/Windows 7 64-bit on Athlon II X4 620 - ATI Radeon X1200.
<lang csharp>using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms;
class Program {
static Size size = new Size(320, 240); static Rectangle rectsize = new Rectangle(new Point(0, 0), size); static int numpixels = size.Width * size.Height; static int numbytes = numpixels * 3;
static PictureBox pb; static BackgroundWorker worker;
static double time = 0; static double frames = 0; static Random rand = new Random();
static byte tmp; static byte white = 255; static byte black = 0; static int halfmax = int.MaxValue / 2; // more voodoo! calling Next() is faster than Next(2)!
static IEnumerable<byte> YieldVodoo() { // Yield 3 times same number (i.e 255 255 255) for numpixels times.
for (int i = 0; i < numpixels; i++) { tmp = rand.Next() < halfmax ? black : white; // no more lists!
// no more loops! yield! yield! yield! yield return tmp; yield return tmp; yield return tmp; } }
static Image Randimg() { // Low-level bitmaps var bitmap = new Bitmap(size.Width, size.Height); var data = bitmap.LockBits(rectsize, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
Marshal.Copy( YieldVodoo().ToArray<byte>(),// source 0, // start data.Scan0, // scan0 is a pointer to low-level bitmap data numbytes); // number of bytes in source
bitmap.UnlockBits(data); return bitmap; }
[STAThread] static void Main() { var form = new Form();
form.AutoSize = true; form.Size = new Size(0, 0); form.Text = "Test";
form.FormClosed += delegate { Application.Exit(); };
worker = new BackgroundWorker();
worker.DoWork += delegate { System.Threading.Thread.Sleep(500); // remove try/catch, just wait a bit before looping
while (true) { var a = DateTime.Now; pb.Image = Randimg(); var b = DateTime.Now;
time += (b - a).TotalSeconds; frames += 1;
if (frames == 30) { Console.WriteLine("{0} frames in {1:0.000} seconds. ({2:0} FPS)", frames, time, frames / time);
time = 0; frames = 0; } } };
worker.RunWorkerAsync();
FlowLayoutPanel flp = new FlowLayoutPanel(); form.Controls.Add(flp);
pb = new PictureBox(); pb.Size = size;
flp.AutoSize = true; flp.Controls.Add(pb);
form.Show(); Application.Run(); }
}</lang>
D
<lang D>import std.stdio, std.random, sdl.SDL;
void main() {
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO); auto surface = SDL_SetVideoMode(320,240,8, SDL_DOUBLEBUF|SDL_HWSURFACE);
uint frameNumber, totalTime, lastTime; while (true) { SDL_LockSurface(surface); foreach (i; 0 .. surface.w * surface.h) (cast(ubyte*)surface.pixels)[i] = (uniform(0, 2) ? 255 : 0); SDL_UnlockSurface(surface); SDL_Flip(surface); frameNumber++;
uint time = SDL_GetTicks(); totalTime += time - lastTime; if (totalTime > 1000) { writeln("FPS: ", frameNumber / (totalTime / 1000.0)); totalTime = frameNumber = 0; } lastTime = time; }
}</lang> This D version shows about 155 FPS, while on the same PC the C version shows about 180 FPS.
Generating random bits with the C core.stdc.stdlib.rand the performance becomes about the same of the C version.
F#
This implementation includes two methods to update the pixels values. One uses unsafe methods and can do 350 fps on my machine, the second uses safe code to marshal the new values onto the bitmap data and can do 240 fps on the same machine. <lang fsharp>open System.Windows.Forms open System.Drawing open System.Drawing.Imaging open System.Runtime.InteropServices open System.Diagnostics open Microsoft.FSharp.NativeInterop
- nowarn "9"
let rnd = System.Random()
// Draw pixels using unsafe native pointer accessor. // This updates the bitmap as fast as possible. let drawbits_fast (size:int) (bits:BitmapData) =
let mutable (p:nativeptr<byte>) = NativePtr.ofNativeInt(bits.Scan0) for n = 0 to size-1 do let c = rnd.Next(2) * 255 NativePtr.set p 2 (byte c) NativePtr.set p 1 (byte c) NativePtr.set p 0 (byte c) NativePtr.set p 3 (byte 255) p <- NativePtr.add p 4
// A reasonably efficient updater using marshalling to copy an array of generated // integers onto the managed bitmap pixel data (see the C# example as well). let drawbits_safe (size:int) (bits:BitmapData) =
let data = Array.init size (fun n -> let c = rnd.Next(2) * 255 0xff000000 ||| (c <<< 16) ||| (c <<< 8) ||| c) Marshal.Copy(data, 0, bits.Scan0, size) |> ignore
// Create a new bitmap and update using the specified function let make_image (width:int) (height:int) f =
let size = width * height let bmp = new Bitmap(width, height) let bits = bmp.LockBits(Rectangle(0,0,width,height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb) f size bits bmp.UnlockBits(bits) bmp
// Draw 30 frames and record the time and display the frames per second // This function is run asynchronously to avoid blocking the main GUI thread. let drawImage (box:PictureBox) (label:Label) f = async {
while true do let timer = new Stopwatch() timer.Start() for frames = 0 to 29 do let bmp = make_image 320 240 f box.Image <- bmp timer.Stop() let fps = 30000. / timer.Elapsed.TotalMilliseconds label.Text <- sprintf "%.1f fps" fps }
[<System.STAThread>] [<EntryPoint>] let main args =
let form = new Form(AutoSize=true, Size=new Size(0,0), Text="image noise demo") let panel = new FlowLayoutPanel(AutoSize=true,FlowDirection=FlowDirection.TopDown) let box = new PictureBox(AutoSize=true) let label = new Label(AutoSize=true, Text="Ready") form.FormClosed.Add(fun eventArgs -> Async.CancelDefaultToken() Application.Exit()) form.Controls.Add(panel) panel.Controls.Add(box) panel.Controls.Add(label) if args.Length > 0 && args.[0] = "-safe" then drawImage box label drawbits_safe |> Async.Start else drawImage box label drawbits_fast |> Async.Start form.Show() Application.Run() 0
</lang>
Factor
By some reason, FPS does not show during execution on Linux.
Max 2 FPS on Factor 0.94 x86-64/Windows 7 64-bits - Athlon II X4 620 - ATI Radeon X1200.
<lang factor>USING: namespaces ui ui.gadgets ui.gadgets.buttons ui.gadgets.tracks ui.gadgets.borders images images.viewer models timers accessors kernel sequences sequences.deep byte-vectors random calendar io math math.functions math.parser prettyprint debugger system ; FROM: models => change-model ;
IN: imagenoise
TUPLE: imgmodel < model content ; SYMBOL: dispimg SYMBOL: num SYMBOL: ttime
- randimg ( -- img )
<image> { 320 240 } >>dim RGB >>component-order ubyte-components >>component-type
dup dim>> product [ { 255 0 } random 3 swap <repetition> ] replicate flatten >byte-vector >>bitmap ;
randimg imgmodel new-model dispimg set-global 0 num set-global 0 ttime set-global
[
now
dispimg get-global [ drop randimg ] change-model num get-global 1 + num set-global now swap time- duration>seconds ttime get-global + ttime set-global num get-global 10 <= [ ] [ num get-global ttime get-global [ / round number>string " FPS" append ] try print
0 num set-global 0 ttime set-global ] if
] 1 nanoseconds every
[ vertical <track>
dispimg get-global <image-control> { 5 5 } <border> f track-add "Test" open-window
] with-ui</lang>
J
<lang j>coclass'example' (coinsert[require)'jzopengl'
P=: 0 : 0 pc p nosize; xywh 0 0 160 120;cc c isigraph opengl; pas 0 0;pcenter; rem form end;
pshow; timer 1;
)
timestamp=: (6!:8) %~ 6!:9
create=:3 :0
ogl=:conew'jzopengl' frames=:0 start=: timestamp sys_timer_base_=: 1 :('p_c_paint_',(;coname),'_') wd P
)
p_run=: 3 : 0
conew'example'
)
destroy=:3 :0
end=:timestamp smoutput 'frames per second: ',":frames%end-start wd 'timer 0' destroy__ogl wd'pclose' codestroy
)
p_close=: destroy
p_c_paint=: 3 : 0
rc__ogl glClear GL_COLOR_BUFFER_BIT glBegin GL_POINTS glVertex _1+2*53050 2?@$ 0 glEnd show__ogl frames=:frames+1
)
p_run</lang>
The script auto-starts when run (that last line p_run''
is responsible for the auto-start.
Average FPS are displayed when the window is closed.
With this revision, on my laptop, I typically get in the range of 58..59 FPS, with a cpu load from J of about 3% (sometimes as much as 5%, sometimes as low as 0.1%). I am probably limited by v-sync, and (hypothetically speaking) if I tuned my opengl drivers I perhaps could get significantly faster fps. However, since my screen only refreshes approximately 60 times per second, anything over that would be meaningless.
About some of the constants: 160 120 corresponds to a 320 by 240 rendering area (this mechanism will be obsolete soon, but I think we should wait for the new code bases stabilize before replacing this code), and the rendering area is not resizable. 53050 was picked because on average half of the pixels will be dark and half of them will be light: We have a black background and 53050 random pixel coordinates (out of 75800 total pixels) being set to being light -- because so many of them will randomly overlap we have on average approximately 50% of each. It would be more efficient to use a pixel shader, pushing the randomizing process into the graphics hardware. But, with this small of a display, efficiency is not really an issue with this approach.
JavaScript
<lang javascript><body>
<canvas id='c'></canvas> <script>
var canvas = document.getElementById('c'); var ctx = canvas.getContext('2d');
var w = canvas.width = 320; var h = canvas.height = 240; var t1 = new Date().getTime(); var frame_count = 0; ctx.font = 'normal 400 24px/2 Unknown Font, sans-serif'; var img = ctx.createImageData(w,h);
function animate() {
for (var x = 0; x < w; x++) { for (var y = 0; y < h; y++) { var index = 4* (x + w*y); var value = (Math.random() > 0.5) ? 255 : 0; img.data[index] = value; img.data[index+1] = value; img.data[index+2] = value; img.data[index+3] = 255; } } ctx.putImageData(img,0,0);
frame_count++; var fps = frame_count / (new Date().getTime() - t1) * 1000; ctx.fillStyle = "red"; ctx.fillText(fps.toFixed(2) + " fps", 20, 40);
setTimeout(animate, 0);
}
animate();
</script>
</body></lang>
OCaml
with the ocaml-sdl bindings: <lang ocaml>let frames =
{ contents = 0 }
let t_acc =
{ contents = 0 }
let last_t =
{ contents = Sdltimer.get_ticks () }
let print_fps () =
let t = Sdltimer.get_ticks () in let dt = t - !last_t in t_acc := !t_acc + dt; if !t_acc > 1000 then begin let el_time = !t_acc / 1000 in Printf.printf "- fps: %g\n%!" (float !frames /. float el_time); t_acc := 0; frames := 0; end; last_t := t
let blit_noise surf =
let ba = Sdlvideo.pixel_data_8 surf in let dim = Bigarray.Array1.dim ba in let rec aux () = for i = 0 to pred dim do ba.{i} <- if Random.bool () then max_int else 0 done; Sdlvideo.flip surf; incr frames; print_fps (); aux () in aux ()
let blit_noise surf =
try blit_noise surf with _ -> Sdl.quit ()
let () =
Sdl.init [`VIDEO; `TIMER]; Random.self_init(); let surf = Sdlvideo.set_video_mode ~w:320 ~h:240 ~bpp:8 [(*`HWSURFACE;*) `DOUBLEBUF] in Sys.catch_break true; blit_noise surf</lang>
compile to native-code with:
ocamlopt bigarray.cmxa -I +sdl sdl.cmxa noise_fps_sdl.ml -o noise_fps_sdl.opt
or using findlib:
ocamlfind opt -linkpkg -package sdl noise_fps_sdl.ml ./a.out
compile to bytecode with:
ocamlc bigarray.cma -I +sdl sdl.cma noise_fps_sdl.ml -o noise_fps_sdl.byte
In script mode, run with:
ocaml bigarray.cma -I +sdl sdl.cma noise_fps_sdl.ml
In a more idiomatic way, using the modules Graphics and Unix from the standard OCaml library: <lang ocaml>open Graphics
let white = (rgb 255 255 255) let black = (rgb 0 0 0)
let t_last = ref (Unix.gettimeofday())
let () =
open_graph ""; let width = 320 and height = 240 in resize_window width height; try while true do for y = 0 to pred height do for x = 0 to pred width do set_color (if Random.bool() then white else black); plot x y done; done; let t = Unix.gettimeofday() in Printf.printf "- fps: %f\n" (1.0 /. (t -. !t_last)); t_last := t done with _ -> flush stdout; close_graph ()</lang>
run this script with:
ocaml unix.cma graphics.cma g.ml
And using an OCaml-Xlib bindings, or an OCaml-Allegro binding.
PicoLisp
This solution works on ErsatzLisp, the Java version of PicoLisp. It creates a 'JFrame' window, and calls inlined Java code to handle the image. <lang PicoLisp>(javac "ImageNoise" "JPanel" NIL
"java.util.*" "java.awt.*" "java.awt.image.*" "javax.swing.*" ) int DX, DY; int[] Pixels; MemoryImageSource Source; Image Img; Random Rnd;
public ImageNoise(int dx, int dy) { DX = dx; DY = dy; Pixels = new int[DX * DY]; Source = new MemoryImageSource(DX, DY, Pixels, 0, DX); Source.setAnimated(true); Img = createImage(Source); Rnd = new Random(); }
public void paint(Graphics g) {update(g);} public void update(Graphics g) {g.drawImage(Img, 0, 0, this);}
public void draw() { for (int i = 0; i < Pixels.length; ++i) { int c = Rnd.nextInt(255); Pixels[i] = 0xFF000000 | c<<16 | c<<8 | c; } Source.newPixels(); paint(getGraphics()); }
/**/
(de imageNoise (DX DY Fps)
(let (Frame (java "javax.swing.JFrame" T "Image Noise") Noise (java "ImageNoise" T DX DY) Button (java "javax.swing.JButton" T "OK") ) (java Frame "add" Noise) (java Frame "add" "South" Button) (java Button "addActionListener" (interface "java.awt.event.ActionListener" 'actionPerformed '((Ev) (bye)) ) ) (java Frame "setSize" DX DY) (java Frame "setVisible" T) (task (/ -1000 Fps) 0 Image Noise (java Image "draw") ) ) )
- Start with 25 frames per second
(imageNoise 320 240 25)</lang>
PureBasic
<lang PureBasic>#filter=0.2 ; Filter parameter for the FPS-calculation
- UpdateFreq=100 ; How often to update the FPS-display
OpenWindow(0,400,300,320,240,"PureBasic") Define w=WindowWidth(0), h=WindowHeight(0) Define x, y, T, TOld, FloatingMedium.f, cnt InitSprite() OpenWindowedScreen(WindowID(0),0,0,w,h,1,0,0,#PB_Screen_NoSynchronization) Repeat
StartDrawing(ScreenOutput()) For y=0 To h-1 For x=0 To w-1 If Random(1) Plot(x,y,#Black) Else Plot(x,y,#White) EndIf Next Next StopDrawing() FlipBuffers() cnt+1 If cnt>=#UpdateFreq cnt =0 TOld=T T =ElapsedMilliseconds() FloatingMedium*(1-#filter)+1000*#filter/(T-TOld) SetWindowTitle(0,"PureBasic: "+StrF(#UpdateFreq*FloatingMedium,2)+" FPS") Repeat ; Handle all events Event=WindowEvent() If Event=#PB_Event_CloseWindow End EndIf Until Not Event EndIf
Python
Max 23 FPS on Python 2.7 (r27:82525 MSC v.1500 32 bit Intel), Windows 7 64-bit on Athlon II X4 620 - ATI Radeon X1200.
<lang python>import Tkinter import Image, ImageTk import random import time
size = (320,240) pixels = size[0] * size[1]
class App():
def __init__(self, root): self.root = root self.root.title("Test") self.img = Image.new("RGB",size) self.label = Tkinter.Label(root) self.label.pack()
self.time = 0.0 self.frames = 0 self.loop() def loop(self): self.ta = time.time() # 13 FPS boost. half integer idea from C#. self.img.putdata([(255,255,255) if random.random() > 0.5 else (0,0,0) for i in range(pixels)]) self.pimg = ImageTk.PhotoImage(self.img) self.label["image"] = self.pimg self.tb = time.time() self.time += (self.tb - self.ta) self.frames += 1
if self.frames == 30: try: self.fps = self.frames / self.time except: self.fps = "INSTANT" print "%d frames in %3.2f seconds (%s FPS)" % (self.frames, self.time, self.fps) self.time = 0 self.frames = 0 self.root.after(1, self.loop)
root = Tkinter.Tk() app = App(root) root.mainloop()</lang>
Tcl
<lang tcl>package require Tk
proc generate {img width height} {
set data {} for {set i 0} {$i<$height} {incr i} {
set line {} for {set j 0} {$j<$width} {incr j} { lappend line [lindex "#000000 #FFFFFF" [expr {rand() < 0.5}]] } lappend data $line
} $img put $data
}
set time 0.0 set count 0
proc looper {} {
global time count set t [lindex [time {generate noise 320 240}] 0] set time [expr {$time + $t}] if {[incr count] >= 30} {
set time [expr {$time / 1000000.0}] set fps [expr {$count / $time}] puts [format "%d frames in %3.2f seconds (%f FPS)" $count $time $fps] set time 0.0 set count 0
} after 1 looper
}
image create photo noise -width 320 -height 240 pack [label .l -image noise] update looper</lang>