动力学知识库

I'm working on my task in computer vision course. One of sub-tasks is gradient direction computation based on image brightness. I've made a matrix bright[width][height] containing brightness values for every pixel of the image. And i have two such functions:

``double Image::grad_x(int x,int y){if(x==width-1 || x==0) return bright[x][y];return bright[x+1][y]-bright[x-1][y];}double Image::grad_y(int x,int y){if(y==height-1 || y==0) return bright[x][y];return bright[x][y+1]-bright[x][y-1];}``

EDIT: border check fixed

I'm working with simple derivative, without using Sobel operator 'cause simple derivative is sufficient for my needs.

The question is, am i doing this gradient computation right and what exactly do i have to do with border pixels(right now function returns value of the pixel itself, im not sure it's accurate)? And, by the way, is there any utility for computation of gradients of the image? I want to be sure my program is performing well.

Your computation is correct. It is a simple gradient method you're using, but if that's fine for your use there is nothing wrong with that.

The corner cases are a problem because you don't have enough data to calculate a gradient in the same way as the other pixels. One way to deal with them is to simply not calculate the corner cases and live with a slightly smaller image.

If this is not an option you can also extrapolate the missing data. If you assume that the gradient changes smoothly it works like this:

In your x-gradient calculations you may have calculated the derivate A for pixel 1 and B for pixel 2. If you want to extrapolate a value for pixel 0 (the corner case) the value a-(b-a) could be used.

A numerical example:

``````  pixel1: gradient = 100

extrapolate using a-(b-a):

pixel0: gradient = 100 - (80-100)) = 120
``````

So, on one hand you want to keep it simple on the other hand you want your program to perform well. Huh.

I'm actually doing something similar, though, I don't care much about the border. I like to base the coefficients off of cubic B-Splines. If you convolve your discrete 2D signal with a 2D cubic B-Spline, you'll get a very smooth and twice continuously differentiable function. It's possible to compute the exact intensities and derivatives of this function at arbitrary points. Since the cubic B-Spline is not an interpolator the result will be a bit smoothed compared to the original. But that's not a problem for many applications. In fact, it tends to improve things (suppresing noise to some extent) in many situations. If you don't want this smoothing effect, you can get around it (see my reference below).

In one dimension, reconstruction using the cubic B-Spline as reconstruction filter followed by sampling the signal again is equivalent to convolving the signal with

``````1/6 4/6 1/6
``````

The exact derivative of this is:

``````1/2 0 -1/2
``````

And the exact second derivative is:

``````1 -2 1
``````

These coefficients follow from the cubic B-Spline curve and its derivatives. In 2D you can combine this arbitratily. One filter for the x direction and one filter for the y direction. Examples:

``````"B-Spline reconstruction" (divisor=36)
1  4  1
4 16  4
1  4  1

"B-Spline differentiator in X" (divisor=12)
1  0 -1
4  0 -4
1  0 -1

"B-Spline, 2nd derivative in X, 1st derivative in Y" (divisor=2)
1 -2  1
0  0  0
-1  2 -1
``````

The nice thing about this is, even though the filtered results don't correspond exactly to the original signal but only a slightly smoothed version, they are nontheless consistent with each other. You can get around the smoothing effect by using a simple preprocessing trick that is described here. You'll also But depending on what you actually want to do, this preprocessing might be inappropriate.

I use this to compute quadratic Taylor approximations at arbitrary (sub-pixel) points to find things like saddle points and local extremums.

If you care about the border you need to somehow choose an extrapolation that fits your needs. I typically just repeat the pixel values of the last pixels. It works well for my applications*.

How you deal with borders totally depends on the application. Mirroring, extrapolation, adding zeroes, depending on your needs it will do.

Now you take as border the brightness value, I would not do that, it has no meaning. Just act like your image has more pixels on all borders and mirror, extrapolate or zero their value for your derivative calculation.

Why not taking just a Sobel kernel? It is fast and not more coding effort?

Edit: you do not check the borders in x-direction. grad_x(0, 0) will result in a runtime exception.

Utility:

OpenCV with the convolution kernel you used (`[1 0 -1]`).

Border pixels:

Depends on the application. Here are some nice ways to pad your image.