What are the units and limits of a image gradient magnitude? For example I know how to get the gradient magnitude of an image (see below). And the resulting Mat
You're taking some approximate derivative of a function. If the function is, say, f(x)
, then remember you're looking at the change in f
over the change in x
. Say the function is position based on time r(t)
, then the units of the derivative are difference of position (distance) over difference of time (time). So what are the units of an image? Well, they are luminosity values at certain positions. The change in luminosity value is just a luminosity value, and change in position is a distance. So the units of the derivative is luminosity/distance.
Since we're working with an image, the smallest distance is one pixel and the largest change possible is from white to black (or vice versa), so those would correspond with the largest gradients. But Sobel can work with arbitrary matrices whose min and max values could be well outside of 0 to 1 or 0 to 255.
Notice that you could get negative values for the slope: the distance in pixels is always positive, but the change from white to black and black to white have opposite signs. After Sobel calculates those derivatives, you'll calculate the magnitude separately from the angle. You can calculate the angle based on weighting the x
and y
directions by the strength of the gradient in each direction, and it needs the sign to return any angle between 0 and 360.
If you want a positive value for the magnitude of all edges, and 0 for non-edges, you can either take the L1-norm, which is abs(x) + abs(y)
, or take the Euclidean or L2-norm with the magnitude function which is sqrt(G(x)^2 + G(y)^2)
, like you would to calculate the hypotenuse of a triangle. Direct adding would mean some of the gradients were positive, and some were negative, leaving you with a grey image showing black and white edges.
The Sobel operator simply calculates the derivative in a neighborhood of pixels, not just comparing two, but six pixels, and weights them, adding them all up---so it can be a bit higher than values in your image. And moreso, floating point images don't get truncated at 0 or 1 so, you could send images with much larger values and get much larger values out. There is no virtual maximum for the operator outside of the maximum values that data type can hold. The Sobel operator also does some smoothing before the gradient calculation to remove small edges, but the smoothing operator does not scale the values.
The OpenCV docs for Sobel shows the values the operator multiplies your image by. Specifically, for the x
direction, each 3x3 pixel neighborhood gets elementwise multiplied by
-1 0 1
-2 0 2
-1 0 1
and summed. If the largest possible value of your image type is M
and the smallest value is m
then the largest positive value in your gradient is
(1+2+1)*M - (1+2+1)*m = 4*M - 4*m
and similarly the largest negative value is
-(1+2+1)*M + (1+2+1)*m = -4*M + 4*m
This is the same for your gradient in each direction. So, the range of your gradient in each direction from Sobel
will be [-4M+4m, 4M-4m]
.
You'll be adding two of these magnitudes together in some way, either with the L1- or L2-norm. Supposing you stick with the L2-norm, the maximum of the combined magnitude would simply be, following the L2-norm definition,
MAX = sqrt((4*M - 4*m)**2 + (4*M - 4*m)**2)
= sqrt(2 * (4*M - 4*m)**2)
= sqrt(2 * 16 * (M - m)**2)
= sqrt(32) * (M - m)
Since the L1 or L2 norm treats positive and negative values equal (their distance from 0 is what matters), the smallest values in the Sobel operator give the same response in the combined magnitude as the largest values do. Of course some points of your response may be 0, which gives Sobel responses and thus summed magnitudes of 0 as well, so 0 will be the minimum value.
Edit: as noted in another answer to this question, we can't actually achieve a maximum in the X and Y direction simultaneously, and if you work out what the maximum can actually be, it ends up being a bit smaller:
sqrt(20) * (M - n)
Thus you can normalize the gradient to specifically be between 0 and 1 w.r.t. your image type by dividing by the maximum. This would allow you to compare intensity of edges across multiple images.
Or you could just use the normalize
function, but the final values will depend on your images, so you cannot compare equal values across images.
Maximum Gradient Magnitude
I can hardly agree with the answer above. Please note that for a central pixel X and its 3✕3 neighbors, it cannot take the maximum horizontal and vertical gradients AT THE SAME TIME, hence for an 8-bit system, the maximum gradient a Sobel filter can achieve should be sqrt(20)*(M-m)
, where M
and m
are the same as those defined in the accepted answer. The structure of the neighborhood is [m M M; m X M; m m M]
.