Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Drawing Gradient Directions

I have created some code to visually display the average gradient direction in a cell/kernel. My questions are:

  • Is my method of calculating the average gradient direction correct? I am aware of a different method (see *) but unsure which is better/more accurate.
  • Is my normalisation of a degrees value to a hue value correct? Ie, normalising a value that can be 0-359 to a value between 0-179 by simply dividing by 2?
  • Most importantly am I accurately calculating and representing the average gradient direction over a series of cells?

*Alt method to calculate the average gradient direction:

hMean = cv2.mean(sobelX)
vMean = cv2.mean(sobelY)
avg_dir = math.atan2(-vMean[0], hMean[0])

Draw gradient directions:

import cv2
import math
import numpy as np

np.set_printoptions(precision=3, threshold=np.inf, linewidth=np.inf, suppress=True)

def get_roi(src, pt1, pt2):

    col1, col2 = (pt1[0], pt2[0]) if pt1[0] < pt2[0] else (pt2[0], pt1[0])
    row1, row2 = (pt1[1], pt2[1]) if pt1[1] < pt2[1] else (pt2[1], pt1[1])
    return src[row1:row2, col1:col2]

def get_gradient_direction_line(avg_dir, cellUpperLeft, cellW, cellH, scale=0.8):

    halfScale = scale/2;
    centrePt = (int(cellUpperLeft[0] + (cellW/2)), int(cellUpperLeft[1] + (cellH/2)))
    strtPt = (int(centrePt[0] - (cellW * halfScale * math.cos(avg_dir))), int(centrePt[1] - (cellH * halfScale * math.sin(avg_dir))))
    endPt = (int(centrePt[0] + (cellW * halfScale * math.cos(avg_dir))), int(centrePt[1] + (cellH * halfScale * math.sin(avg_dir))))
    return [strtPt, endPt]

def get_gradient_directions_arrows(direction, kernel_w=3, kernel_h=3):

    arrows = np.zeros(direction.shape, dtype=np.uint8)
    n_cols = int(direction.shape[1] / kernel_w)
    n_rows = int(direction.shape[0] / kernel_h)

    for c in range(n_cols):
        # Draw grid lines
        cv2.line(arrows, (c*kernel_w, 0), (c*kernel_w, direction.shape[0]), (255,255,255), 1)
        cv2.line(arrows, (0, c*kernel_h), (direction.shape[1], c*kernel_h), (255,255,255), 1)

        for r in range(n_rows):
            roiUpperleft = (c*kernel_w, r*kernel_h)
            roi = get_roi(direction, roiUpperleft, ((c+1)*kernel_w, (r+1)*kernel_h))
            avg_dir = cv2.mean(roi)[0]
            arrow_pnts = get_gradient_direction_line(avg_dir, roiUpperleft, kernel_w, kernel_h)
            cv2.arrowedLine(arrows, arrow_pnts[0], arrow_pnts[1], (255,255,255), 1)

    return arrows

def get_gradient_directions_colours(direction, kernel_w=3, kernel_h=3):
    # (red=0°; yellow=60°, green=120°, blue=240°...)

    hsv = np.zeros((direction.shape[0], direction.shape[1], 3), dtype=np.uint8)
    hsv = cv2.cvtColor(hsv, cv2.COLOR_BGR2HSV)
    n_cols = int(direction.shape[1] / kernel_w)
    n_rows = int(direction.shape[0] / kernel_h)

    for c in range(n_cols):
        # Draw grid lines
        cv2.line(hsv, (c*kernel_w, 0), (c*kernel_w, direction.shape[0]), (180,255,255), 1)
        cv2.line(hsv, (0, c*kernel_h), (direction.shape[1], c*kernel_h), (180,255,255), 1)

        for r in range(n_rows):
            roiUpperleft = (c*kernel_w, r*kernel_h)
            roi = get_roi(direction, roiUpperleft, ((c+1)*kernel_w, (r+1)*kernel_h))
            avg_dir = cv2.mean(roi)[0]
            # avg_dir will be value between 0-359. HSV hue needs a value between 0-179
            avg_dir /= 2
            arrow_pnts = get_gradient_direction_line(avg_dir, roiUpperleft, kernel_w, kernel_h)
            cv2.rectangle(hsv, roiUpperleft, ((c+1)*kernel_w, (r+1)*kernel_h), (avg_dir, 255,255), -1)

    bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
    return bgr

def main():
    src = cv2.imread('foo.jpg', 0)

    # Calculate gradient magnitude and direction for the image
    dX = cv2.Sobel(src, cv2.CV_32F, 1, 0)
    dY = cv2.Sobel(src, cv2.CV_32F, 0, 1)
    mag, direction = cv2.cartToPolar(dX, dY, angleInDegrees=True)

    arrows = get_gradient_directions_arrows(direction, 20, 20)
    colours = get_gradient_directions_colours(direction, 20, 20)

    cv2.imshow('src', src)
    cv2.imshow('arrows', arrows)
    cv2.imshow('colours', colours)

    cv2.waitKey(0)

main()