Image Processing & Computational Photography

Sobel Operator

A pair of 3×3 kernels that estimate the horizontal and vertical image derivatives by combining a central difference with smoothing across it; the most common way to compute image gradients.

beginner

The Sobel operator estimates the two partial derivatives of an image with a pair of small kernels. Each kernel takes a central difference in one direction and smooths with weights 1, 2, 1 in the other, so it is less sensitive to noise than a plain difference while costing only a few additions per pixel. The two outputs give the image gradient at every pixel, and with it the edge strength and orientation used by edge detectors, corner detectors, and gradient-histogram descriptors.

Problem

Derivatives of a sampled image must be estimated from neighboring pixels. The simplest estimate, the central difference, responds strongly to noise, and its accuracy depends on the direction of the edge. The Sobel operator is a small, fixed convolution that trades a little resolution for robustness and more uniform behavior across orientations.

Inputs and Outputs

Input: a grayscale image II (color images are usually converted or processed per channel), in a floating-point or wide integer type.

Output: two images of the same size, GxG_x and GyG_y, estimating ∂I/∂x\partial I / \partial x and ∂I/∂y\partial I / \partial y. They take both signs, so storing them in an unsigned 8-bit type clips half of the edges. Magnitude and orientation are computed from them as described in image gradients.

Intuition

A central difference compares the pixel to the right with the pixel to the left. The Sobel operator makes the same comparison on the row above, the current row, and the row below, and averages the three with the middle row counted twice. Independent noise in the three rows partly cancels, while the signal of a straight edge, the same in all three, does not. The extra weight on the middle row, as the analysis below shows, also makes the response depend less on edge direction than equal weights would.

Algorithm

  1. Convert the image to a floating-point or 16-bit signed type.
  2. Correlate the image with the horizontal template SxS_x to get GxG_x, and with Sy=Sx⊤S_y = S_x^{\top} to get GyG_y, handling borders by replication or reflection.
  3. Divide by 8 if derivatives in intensity units per pixel are needed.
  4. Compute magnitude Gx2+Gy2\sqrt{G_x^2 + G_y^2} and orientation atan2⁡(Gy,Gx)\operatorname{atan2}(G_y, G_x) where needed.

Because both kernels are separable, step 2 is usually done as two 1D passes per output: smoothing along one axis and differencing along the other.

Mathematical Formulation

The kernels below are written as templates, the arrays that are laid over the image and multiplied pixel by pixel (correlation), with xx increasing to the right and yy increasing downward, as in image row indices. This is how OpenCV documents its Sobel kernels and how scipy.ndimage.sobel applies them. As convolution explains, a true convolution flips the kernel, which for these antisymmetric kernels changes the sign: the convolution kernel for the same result has +1+1 on the left.

Sx=[−101−202−101]=[121][−101],Sy=Sx⊤=[−1−2−1000121]=[−101][121].S_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} = \begin{bmatrix} 1 \\ 2 \\ 1 \end{bmatrix} \begin{bmatrix} -1 & 0 & 1 \end{bmatrix}, \qquad S_y = S_x^{\top} = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} = \begin{bmatrix} -1 \\ 0 \\ 1 \end{bmatrix} \begin{bmatrix} 1 & 2 & 1 \end{bmatrix}.

The factor [1,2,1][1, 2, 1] is the smallest binomial smoothing kernel, a coarse approximation to a Gaussian, and [−1,0,1][-1, 0, 1] is the central difference without its factor of 12\tfrac{1}{2}. Applied to a linear ramp I=ax+byI = a x + b y, SxS_x returns (1+2+1)⋅2a=8a(1 + 2 + 1) \cdot 2a = 8a, so

∂I∂x≈18 (Sx⋆I),∂I∂y≈18 (Sy⋆I),\frac{\partial I}{\partial x} \approx \frac{1}{8}\,(S_x \star I), \qquad \frac{\partial I}{\partial y} \approx \frac{1}{8}\,(S_y \star I),

where ⋆\star denotes correlation. Libraries usually omit the 18\tfrac{1}{8} to stay in integer arithmetic; the scale does not affect orientation, but it matters when the magnitude is compared with a threshold or combined with other derivatives.

Why the smoothing weights matter

