The full Canny pipeline, ending in Hough-detected lines and circles.
A noisy painted room goes through Canny edge detection one stage at a time. A separable Gaussian blur removes the noise, Sobel kernels measure the gradient (shown with hue for direction and brightness for strength), non-maximum suppression thins every ridge to one pixel, and hysteresis keeps weak edges only when they connect to strong ones, animated as a flood from the strong seeds. The surviving pixels become line art, then vote in two Hough transforms: each pixel traces a sinusoid in (theta, rho) space whose peaks are straight segments, and votes along its gradient for circle centres whose best radius comes from a radial histogram.
Try it. Click a stage or press 1 to 7. Drag the blur, low and high threshold sliders and the whole pipeline reruns live. Hover the image for a magnifier that shows gradient vectors in the gradient stages. In the Hough stage, hovering draws that pixel's sinusoid in (theta, rho) space and lights up every detected segment it lies on.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a step-by-step Canny edge detector with JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Paint a 320 x 200 test scene in code: a window with a cross-shaped frame, a round wall clock, a shelf of books and a couple of round fruits on a desk. Add some random noise to every pixel and convert to greyscale.
- Blur it with a separable Gaussian (build a 1D kernel from sigma, run it horizontally then vertically).
- Compute Sobel gradients gx and gy, then magnitude and angle.
- Non-maximum suppression: round the angle to one of four directions and keep a pixel only if its magnitude is at least that of both neighbours along that direction.
- Hysteresis: pixels above a high threshold are edges; pixels above a low threshold are edges only if they connect (8-way) to one. Use a queue flood fill.
- Show the stages with buttons and draw each one scaled up with drawImage.
Once that works, make it beautiful:
- Draw the gradient stage with hue for direction and brightness for magnitude.
- Add sliders for sigma and both thresholds that rerun the pipeline live.
- Add a Hough transform: every edge pixel adds a vote to (theta, rho) for 180 angles. Show the accumulator as an image (sinusoids!), find local maxima and draw the detected lines over the edges.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as a Hough transform for circles using the gradient direction, animating the hysteresis flood, or loading my own photo from a file input.