pythonopencv

Gradient orientation in OpenCV


Through the Sobel operator I have been able to determine the gradient magnitude of an image. I display this below:

GradMag

Now I wish to determine the gradient orientation. To do so, I am following this post, which makes use of the function cv2.phase. Following this, angles are hard coded a particular colour depending on the returned degrees of the function. My issue is that the values this function returns for me are between the range of 0 and 90 degrees. Consequently, I am getting an image consisting of only red and cyan.

My code is as follows:

# where gray_blur is a grayscale image of dimension 512 by 512

# 3x3 sobel filters for edge detection
sobel_x = np.array([[ -1, 0, 1], 
                   [ -2, 0, 2], 
                   [ -1, 0, 1]])


sobel_y = np.array([[ -1, -2, -1], 
                   [ 0, 0, 0], 
                   [ 1, 2, 1]])


# Filter the blurred grayscale images using filter2D

filtered_blurred_x = cv2.filter2D(gray_blur, -1, sobel_x)  
filtered_blurred_y = cv2.filter2D(gray_blur, -1, sobel_y)

# Compute the orientation of the image
orien = cv2.phase(np.array(filtered_blurred_x, np.float32), np.array(filtered_blurred_y, dtype=np.float32), angleInDegrees=True)

image_map = np.zeros((orien.shape[0], orien.shape[1], 3), dtype=np.int16)

# Define RGB colours
red = np.array([255, 0, 0])
cyan = np.array([0, 255, 255])
green = np.array([0, 255, 0])
yellow = np.array([255, 255, 0])

# Set colours corresponding to angles
for i in range(0, image_map.shape[0]):
    for j in range(0, image_map.shape[1]):
        if orien[i][j] < 90.0:
            image_map[i, j, :] = red
        elif orien[i][j] >= 90.0 and orien[i][j] < 180.0:
            image_map[i, j, :] = cyan
        elif orien[i][j] >= 180.0 and orien[i][j] < 270.0:
            image_map[i, j, :] = green
        elif orien[i][j] >= 270.0 and orien[i][j] < 360.0:
            image_map[i, j, :] = yellow

# Display gradient orientation
f, ax1 = plt.subplots(1, 1, figsize=(20,10))

ax1.set_title('gradient orientation')
ax1.imshow(image_map)

Which displays the image:

Orien

Thanks in advance.


Solution

  • The ddepth parameter of cv2.filter2D is important. You set it to -1, meaning that the filtered image will have the same depth as the input. gray_blur seems to be in an unsigned integer (probably uint8), thus the filter output is as well.

    As your filter can produce negative values they are underflowing the uint8. Set the ddepth to receive the full value range from the filter:

    filtered_blurred_x = cv2.filter2D(gray_blur, cv2.CV_32F, sobel_x)  
    filtered_blurred_y = cv2.filter2D(gray_blur, cv2.CV_32F, sobel_y)
    

    With this your filtered images now encode a direction, and the orientation will map the full 360 degrees.