Image noise
You are encouraged to solve this task according to the task description, using any language you may know.
Generate a random black and white 320x240 image continuously, showing FPS (frames per second).
Sample image:
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>
Factor
Still learning Factor, my code may suck, please fix.
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*16000 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 of about 3% (so I am probably limited by v-sync, and if I tuned my opengl drivers I perhaps could get significantly faster fps?).
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
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>