Write a general cross-smoothing kernel as [a,1−2a,a][a, 1 - 2a, a]. The central difference has a=0a = 0, the Prewitt operator (equal weights) a=13a = \tfrac{1}{3}, Sobel a=14a = \tfrac{1}{4}, and the Scharr kernel discussed below a=316a = \tfrac{3}{16}. A short Taylor expansion shows why the choice matters. For a plane wave with spatial frequency (ωx,ωy)(\omega_x, \omega_y), the frequency response of the x-derivative estimate is proportional to

sin⁡ωx (1−2a+2acos⁡ωy)≈ωx(1−ωx26−a ωy2),\sin \omega_x \,\bigl(1 - 2a + 2a \cos \omega_y\bigr) \approx \omega_x \left(1 - \frac{\omega_x^2}{6} - a\,\omega_y^2\right),

while the true derivative responds with ωx\omega_x. The estimate is isotropic to this order only when the error term is proportional to ωx2+ωy2\omega_x^2 + \omega_y^2, which requires a=16a = \tfrac{1}{6}. With aa smaller, as for the central difference, the estimated orientation is pulled toward the diagonals; with aa larger, as for Prewitt and Sobel, it is pulled toward the axes. Sobel’s 14\tfrac{1}{4} is closer to 16\tfrac{1}{6} than Prewitt’s 13\tfrac{1}{3} is, and Scharr’s 316\tfrac{3}{16} is closer still.

Parameters

The 3×3 operator has none: its scale is fixed by the kernel size. Larger Sobel-type kernels raise the binomial order on both factors. OpenCV, for example, builds its 5×55 \times 5 kernel from the smoothing [1,4,6,4,1][1, 4, 6, 4, 1] and the derivative [−1,−2,0,2,1][-1, -2, 0, 2, 1] (the central difference smoothed once more by [1,2,1][1, 2, 1]), and allows sizes up to 7; it normalizes the coefficients only on request. Larger kernels approach a derivative of a Gaussian and respond to coarser structure. When the scale must be chosen freely, smoothing with a Gaussian filter of chosen width and then differentiating is the more flexible option.

Complexity

Each output costs a constant number of operations: as two separable passes, three additions or subtractions and a shift per derivative, or nine multiply-adds done directly. The total cost is linear in the number of pixels, and the integer weights suit fixed-point hardware.

Implementation

The example applies four derivative templates to a step edge rotated through several angles and compares the estimated orientation and magnitude with the true values. The edge is blurred by a Gaussian of 1 pixel, so it is well sampled and its true gradient is known exactly. All templates are normalized to derivative units, and correlation is used, so the ++ column is on the right.

import numpy as np
from scipy import ndimage
from scipy.special import erf

# Derivative templates for d/dx, applied by correlation (no flip): the + column
# is on the right, so the output is positive where intensity increases with x.
d = np.array([-1.0, 0.0, 1.0])
templates = {
    "central": np.outer([0, 1, 0], d) / 2,     # plain central difference
    "Prewitt": np.outer([1, 1, 1], d) / 6,     # box smoothing across the edge
    "Sobel":   np.outer([1, 2, 1], d) / 8,     # binomial smoothing
    "Scharr":  np.outer([3, 10, 3], d) / 32,   # smoothing tuned for isotropy
}

def edge_image(theta_deg, size=65, blur=1.0):
    """A unit-contrast step edge through the center, rising along direction theta,
    smoothed by a Gaussian of std `blur` pixels (an ideal blurred, unaliased edge)."""
    t = np.deg2rad(theta_deg)
    y, x = np.mgrid[:size, :size] - (size - 1) / 2
    dist = x * np.cos(t) + y * np.sin(t)          # signed distance to the edge
    inner = np.hypot(x, y) < 20                   # stay clear of the borders
    return 0.5 * (1 + erf(dist / (np.sqrt(2) * blur))), dist, inner

