Edge Detection
Edge detection finds locations where image brightness changes sharply. Sobel compares brightness on opposite sides of a small neighborhood, measures how much the two sides differ, and lets a threshold select strong changes. Flat regions cancel even when they are bright; noise can produce edges too.
Think of the filter as a balance with pixels on each side. Equal brightness balances out. A dark region beside a bright one tips the balance. Reverse the two regions and the balance tips the other way, by the same amount. That distinction between direction and amount is the reason Sobel keeps signed derivatives until it computes edge strength.
How Sobel Edge Detection Works
An image is a grid of brightness values. This example uses a synthetic 7×7 grid with intensities from 0 (dark) to 8 (bright), small enough to calculate by hand. The filter examines a 3×3 neighborhood around each interior pixel. Its horizontal and vertical kernels are:
Kx = -1 0 1 Ky = -1 -2 -1
-2 0 2 0 0 0
-1 0 1 1 2 1
Multiply each patch value by the coefficient in the same position, then add the nine products. For Kx, this is a weighted right column minus a weighted left column; the middle row counts twice. Ky compares the bottom row with the top row, giving the middle column double weight. These weights also smooth across the direction perpendicular to the difference.
The horizontal derivative Gx responds to brightness changes as you move left to right, so it detects a vertical boundary. Gy responds as you move top to bottom, so it detects a horizontal boundary. The direction of the derivative and the orientation of the edge are perpendicular. Confusing the two makes choosing a filter harder than it needs to be.
Combine both responses with M = √(Gx² + Gy²). This is edge strength, not a probability. A large negative derivative counts just as much as a large positive one. The threshold rule here is M > 0 and M >= threshold: keep nonzero responses at or above the chosen threshold. The extra nonzero condition keeps flat regions out when the threshold is zero.
The displayed kernels are applied as sliding dot products without flipping them, often called cross-correlation in mathematical terminology. Rows increase downward, columns rightward. No normalization factor is applied, so thresholds are in these unscaled response units. The OpenCV Sobel formulation gives the same two kernels and Euclidean magnitude formula.
Edge Detection Step by Step
The default image repeats this row seven times:
0 0 0 8 8 8 8
The threshold is 16. Coordinates below are zero-based source coordinates. Only centers in rows and columns 1 through 5 have a complete 3×3 neighborhood, so the output is 5×5. The border is excluded; it is not silently filled with zero responses.
1. Read the flat patch centered at (3,1). Its nine pixels are zero. Both sides of each balance carry zero, so Gx = 0, Gy = 0, and M = 0. Write zero to output (2,0). A calculated zero is different from a cell that has not been visited.
2. Move one column right to (3,2). Each patch row is [0,0,8]. Multiplying by Kx gives:
0 0 8
0 0 16
0 0 8
The horizontal balance has 32 on the right and zero on the left, so Gx = 32. The vertical balance stays level: Ky gives a top-row contribution of −8 and a bottom-row contribution of +8, which cancel; the middle row has zero weights. Thus Gy = 0, and M = √(32² + 0²) = 32. Write that strength to output (2,1).
3. Fill the remaining 23 positions, grouped into five rows. The two probes establish the arithmetic; the rest reuse the same kernels. Every output row becomes [0,32,32,0,0]. The animation revisits centers (3,2) and (3,3): their patch rows are [0,0,8] and [0,8,8]. Both windows cross the boundary. The middle column has zero Kx weight, so moving the window one column changes neither weighted side: both have Gx=32 and Gy=0. That is why two output columns respond. The bright area farther right still produces zero: equal positive and negative weighted brightness cancels there too.
4. Apply threshold 16. Each strength of 32 passes and each zero fails. The mask contains ten retained cells: two columns across five rows. Those cells form a response band two pixels wide. A threshold does not thin it into a single-pixel contour.
5. Reverse the brightness. Replace every intensity I with 8-I. At (3,2), the horizontal response becomes −32 and the vertical response stays zero. The magnitude remains 32. Every magnitude in the full map is unchanged, so the mask is unchanged as well. For either kernel K, ΣK=0, so G(8-I) = ΣK(8-I) = 8ΣK - ΣKI = -G(I). The constant 8 balances out. Squaring the negated derivatives preserves their magnitude.
6. Calculate a noise neighbor in both directions. The next example explicitly switches to one intensity-8 pixel at (3,3) on a zero background. At center (2,2), that bright pixel sits at the bottom-right corner of the patch. Both kernels put weight 1 there, giving Gx=8 and Gy=8. Neither balance is level. The strength is √(8²+8²)=8√2≈11.3; using only |Gx| would understate it as 8.
7. Move to the axial neighbor at (2,3). Now the bright pixel is in the bottom-middle position: Kx puts weight 0 there, while Ky puts weight 2 there. Thus Gx=0, Gy=16, and M=16. Threshold 12 rejects the four diagonal responses and retains the four axial responses. A single noise pixel has produced four detected edges.
8. Compare the failure cases. The closing panels show the same weak image at thresholds 16 and 4, alongside the noise example at 12. They retain zero, ten, and four cells respectively. These are labeled comparison examples; the final frame returns to your selected input and threshold.
Choosing a Sobel Threshold
A threshold decides which measured changes matter to your application. Keep the image fixed when comparing thresholds; otherwise you cannot tell which change caused the result.
The weak-step pattern replaces the bright region's intensity 8 with 2. The edge response falls from 32 to 8. Threshold 16 removes it entirely; threshold 4 restores all ten responding cells. The boundary was present in both images. The decision discarded it.
Now use the noise-pixel pattern: one intensity-8 pixel at the center of an otherwise dark image. Its four axial neighbors have strength 16 and its four diagonal neighbors have strength 8√2, about 11.31. At threshold 12, four responses survive around the noise pixel, even though there is no extended object contour. Raising the threshold can remove these responses, but it can also remove weak edges you wanted. Additional denoising, edge thinning, and connected-edge reasoning solve different parts of that problem.
When to Use Sobel
Use Sobel when you need inexpensive, inspectable local gradients: an orientation or strength map, a baseline for an image-processing experiment, or input to a later feature-extraction stage. Keep Gx and Gy if that later stage needs direction. A thresholded Sobel map alone cannot tell an object boundary from a shadow or texture.
If you need thin edges with connectivity-based decisions, consider Canny's additional stages: noise reduction, non-maximum suppression, and hysteresis with two thresholds. Canny still needs parameter choices and does not recognize objects. Object labels or semantic boundaries require a task-specific recognition or segmentation method.
Carry the units into a real pipeline
For unchanged kernels, scaling image intensities by a positive factor a scales Gx, Gy, M, and an equivalent threshold by a. Scaling both kernels by s scales the strength and threshold by |s|. A constant intensity offset cancels in each valid window because its kernel sums to zero.
For example, mapping this demo's 0..8 values to 0..255 multiplies them by 255/8: the default strength 32 becomes 1020, and threshold 16 becomes 510. Mapping to 0..1 instead gives strength 4 and threshold 2. These are equivalent settings for the same rescaled image, not recommended thresholds for arbitrary photographs. Rounding into byte values can also change responses slightly.
Use a signed or floating-point derivative buffer; unscaled Sobel outputs can exceed the input's byte range. Fix preprocessing, kernel size, kernel scale, magnitude definition, and border policy before tuning a threshold. OpenCV exposes Sobel's scale, output depth, and border parameters. A different kernel size or a change from Euclidean magnitude to |Gx|+|Gy| changes the response definition; a single threshold conversion need not preserve every decision.
Time and Space Complexity
For a fixed 3×3 kernel, each interior pixel requires a constant number of multiplications and additions. The time complexity is O(HW) for an image of height H and width W. Storing the derivative, magnitude, and mask maps uses O(HW) space. The 3×3 kernels are separable: a one-dimensional difference and a perpendicular [1,2,1] smoothing pass give the same interior result. This permits two short filtering passes per derivative. Choose reflection, replication, or valid cropping deliberately at the border, then budget separately for denoising, thinning, or linking edges. A streaming implementation can retain fewer working rows; the animation additionally stores reveal snapshots so you can scrub backward.
Sobel Edge Cases
- Uniform brightness: all-dark and all-bright regions have zero gradient. Sobel measures differences, not brightness alone.
- Opposite polarity: bright-to-dark and dark-to-bright steps have opposite signs but equal magnitude when their contrast is equal.
- Horizontal boundaries: Gx alone misses a purely horizontal step. Gy supplies the missing component.
- Threshold equality: a nonzero response exactly equal to the threshold is retained. Comparisons use the full numeric value, not the rounded label.
- Threshold extremes: zero still excludes M=0. At 48, no response in these supported 0..8 patterns survives; 48 is a control range chosen for this teaching scale, not a universal Sobel limit.
- Image borders: this valid-window example omits the outer ring. Other implementations may reflect or replicate pixels at the boundary; that choice can change border responses.
Common Sobel Mistakes
Clipping a signed derivative to zero before computing magnitude loses evidence. The reversed default has Gx=−32. If you discard it, its strength becomes zero and a real brightness boundary vanishes. Preserve signed arithmetic, then square or take absolute values as required by the chosen magnitude definition.
Do not normalize each image's response map independently when comparing strength. A weak response can look as dark as a strong response if both are rescaled to their own maximum. This lesson uses one 0..48 strength scale across every pattern. Input brightness and output strength have separate legends.
Finally, an edge mask is not object recognition. Texture, shadows, sensor noise, and object boundaries can all change brightness. Sobel gives you local evidence. A CNN builds feature maps with filters; an image classifier uses a supplied crop to produce class scores. Those are additional computations, not meanings hidden inside a Sobel response.
What This Sobel Demo Leaves Out
This is an explainer, not a substitute for formal training. It uses small synthetic grayscale images, fixed unscaled Sobel kernels, valid interior windows, and one threshold. There is no separate denoising pass, non-maximum suppression, hysteresis, or color processing. Sobel's own perpendicular smoothing is still present in the kernels. The resulting mask can be thick and can respond to noise; it should not be mistaken for the full Canny edge-detection pipeline.
Keep exploring
A few lessons that share the same technique or lead into the next idea.
Found a mistake or something unclear? Leave feedback.