Edge Detection
Run Sobel, Prewitt and Laplacian kernels on a real image, step through every stage of the Canny detector, and check the arithmetic at any pixel.
A 160×120 grayscale test image generated in the browser. Tap any image to inspect a pixel.
Gx and Gy: orange = brightness increases (right / down), blue = it decreases. Direction: hue encodes the angle of the gradient (red → right, yellow-green → down, cyan → left, violet → up), brightness encodes strength.
Pixel inspector at (71, 45)
The 3×3 neighbourhood of the original image around the tapped pixel, and the exact arithmetic the kernel performs there.
Neighbourhood
Gx kernel
pixel × weight
sum
Gx = -540
(-229) + 96 + (-456) + 190 + (-231) + 90 = -540
Gy kernel
pixel × weight
sum
Gy = -4
(-229) + (-180) + (-96) + 231 + 180 + 90 = -4
|G| = √(Gx² + Gy²) = √(-540² + -4²) = 540.0
θ = atan2(Gy, Gx) = -179.6°
What edge detection does
An edge is a place where image brightness changes quickly. Edge detectors estimate the derivative of the image with small kernels: a 3×3 grid of weights slid over every pixel. Sobel and Prewitt estimate the first derivative in x and y separately, giving a gradient vector with a strength (magnitude) and a direction. The Laplacian estimates the second derivative, which is zero right at the middle of an edge.
Every image on this page is computed for real in your browser from the pixel values: nothing is pre-rendered. The only simplification is the size (160×120 pixels) so the pipeline reruns instantly when you move a slider.
An edge is a fast change
Gradients have a direction
Derivatives amplify noise
Canny adds decisions
Key formulas
Gradient magnitude and direction
|G| = √(Gx² + Gy²), θ = atan2(Gy, Gx)
- Gx, Gy
- responses of the horizontal and vertical kernels at a pixel
- |G|
- edge strength
- θ
- direction of fastest brightness increase (edge runs at θ + 90°)
Applying a 3×3 kernel
G(x, y) = Σi,j ∈ {-1,0,1} K(i, j) · I(x + i, y + j)
- K
- the kernel weights
- I
- image brightness
Gaussian blur used by Canny
g(x) = e−x² / 2σ² / Σ e−k² / 2σ²
- σ
- standard deviation: larger σ smooths more and keeps only bigger edges
The Canny pipeline
- Blur with a Gaussian of width σ to suppress noise.
- Gradient: Sobel Gx and Gy, then magnitude and direction.
- Non-maximum suppression: round the direction to 0°, 45°, 90° or 135° and keep a pixel only if its magnitude is at least as large as both neighbours along that direction.
- Double threshold: above
highis strong, betweenlowandhighis weak, belowlowis dropped. - Hysteresis: keep weak pixels only if they are connected (8-neighbourhood) to a strong pixel.
| Detector | Kernel | Measures | Noise handling |
|---|---|---|---|
| Sobel | [-1 0 1; -2 0 2; -1 0 1] | First derivative, with built-in smoothing across the edge | Moderate |
| Prewitt | [-1 0 1; -1 0 1; -1 0 1] | First derivative, plain average across the edge | Slightly worse than Sobel |
| Laplacian | [0 1 0; 1 -4 1; 0 1 0] | Second derivative, all directions at once | Poor: amplifies noise |
| Canny | Gaussian + Sobel + NMS + hysteresis | Thin, connected edge map | Good, tuned by σ |
How to use this visualizer
- 1Start in Gradient operators mode and switch between Sobel, Prewitt and Laplacian. Compare Gx, Gy, magnitude and the direction (hue) image.
- 2Raise the noise slider and watch the Laplacian fill with speckle much sooner than Sobel.
- 3Tap any image to move the inspector. It shows the 3×3 neighbourhood, each kernel weight times its pixel, and the sum.
- 4Switch to Canny pipeline. Step through the five stages with the buttons or thumbnails.
- 5Increase σ to remove noise edges (and fine detail). Move the low and high thresholds and watch which weak pixels survive hysteresis.
- 6Use your own image with the upload button. It is converted to grayscale locally and never uploaded.
Code
// Sobel gradient at pixel (x, y) of a grayscale image (values 0..255)
const KX = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]];
const KY = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];
function sobelAt(img, x, y) {
let gx = 0, gy = 0;
for (let j = -1; j <= 1; j++) {
for (let i = -1; i <= 1; i++) {
const v = img.get(x + i, y + j); // clamp at the borders
gx += KX[j + 1][i + 1] * v;
gy += KY[j + 1][i + 1] * v;
}
}
return { magnitude: Math.hypot(gx, gy), angle: Math.atan2(gy, gx) };
}Practice problems
Problem 1: Sobel by hand
[10 10 10; 10 10 10; 90 90 90] (rows top to bottom). Compute Gx, Gy, |G| and θ with the Sobel kernels.Show solutionHide solution
Gx: every row is constant, so (−1·10 + 1·10) etc. sums to 0. Gx = 0.
Gy = −1·10 −2·10 −1·10 + 1·90 + 2·90 + 1·90 = −40 + 360 = 320.
|G| = √(0² + 320²) = 320.
θ = atan2(320, 0) = 90°: brightness increases downward.
A horizontal edge, strength 320, gradient pointing down.
Problem 2: Which pixels survive?
30, 70, 140, 60, 0, all 8-connected in a line. With low = 50 and high = 120, which pixels are in the final Canny edge map?Show solutionHide solution
Classify: 30 → dropped, 70 → weak, 140 → strong, 60 → weak, 0 → dropped.
Hysteresis starts at the strong pixel (140) and grows into connected weak neighbours: 70 and 60.
Final edge: the pixels with 70, 140 and 60.
If the 140 were 110 instead, there would be no strong pixel and the whole run would be dropped.
Discussion
Questions, ideas or a different approach? Join the conversation.