blur = 1.0
angles = [0, 10, 22.5, 30, 45, 60, 67.5]
print("orientation error in degrees (mean over pixels on the edge)")
print("angle  " + "".join(f"{n:>9s}" for n in templates))
worst = {n: 0.0 for n in templates}
mag_ratio = {n: [] for n in templates}
for a in angles:
    img, dist, inner = edge_image(a, blur=blur)
    on_edge = (np.abs(dist) < 0.5) & inner
    # true gradient magnitude: the Gaussian profile of the blurred step
    true_mag = np.exp(-dist**2 / (2 * blur**2)) / (np.sqrt(2 * np.pi) * blur)
    row = f"{a:5.1f}  "
    for name, k in templates.items():
        gx = ndimage.correlate(img, k)        # x is the column index
        gy = ndimage.correlate(img, k.T)      # y is the row index (pointing down)
        theta = np.rad2deg(np.arctan2(gy[on_edge], gx[on_edge]))
        err = np.mean(theta - a)
        worst[name] = max(worst[name], abs(err))
        mag_ratio[name].append(np.mean(np.hypot(gx, gy)[on_edge] / true_mag[on_edge]))
        row += f"{err:9.3f}"
    print(row)
print("worst  " + "".join(f"{worst[n]:9.3f}" for n in templates))
print("\nmagnitude / true slope on the edge, min-max over angles")
for n in templates:
    print(f"  {n:8s} {min(mag_ratio[n]):.3f} - {max(mag_ratio[n]):.3f}")

# Noise: apply each normalized template to unit-variance white noise.
rng = np.random.default_rng(0)
noise = rng.standard_normal((512, 512))
print("\nstd of x-derivative of unit white noise")
for n, k in templates.items():
    print(f"  {n:8s} measured {ndimage.correlate(noise, k).std():.3f}"
          f"  predicted {np.sqrt((k**2).sum()):.3f}")

Output:

orientation error in degrees (mean over pixels on the edge)
angle    central  Prewitt    Sobel   Scharr
  0.0      0.000   -0.000    0.000   -0.000
 10.0      1.420   -1.200   -0.538   -0.044
 22.5      2.138   -1.916   -0.854   -0.079
 30.0      1.814   -1.689   -0.749   -0.074
 45.0     -0.000   -0.000   -0.000   -0.000
 60.0     -1.830    1.702    0.754    0.073
 67.5     -2.138    1.916    0.854    0.079
worst      2.138    1.916    0.854    0.079

magnitude / true slope on the edge, min-max over angles
  central  0.856 - 0.923
  Prewitt  0.805 - 0.860
  Sobel    0.835 - 0.863
  Scharr   0.856 - 0.867

std of x-derivative of unit white noise
  central  measured 0.707  predicted 0.707
  Prewitt  measured 0.410  predicted 0.408
  Sobel    measured 0.435  predicted 0.433
  Scharr   measured 0.482  predicted 0.480

All four are exact at 0° and 45°, where symmetry cancels the error. In between, the signs follow the analysis above: the central difference tilts the orientation toward the diagonal by up to 2.1°, Prewitt toward the axis by up to 1.9°, Sobel by under 0.9°, and Scharr by under 0.1°. The variation of magnitude with angle follows the same order: 7.8% for the central difference, 3.4% for Sobel, 1.3% for Scharr. Every operator reports between 80% and 92% of the true slope at the edge, because its own smoothing makes the edge look slightly more blurred; on a linear ramp the normalized kernels are exact. On white noise, the normalized Sobel output has 61% of the standard deviation of the central difference; Prewitt’s equal weights remove slightly more noise at the cost of a larger orientation bias.

Properties and Behavior

  • Linear and shift-invariant. The operator is a convolution, so it commutes with other linear filters: Sobel applied to a Gaussian-smoothed image equals the Sobel output smoothed by the same Gaussian.
  • Zero response to constants. Each kernel sums to zero, so a uniform brightness offset does not change the output.
  • Polarity. Dark-to-bright and bright-to-dark edges give outputs of opposite sign and equal magnitude.

Limitations

  • Fixed scale. A 3×33 \times 3 support responds to fine detail and texture as strongly as to object boundaries. Coarser structure needs pre-smoothing, larger kernels, or a multi-scale representation such as an image pyramid.
  • Limited noise suppression. One pass of [1,2,1][1, 2, 1] is weak smoothing; on noisy images Sobel is usually preceded by a Gaussian filter.
  • Orientation bias. Errors approach 1° on the well-sampled edges of the example and grow as edges get sharper, which matters when orientations are histogrammed or used to step along an edge.
  • Less localized than smaller masks. The smoothing spreads a one-pixel line over three pixels across its direction. In their study of gradient histograms for pedestrian detection, Dalal and Triggs (2005) reported that the plain [−1,0,1][-1, 0, 1] mask without smoothing worked best, and that larger masks, including 3×33 \times 3 Sobel, and Gaussian pre-smoothing lowered performance.

