NURLNURL registrynurl-lang.org →

← objdet

objdet 0.3.1 API

detect.nu

packages/objdet/src/detect.nu — tiny-YOLOv2 detection head.

Decodes the [1,125,13,13] grid the network produces into boxes: each of the 13×13 cells predicts 5 anchor boxes, each carrying (tx,ty,tw,th,to)

sigmoid/exp; the score is objectness × softmax(class). Overlapping boxes of the same class are then removed by non-max suppression.

API

& c @ nurl_peek_f32 *u base i idx → f

: Detection { i cls f score f cx f cy f w f h }

A detection in normalised (0..1) centre/size coordinates.

@ sigmoid f x → f

@ voc_class i i → s

VOC 2007 20 classes (tiny-yolov2 order). Static literals — the old version built a fresh Vec String per call and returned a borrow into it (leaked the vector every lookup).

@ yolo_decode * u grid f thresh → ( Vec Detection )

Decode the grid into detections above thresh.

@ yolo_nms ( Vec Detection ) dets f iou_thresh → ( Vec Detection )

Non-max suppression: sort by score, greedily keep, drop same-class boxes overlapping a kept box by more than iou_thresh.


image.nu

packages/objdet/src/image.nu — detector-facing adapter over packages/image.

The codecs and raster ops live in the image package (PNG/JPEG/PPM decode, bilinear resize, rectangle drawing — see deps/image); this file keeps only what is detector-specific: loading ANY supported format as guaranteed-RGB, saving by extension, saturating pixel stores, and packing to the NCHW float tensor the model consumes. The Image type is the image package's (width/height/channels/data).

API

& c @ nurl_poke_f32 *u base i idx f val → v

@ img_w Image im → i

@ img_h Image im → i

@ img_blank i w i h → Image

A blank (black) RGB image.

@ img_get Image im i x i y i ch → i

@ img_set Image im i x i y i ch i val → v

Saturating store (image_set masks to the low byte; the detector's callers pass computed values that must clamp, not wrap).

@ img_resize Image im i nw i nh → Image

@ img_load s path → ?Image

Load any supported format (PNG / baseline+progressive JPEG / PPM) as 3-channel RGB. On None, ( image_error ) says why.

@ img_save s path Image im → b

Save by extension: .png / .jpg / .jpeg (quality 90) / anything else = PPM.

@ img_draw_rect Image im i x0 i y0 i x1 i y1 i r i gg i bb → v

Draw a thickness-2 rectangle outline in the given colour.

@ img_to_nchw Image im → *u

── pack to NCHW float tensor (values 0..255) ───────────────────── Writes a fresh host buffer of 3HW floats in CHW order; the model's in-graph preprocessor scales by 1/255.


main.nu

packages/objdet/src/main.nu — object detection from pure NURL on the GPU.

objdet <model.onnx> <image.{png,jpg,ppm}> [out.{png,jpg,ppm}] objdet <model.onnx> --video <in_dir> <out_dir> <count>

Loads any tiny-YOLOv2-style ONNX detector (e.g. the ONNX model-zoo tinyyolov2-8.onnx), runs it on the GPU through packages/onnx, decodes the grid into labelled boxes (packages objdet/detect), prints them, and (for an image) writes an annotated image. Stills are read/written natively via packages/image (PNG, baseline+progressive JPEG, PPM) — no ImageMagick. The video mode runs a frame sequence frame00000.ppm … reusing one GPU engine (kernels compiled once); use ffmpeg for the container: ffmpeg -i clip.mp4 -vf fps=10 in/frame%05d.ppm ffmpeg -framerate 10 -i out/frame%05d.ppm out.mp4

API

@ p s m → v

@ pf f x → v

@ pn i n → v

@ streqm s a s b → b

@ shape4 i a i b i c i d → ( Vec i )

@ detect_image * Engine e OGraph g Image im f conf f iou → i

Run the detector on one image, draw boxes in place, print detections. Returns the number of detections.

@ load_model s path * u pok → OGraph

@ frame_path s dir i n → String

frame path: <dir>/frameNNNNN.ppm

@ main → i


wasm_detect.nu

wasm_detect.nu — tiny-YOLOv2 object detection as a wasm32-wasi module, running on the browser GPU via the gpu package's WebGPU backend (WGSL compute shaders). A WASI command driven by host imports: the embedder (a web worker — see web/objdet_worker.js) feeds the model and 416×416 frames, the module loops inside start decoding YOLO boxes and handing them back. The whole detector — conv/bn/leakyrelu/maxpool — runs on the GPU with no server; only gpudownload (the grid readback) is async, bridged by Asyncify.

host_blob_size(0)/read(0) → model.onnx bytes host_frame(nchw, ctl) → cmd 0 = frame ready (nchw = 3416416 f32, raw 0-255 CHW), else exit. ctl[0] = conf‰. host_result(dets, nd) nd boxes: 6 f32 each [cls, score, cx, cy, w, h] (0..1 coords). host_status(code, extra) 1 model-parsed, 2 engine-ready, -1 fatal.

API

& c @ host_blob_size i kind → i

& c @ host_blob_read i kind *u dst → i

& c @ host_frame *u nchw *u ctl → i

& c @ host_result *u dets i nd → v

& c @ host_status i code i extra → v

: i OD_N 416

: i OD_MAXDET 64

@ od_shape4 i a i b i c i d → ( Vec i )

@ main → i