Blog
Learn computer vision by running it: explainers, interactive demos, runnable Python & C++, and honest benchmarks. Newest first.
Edge Deployment Build a computer-vision plugin for OBS Studio, and measure what every frame costs
A step-by-step OBS Studio video filter in C++ on OpenVINO, split so the model swaps without touching the plumbing, and measured stage by stage: getting pixels off the GPU, where inference has to live so OBS never drops a frame, and what the trip from camera to virtual camera costs.
Evaluation How to build a rep counter that does not count your rest
A step-by-step build of exercise repetition counting on MediaPipe pose landmarks, in the browser. Each design decision is settled with a measurement: why the joint angle comes from world landmarks, why the 1 euro filter beats an exponential moving average by 44 percent at a 100 ms lag budget, and why one threshold turns six push-ups into twenty.
Models & Detection Reproducing a published pupil-diameter model, and running it in the browser
An independent run of Shah et al.'s released PupilSense checkpoints over all 424,000 EyeDentify crops, then the whole thing converted to ONNX and put in a browser tab: what the quantisation costs, what the preprocessing port costs, where the compute goes, and what I would change to make it both cheaper and more trustworthy.
Fundamentals An Image Is an Array: Shape, dtype, and Why OpenCV Hands You BGR
Lesson 1 of The Image as Data. One photograph, held three ways: a 24.7 MB mosaic of 12-bit counts, a 74.2 MB 16-bit development, and the 37.1 MB 8-bit array imread would give you. Two thirds of the numbers in that last one were never measured, adding 60 to a value of 207 gives 11, and a slice you write into changes the original.
Fundamentals From Photons to Counts: What a Raw Number Means
A photosite collects electrons, a converter turns them into an integer, and that integer is all any algorithm ever sees. Measured on eighteen exposures of one scene: the count doubles with the shutter to within a few percent, then sticks near 3875 DN — and the ceiling the file declares is not the ceiling the sensor has.
Fundamentals High Dynamic Range: Merging a Bracket, Then Checking It Against a Meter
Eighteen exposures of a 17-stop scene, merged into one radiance map, calibrated with a single scale factor fitted on one patch — and then compared with the colorimeter readings taken in the room. The other 47 points land a median of 0.198 stops away, 0.109 stops across the neutral patches, and every large error is at the dark end.
Fundamentals Image Formation: How a Camera Flattens the World Onto a Sensor
The unit overview: why a pinhole gives a sharp picture and a lens gives a bright one, what focus costs you, and where the pinhole model stops describing the lens in front of you. Measured on public photographs: a real lens moves a corner 51 px, stopping down from f/4 to f/22 deepens focus 5.54x, and a fisheye fitted with the wrong model misses by 7.3 px against 0.64 px with the right one.
Fundamentals How Close Is Your Colour to the Real Thing?
Lesson 5 of The Image as Data. Converting between colour spaces is exact arithmetic; deciding what the numbers mean physically is a fit. Checked against a colorimeter on 22 chart patches: treating the developed file as sRGB lands 9.54 ΔE*ab from the light in the room, the camera's own published matrix does no better, and a 3x3 fitted here and scored on patches it never saw reaches 2.41.
Fundamentals File Formats: What the Encoder Did Before You Read the Pixels
Lesson 5 of The Image as Data. A JPEG quality sweep costs almost nothing in PSNR and takes Canny's edge agreement from 0.949 to 0.895. Chroma subsampling saves 40% of the bytes for 0.09 of ΔE. And OpenCV and Pillow decode every JPEG here bit-for-bit identically — the disagreement is a 16-bit PNG, which Pillow silently opens as 8-bit.