21

The x-derivative Sobel looks that way:

-1 0 +1
-2 0 +2
-1 0 +1

Lets say there are two samples of my image which look like that (0=black, 1=white):

0 0 1            1 0 0
0 0 1      &     1 0 0
0 0 1            1 0 0

If I perform convolution I'll end up with 4 and -4 respectively.

So my natural response would be to normalize the result by 8 and translate it by 0.5 - is that correct? (I am wondering as can't find Wikipedia etc. mentioning any normalization)

EDIT: I use the Sobel Filter to create a 2D Structure Tensor (with the derivatives dX and dY):

                   A B 
Structure Tensor = C D

with  A = dx^2 
      B = dx*dy
      C = dx*dy 
      D = dy^2

Ultimately I want to store the result in [0,1], but right now I'm just wondering if I have to normalize the Sobel result (by default, not just in order to store it) or not, i.e.:

A = dx*dx 
//OR
A = (dx/8.0)*(dx/8.0)
//OR
A = (dx/8.0+0.5)*(dx/8.0+0.5)
Tom
  • 433
  • 1
  • 4
  • 13
  • 2
    it only depends on your application. If the goal is to store it and visualize the result as a bitmap, then you should translate and scale so that it falls within 0..255. What is your goal ? – nbonneel Apr 09 '13 at 02:14
  • "So my natural response would be to normalize the result by 8 and translate it by 0.5 - is that correct?" Your response to what? – Lajos Arpad Apr 09 '13 at 02:43
  • @WhitAngl: storing and visualizing is the ultimate goal (so I'll do the appropriate normalization/translation in the end), but I have to do a bit more calculation in between. And I am wondering if the Sobel Filter ALWAYS has to be normalized (see updated question). – Tom Apr 09 '13 at 03:01
  • @Lajos Arpad: Natural response to getting results which are no longer in the range of the input, i.e. [0=black to 1=white] – Tom Apr 09 '13 at 03:04
  • if the question is: does it *ALWAYS* have to be normalized, the answer is no. For example, I have an application that does not do that. Hence "always" does not hold. – nbonneel Apr 09 '13 at 04:08
  • I just saw your edit: if you want to compute the structure tensor: you should NOT normalize it at all. – nbonneel Apr 09 '13 at 04:10
  • Ok, no normalization until the very end. Thank you! – Tom Apr 09 '13 at 09:55
  • Perhaps you're already thinking this, but I would assume that it is ALWAYS going to be normalized and for every image know the max/min of the resulting values and scale it accordingly. Have that be part of the process for every image, and it it so happens that the max and min are 1 and 0, so be it, no scaling needed. – Noremac Apr 09 '13 at 15:00
  • 5
    The only reason you would ever normalize any convolution is either because I want to see the results, or the algorithm calls for normalization. If you're just using the coefficients produced for some further computation than there's no reason to normalize. – jodag Sep 18 '13 at 20:49
  • I’d like to stick to the mathematically precise gradient magnitudes. I’m going to divide them by 8, because that is the denominator, the delta in the very formula. – Константин Ван Nov 13 '22 at 22:06

4 Answers4

6

The Sobel filter is the composition of a finite difference filter in one dimension:

[ 1  0  -1 ] / 2

and a smoothing filter in the other dimension:

[ 1  2  1 ] / 4

Therefore, the proper normalization to the kernel as typically defined is 1/8.

This normalization is required when a correct estimate of the derivative is needed. When computing the gradient magnitude for detecting edges, the scaling is irrelevant. This is why often the Sobel filter is implemented without the 1/8 normalization.

The 1/4 in the smoothing filter is to normalize it to 1. The 1/2 in the finite difference filter comes from the distance between the two pixels compared. The derivative is defined as the limit of h to zero of [f(x+h)-f(x)]/h. For the finite difference approximation, we can choose h=1, leading to a filter [1,-1], or h=2, leading to the filter above. The advantage with h=2 is that the filter is symmetric, with h=1 you end up computing the derivative in the middle between the two pixels, thus the result is shifted by half a pixel.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
1

A mathematically correct normalization for the Sobel filter is 1/8, because it brings the result to the natural units of one gray-level per pixel. But in practical programming, this isn't necessarily the right thing to do.

Ophir Gvirtzer
  • 604
  • 4
  • 8
1

The structure tensor is made of sums of products, so the normalization to [0, 1] is not really helpful.

You mainly use the Eigenvalues, possibly comparing them to a threshold. Rather than normalizing all values, it is more efficient to adjust the threshold.

The ratios of the coefficients or of the Eigenvalues are normalization-independent.


Now if you want to store the Sobel components and your pixel data type is unsigned bytes [0, 255], the range of the components will be [-1020, 1020], which you rescale to [0, 255] by adding 1024 and dividing by 8.

If you only need to store the gradient modulus (L∞ norm), the range is [0, 1020] and a division by 4 is enough.


Final remark: the Sobel components are usually small, except along strong edges. So it can make sense, to preserve accuracy, to use a smaller denominator (1, 2 or 4) and clamp the values that are out of range.

-1

Sobel filter is sort of heuristic approach to do differential along horizontally or vertically. Therefore, normalization could be arbitrary. I found following normalization makes more sense than others, which take half of the sum of absolute values.

http://www.imagemagick.org/discourse-server/viewtopic.php?t=14434&start=30

In fact, scikit-image uses this approach. e.g.,

>>>from skimage import filters
>>>import numpy as np
>>>one[:,0] = 2
>>>one
array([[ 2.,  1.,  1.],
       [ 2.,  1.,  1.],
       [ 2.,  1.,  1.]])
>>>filters.sobel_v(one)
array([[ 0.,  0.,  0.],
       [ 0., -1.,  0.],
       [ 0.,  0.,  0.]])
Yan Zhu
  • 4,036
  • 3
  • 21
  • 37