OpenCV中的梯度方向

6
通过Sobel算子我能够确定图像的梯度幅值。我在下面显示了这个结果:

GradMag

现在我想要确定梯度方向。为此,我正在遵循这个帖子,该帖子使用函数cv2.phase。按照这个方法,根据函数返回的角度,将角度硬编码成特定的颜色。我的问题是,这个函数对我而言返回的值只在0到90度之间。因此,我得到的图像仅由红色和青色组成。
以下是我的代码:
# 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)

以下代码用于显示图片:

Orien

提前感谢。


角度可能在-180到180的范围内,因此大多数角度都符合您的<90条件。 - Miki
@Miki 我也认为是这种情况,然而当打印数组的值时,它们都在0.0到90.0的范围内。 - Wizard
我比较喜欢红色和青色;-) - Mark Setchell
2个回答

8

cv2.filter2D函数的参数ddepth非常重要。你将其设置为-1,这意味着滤波后的图像深度与输入图像的深度相同。gray_blur 似乎是一个无符号整数(可能是 uint8),因此滤波输出也是如此。

由于您的滤波器可能会产生负值,它们正在向 uint8 中下溢。将 ddepth 设置为接收滤波器的全值范围:

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

通过这个操作,你的筛选图像现在编码了一个方向,其方向将映射到完整的360度。


太棒了,它解决了我的问题,谢谢。可以在这里看到结果方向。我需要修复颜色,其中渐变不会改变。 - Wizard

6

你也可以使用HSV颜色空间来编码方向和大小,因为色调与角度有关,你可以使用V来编码大小。

例如,使用你的代码和性感的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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接