Variants

  • Prewitt operator. The same construction with equal smoothing weights [1,1,1][1, 1, 1]: slightly less noise, more orientation bias.
  • Scharr operator. Scharr’s dissertation (2000) designed filters, derivative filters among them, by optimizing their transfer functions under weighted error norms in the frequency domain. The 3×33 \times 3 kernel commonly named after him has smoothing weights [3,10,3][3, 10, 3] (normalized by 32 in derivative units); OpenCV provides it as its Scharr filter and documents that it may give more accurate results than the 3×33 \times 3 Sobel. Its a=316a = \tfrac{3}{16} is close to the value 16\tfrac{1}{6} that cancels the leading error term, and the example shows its orientation error is about a tenth of Sobel’s.
  • Larger and higher-order Sobel kernels. Higher binomial orders give 5×55 \times 5 and 7×77 \times 7 versions; replacing [−1,0,1][-1, 0, 1] by [1,−2,1][1, -2, 1] gives second-derivative kernels, which some libraries add to form a Laplacian.
  • Derivative-of-Gaussian filters. Sampling ∂G/∂x\partial G / \partial x for a chosen σ\sigma gives a continuous family of which Sobel is a coarse integer member.

History and Uses

Irwin Sobel and Gary Feldman presented the operator in a 1968 talk at the Stanford Artificial Intelligence Project but did not publish it as a paper. It reached print through others: Pingle’s 1969 description of a computer vision system, and Duda and Hart’s 1973 textbook, which credits it to Sobel in a footnote.

The operator remains a default first stage wherever image gradients are needed. In edge detection its magnitude marks candidate edge pixels, and widely used implementations of the Canny edge detector, OpenCV’s among them, compute their gradients with Sobel kernels before thinning and hysteresis thresholding. OpenCV’s Harris corner detector likewise builds its window sums of gradient products from Sobel derivatives. Gradient-based feature tracking and the Lucas–Kanade method need spatial derivatives at every iteration, and small kernels of this kind are a common way to compute them. Gradient-orientation descriptors such as HOG need the same measurements, although HOG’s authors found the unsmoothed central difference better than Sobel for their detector.

Related

  • Image Filtering

    Computing each output pixel from a neighborhood of input pixels, the family of operations behind smoothing, sharpening, edge detection, and denoising.

  • Gaussian Filter

    A linear smoothing filter that replaces each pixel by an average of its neighbors weighted by a Gaussian, whose standard deviation sets the scale of the detail removed.

  • Laplacian Operator

    The sum of the second partial derivatives of an image, an isotropic operator whose zero crossings mark edges, whose Gaussian-smoothed form detects blobs across scales, and which appears in sharpening, pyramids, and variational methods.

  • Image Noise

    The random variation in recorded pixel values that does not come from the scene, its physical sources in the camera, and how it is modeled and measured.

  • Feature Tracking

    How distinctive image points are selected and followed across video frames, using the classic KLT tracker as the main example.

References

  1. Sobel, I. & Feldman, G. (1968). An Isotropic 3×3 Image Gradient Operator. Talk at the Stanford Artificial Intelligence Project. Unpublished; note deposited 2015.
  2. Duda, R. O. & Hart, P. E. (1973). Pattern Classification and Scene Analysis. New York: Wiley.
  3. Scharr, H. (2000). Optimale Operatoren in der Digitalen Bildverarbeitung (Optimal Operators in Digital Image Processing). PhD thesis, Universität Heidelberg.
  4. Dalal, N. & Triggs, B. (2005). Histograms of Oriented Gradients for Human Detection. Proceedings of the IEEE Computer Society Conference on Computer Vision and Pattern Recognition (CVPR), 1, 886–893.
  5. OpenCV. Image Filtering: Sobel, Scharr, getDerivKernels. OpenCV 4.x Documentation.