1
votes

I am trying to implement Canny Algorithm using python from scratch.

I am following the steps

  1. Bilateral Filtering the image

  2. Gradient calculation using First Derivative of Gaussian oriented in 4 different directions

def deroGauss(w=5,s=1,angle=0):

    wlim = (w-1)/2
    y,x = np.meshgrid(np.arange(-wlim,wlim+1),np.arange(-wlim,wlim+1))
    G = np.exp(-np.sum((np.square(x),np.square(y)),axis=0)/(2*np.float64(s)**2))
    G = G/np.sum(G)
    dGdx = -np.multiply(x,G)/np.float64(s)**2
    dGdy = -np.multiply(y,G)/np.float64(s)**2

    angle = angle*math.pi/180 #converting to radians

    dog = math.cos(angle)*dGdx + math.sin(angle)*dGdy

    return dog
  1. Non max suppression in all the 4 gradient image

def nonmaxsup(I,gradang):

    dim = I.shape
    Inms = np.zeros(dim)
    weak = np.zeros(dim)    
    strong = np.zeros(dim)
    final = np.zeros(dim)
    xshift = int(np.round(math.cos(gradang*np.pi/180)))
    yshift = int(np.round(math.sin(gradang*np.pi/180)))
    Ipad = np.pad(I,(1,),'constant',constant_values = (0,0))
    for r in xrange(1,dim[0]+1):
        for c in xrange(1,dim[1]+1):
            maggrad = [Ipad[r-xshift,c-yshift],Ipad[r,c],Ipad[r+xshift,c+yshift]]
            if Ipad[r,c] == np.max(maggrad):
                Inms[r-1,c-1] = Ipad[r,c]
    return Inms
  1. Double Thresholding and Hysteresis: Now here the real problem comes.

I am using Otsu's method toe calculate the thresholds.

Should I use the grayscale image or the Gradient images to calculate the threshold?

Because in the gradient Image the pixel intensity values are getting reduced to a very low value after bilateral filtering and then after convolving with Derivative of Gaussian it is reduced further. For example :: 28, 15

Threshold calculated using the grayscale is much above the threshold calculated using the gradient image.

Also If I use the grayscale or even the gradient images to calculate the thresholds the resultant image is not good enough and does not contain all the edges.

So practically, I have nothing left to apply Hysteresis on.

I have tried

img_edge = img_edge*255/np.max(img_edge)

to scale up the values but the result remains the same

But if I use the same thresholds with cv2.Canny the result is very good.

What actually can be wrong?

1

1 Answers

0
votes

Applying the Otsu threshold from the original image doesn't make sense, it is completely unrelated to the gradient intensities.

Otsu from the gradient intensities is not perfect because the statistical distributions of noise and edges are skewed and overlap a lot.

You can try some small multiple of Otsu or some small multiple of the average. But in no case will you get perfect results by simple or hysteresis thresholding. Edge detection is an ill-posed problem.