# Convolution of Two Kernels [OpenCV]

I've been completely stuck on a portion of my assignment for a few days now. After plenty of searching around, I have been unsuccessful in discovering information that leads me to the correct solution. That said, this is for OpenCV in Python, using Numpy for matrix calculations.

The problem statement:

Construct the derivative of Gaussian kernels, 𝑔𝑥 and 𝑔𝑦 by convolving the above two kernels: 𝑔𝑥=𝑆𝑥∗𝑔𝜎; 𝑔𝑦=𝑆𝑦∗𝑔𝜎

Additionally, here's a screenshot of the problem in full form:

What I Have Attempted:

import cv2
import numpy as np

def my_Normalize(img):
if len(img.shape) != 2:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert img to grayscale
img_float = cv2.normalize(img.astype('float'), None, 0.0, 1.0, cv2.NORM_MINMAX)
return img_float

def my_DerivativesOfGaussian(img, sigma):
#the two 3x3 Sobel kernels
#Sx = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], np.float)
#Sy = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], np.float)

sobelx = cv2.Sobel(img,cv2.CV_32F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_32F,0,1,ksize=3)

#the Gaussian kernel, taken from example program 9
halfSize = 3 * sigma
maskSize = 2 * halfSize + 1
xyRange = np.arange(-halfSize, halfSize+1)
xx, yy = np.meshgrid(xyRange, xyRange)
x2y2 = (xx**2 + yy**2)
exp_part = np.exp(-(x2y2/(2.0*(sigma**2))))
gKern = gKern * exp_part

#convolve the two kernels
Gx = cv2.filter2D(sobelx, -1, gKern)

IxN = my_Normalize(Gx)
cv2.imshow('Gx Normalized', IxN)
return Gx, Ix

Ix, Iy = my_DerivativesOfGaussian(img1, 1)

cv2.waitKey(0)
cv2.destroyAllWindows()


Here is a side-by-side comparison of the result I was given for a test image (left image), compared with the result I obtained from the above execution (right image):

Where I am confused:

The resulting image that was obtained is close to the target image, except blurred slightly. The blurring leads me to believe there's an error with the Gaussian kernel. I also obtain a drastically different image when I switch the order of the Gaussian and Sobel kernels in the cv2.filter2D() function. However, this is counter-intuitive for me, as the association property states that convolution should be equivalent, regardless of the order in which the convolution occurs.

Specific Questions:

• Is the cv2.filter2D() function able to convolve two kernels?
• Assuming the answer to ^ is false, do you know of a function that is able to perform such an operation?
• Where does my logic/understanding begin to fail? (i.e. what topics/concepts am I completely not understanding?)

Thanks so much for your time, any help is appreciated. This is the first time I have been absolutely stumped on an assignment, and can not think of a way to solve this problem without brute-forcing the convolution formula via nested loops.

Here are the images supplied for verifying correctness of the convolution, in their native formats:

Base input test image

Normalized Ix

Normalized Iy

• Lookign at your result, it does not seem to be too unreasonable. The Gaussian will introduce some smoothing in any case I think. Can you also provide the original image? – Maximilian Matthé Mar 17 '17 at 5:51
• I've edited the original image and the two verification images that were supplied into the question now, thank you. Earlier I was trying to get a better understanding of what was done to produce these images, and the supplied Normalized Ix has different shape from the input image: img3 size: 1067346 img3 shape: (591L, 602L, 3L) img4 size: 1080000 img4 shape: (600L, 600L, 3L) - which adds to my confusion. @MaximilianMatthé – manapaws Mar 17 '17 at 6:26
• I actually have the feeling that the images Ix and Iy you show are only the application of Sobel to the original image. Doing an additional Gaussian will smooth the result and yield the image that comes out of your code. – Maximilian Matthé Mar 17 '17 at 6:56
• It is strange (to use a kind word) to derive the Gaussian derivative kernel this way. It is trivial to compute the analytic derivative of a Gaussian and sample that as the convolution kernel. The error introduced by using a Sobel derivative is unnecessary. A true Gaussian derivative yields a much better estimate of local edge orientation than Sobel kernels do. – Cris Luengo Nov 3 '18 at 20:36