pythonopencvedge-detectioncanny-operatorsobel

How to apply gradient/magnitude to an image using OpenCV?


I'm currently following this tutorial as part of an university assignment where we are supposed to implement canny edge detection ourselfes. Applying the gaussian blur worked without any problems but now I'm trying to display the magnitude intensity as shown on the website.

I implemented the functions as seen on the mentioned website and created a function for running the canny edge detection. Currently this is what the function looks like:

def canny_edge(img):
    noise_reduction = cv.filter2D(img, -1, gaussian_kernel(5))
    cv.imshow('Blur', noise_reduction)
    magnitude, gradient = sobel_filters(img)
    magnitude = magnitude.astype(np.uint8)
    sobel = magnitude * gradient
    sobel = sobel.astype(np.uint8)
    test = img + (255 - gradient * noise_reduction)
    plt.imshow(gradient, cmap='gray')
    plt.show()
    cv.imshow('Gradient', magnitude)
    cv.imshow('Original Image', img)

I had to convert the magnitude and sobel arrays to np.uint8 as otherwise they'd contain float values which led to an error when displaying the image. Currently, I'm using the variable test to try various things, like gradient - noise_reduction, the line you see above, etc. The problem is that I always get images that look similar to these (image on the left shows test, image on the right shows gradient, image at the bottom shows magnitude):

enter image description here enter image description here enter image description here

I'm not too familiar with all the OpenCV functions that are available but I guess perhaps it might be important to use some of them that I don't know for this purpose. Unfortunately I haven't been able to find any information about how the magnitude returned by the sobel_filters function is applied to the image in the tutorial linked above. Thanks in advance for any input on how to solve this problem.


Solution

  • I think there might be an issue with ndimage.filters.convolve. I got similar results as you. But the following seems to work fine using Python/OpenCV

    Input:

    enter image description here

    import cv2
    import numpy as np
    import skimage.exposure
    
    img = cv2.imread('black_dress.png', cv2.IMREAD_GRAYSCALE)
    
    img = cv2.GaussianBlur(img, (0,0), sigmaX=1.5, sigmaY=1.5)
    
    Kx = np.array([[-1, 0, 1], 
                   [-2, 0, 2], 
                   [-1, 0, 1]])
    Ky = np.array([[1,   2,  1], 
                   [0,   0,  0], 
                  [-1,  -2, -1]])
    
    Ix = cv2.filter2D(img, -1, Kx)
    Iy = cv2.filter2D(img, -1, Ky)
    
    G = np.hypot(Ix, Iy)
    G = skimage.exposure.rescale_intensity(G, in_range='image', out_range=(0,255)).astype(np.uint8)
    
    theta = np.arctan2(Iy, Ix)
    theta = skimage.exposure.rescale_intensity(theta, in_range='image', out_range=(0,255)).astype(np.uint8)
       
    cv2.imwrite('black_dress_gradient_magnitude.png', G)
    cv2.imwrite('black_dress_gradient_direction.png', theta)
    
    cv2.imshow("magnitude", G)
    cv2.imshow("direction", theta)
    cv2.waitKey(0)
    

    Magnitude:

    enter image description here

    Direction:

    enter image description here