A gradient is not immediately well defined for digital images because they are both:
- Quantized (the image values have a finite number of possible values E.g. 0-255 or likewise)
- The image is discretized. That is, the pixels are located at whole number coordinate points, E.g. (3, 5) or (1, 12).
This means that any approach to calculate the derivative of the image, in some way, will be an approximate method. There are a number of approaches.
Of common approaches I can think of from the top of my head are:
- Using a finite difference method. That is, for a first-order approach, instead of calculating $\frac{f(x+h)-f(x)}{h}$ in the $\lim\limits_{h\to0}$, you let $h$ be some positive value. This still leaves an issue of how to handle the discrete nature of the pixels. Therefore choosing $h$ to be 1, means you are calculating the difference between pixels.
- Alternatively, you first fit a smooth function to your image, a 2d polynomial or similar, of which you can find the derivative and then let this derivative be the substitute for the image. This will be more complicated than calculating the sobel filter.
What you have done, it seems, is to interpolate the grayscale values between the discrete image pixels using a nearest neighbor interpolation. I can deduce that you didn't show the whole list of values because the grayscale values here only have slight variations. You could go by the interpolated coordinates, and calculate a finite difference directly on those. However, your step size is too small using the nearest neighbor interpolation, and you will thus end with the derivative being 0 (mostly) and occasionally 1, I predict. If you increase the step size this should work.
Alternatively, you interpolate using a more refined approach, you can look into bilinear interpolation. Letting two consecutive points on the line be denoted by p[i]
and p[i+1]
, with I[p[i]]
, I[p[i+1]]
be the grayscale values and |p[i+1]-p[i]|
denote the distance. You can estimate the derivative at p[i]
by (I[p[i+1]]-I[p[i]])/|p[i+1]-p[i]|
. What you get is the slope of the image at p[i]
of the image along that red line.
Alternatively, you abandon the interpolated line and calculate the derivative directly in the image using finite difference. Doing something like:
import numpy as np
from PIL import Image
image = np.array(Image.open('your_image.png'))
di = image[:-1,1:] - image[1:,1:]
dj = image[1:,:-1] - image[1:,1:]
mag = np.sqrt(di**2 + dj**2)
should work.
Here di
is the derivative along columns and dj
is the derivative along the rows. mag
holds the gradient magnitude.
A mention on convolutions. They don't particularly help you calculate filters on images unless you are interested in some specific properties of the Fourier space or need the filter application to be fast (using FFT fast Fourier transforms). It's a nice theoretic framework but not one that improves the results in this case. Usually rather the opposite.