Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradient orientation in OpenCV

Tags:

python

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.

like image 706
Wizard Avatar asked Aug 03 '18 07:08

Wizard


2 Answers

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.

like image 109
w-m Avatar answered Sep 29 '22 10:09

w-m


You can also use the HSV colorspace to encode orientation and magnitude, since Hue works with angles, and you can use the V to encode the magnitude.

For example, using your code and sexy Lenna:

import cv2 as cv
import numpy as np


im = cv.imread("lenna.png", -1)
im_gray = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
k = 5
gray_blur = cv.bilateralFilter(im_gray, k, k * 2, k / 2) # To perserve edges

# 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 = cv.filter2D(gray_blur, cv.CV_32F, sobel_x)  
filtered_blurred_y = cv.filter2D(gray_blur, cv.CV_32F, sobel_y)

mag = cv.magnitude(filtered_blurred_x, filtered_blurred_y)
orien = cv.phase(filtered_blurred_x, filtered_blurred_y, angleInDegrees=True)
orien = orien / 2. # Go from 0:360 to 0:180 
hsv = np.zeros_like(im)
hsv[..., 0] = orien # H (in OpenCV between 0:180)
hsv[..., 1] = 255 # S
hsv[..., 2] = cv.normalize(mag, None, 0, 255, cv.NORM_MINMAX) # V 0:255

bgr = cv.cvtColor(hsv, cv.COLOR_HSV2BGR)
cv.imshow("Color coded edges", bgr)
cv.waitKey(0)

enter image description here

like image 45
João Cartucho Avatar answered Sep 29 '22 11:09

João Cartucho