DEV Community

Cover image for Dog Vision: I Made My Camera See Like a Dog (And Now I Can't Unsee It)
Courage Labhani Paul
Courage Labhani Paul Subscriber

Posted on

Dog Vision: I Made My Camera See Like a Dog (And Now I Can't Unsee It)

DEV Weekend Challenge: Dog Days Edition Submission πŸ•

This is a submission for Weekend Challenge: Dog Days Edition

What I Built

I built Dog Vision, a little browser app that takes your camera feed (or a photo you upload) and shows you two versions side by side: what you see, and roughly what a dog would see looking at the same thing.

The short version of why dogs see the world differently: they only have two types of color-detecting cone cells in their eyes, while humans have three. That means the reds and greens that look totally different to us blend together for them, and their world leans heavily blue and yellowish-brown instead. On top of that, their visual acuity is worse than ours, somewhere around 20/75, so things look a bit softer too.

Demo

Point your camera at literally anything (your dog, your red mug, your questionable fashion choices) and watch the "dog" panel update live. No camera handy? Upload a photo instead, the app handles both. There's also a "Save Comparison" button that exports a side by side PNG, because obviously you're going to want to send this to your group chat.

best tech writer

πŸ”— Live demo: https://couragecodejourney.github.io/Dog_Vision/

(Heads up: camera access needs you to allow permissions, and works best on desktop Chrome/Edge. No camera handy? Use the Upload Photo button instead.)

Repo

https://github.com/CourageCodeJourney/Dog_Vision

How I Built It

No frameworks, just HTML, CSS, and JavaScript. It's a weekend project and I like sleep. Two <canvas> elements carry the whole thing: one draws the untouched frame, the other draws a filtered one, and both get redrawn on every animation frame while the camera is live.

The part I actually spent time thinking about was making the "dog" filter feel like it was modeling something real, instead of being an Instagram filter with a science-y label slapped on it.

Why dogs see the way they do, and how I modeled it: Dogs are dichromats. They have two types of color-sensing cone cells instead of the three humans have, one tuned to blue-violet light and one tuned to yellow-green. What that means practically is they can't tell red and green apart the way we can, since those colors both land on the cone type they're missing. My first pass at simulating this was embarrassingly naive: "if the pixel leans blue, boost blue, otherwise push it yellow." It looked plausible on camera, but it wasn't modeling the actual biology, it was just vibes with extra steps.

So I rebuilt it as a small transform matrix applied per pixel:

let nr = 0.625 * r + 0.375 * g;
let ng = 0.7 * r + 0.3 * g;
let nb = 0.3 * g + 0.7 * b;
Enter fullscreen mode Exit fullscreen mode

This collapses the red-green axis (the one dogs genuinely can't resolve) while keeping the blue-yellow axis intact, which is the same general math used to simulate red-green colorblindness in humans since it's the closest human analog we have to canine color vision. I'm upfront in the app itself that this is a stylized approximation, not a lab-calibrated model, canine color science is still an active research area and I'm not going to pretend a weekend project nailed it. But it's a simplification made on purpose, not a guess.

Why the blur runs at draw time instead of pixel by pixel: dogs also have lower visual acuity than we do, roughly 20/75, so their world looks softer, not just recolored. My first version of that softness was a hand-rolled box blur, looping over every pixel and averaging its neighbors, running on every single frame. It worked fine on my machine, and then I pictured it running live on someone's five-year-old laptop and immediately regretted it. I moved the blur onto the canvas's built-in filter property instead:

dogCtx.filter = 'blur(1.4px)';
dogCtx.drawImage(source, 0, 0, W, H);
Enter fullscreen mode Exit fullscreen mode

Same visual effect, but it's GPU-accelerated instead of a JS loop fighting the render thread, so it stays smooth on a live camera feed instead of choking on it.

Everything else is UI plumbing: camera permission handling with a visible fallback message (camera access needs HTTPS or localhost, and fails silently otherwise, so I added a hint rather than let people wonder what broke), file upload as a no-camera alternative, and a snapshot export that stitches both canvases into one downloadable side-by-side PNG.

Anyway, if your dog is reading this over your shoulder: yes, your favorite red ball probably looks like a sad gray rock to you. I'm sorry. The tennis ball was always going to win.

Top comments (2)

Collapse
 
paulthedev profile image
Courage Labhani Paul

Okay, but I genuinely want to see your results, comment your comparison shots....🐢

Collapse
 
paulthedev profile image
Courage Labhani Paul

mine