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 
gKern = np.ones((maskSize,maskSize)) / (float)( 2 * np.pi * (sigma**2))
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 

img1 = cv2.imread('TestImg1.jpg')
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
To answer your specifiy questions:


  Is the cv2.filter2D() function able to convolve two kernels?


Yes, but by default, it actually computes the correlation, not the convolution. However, the only difference is that the filter kernel (your second kernel) needs to be flipped. See OpenCV documentation for filter2D.


  Where does my logic/understanding begin to fail? (i.e. what topics/concepts am I completely not understanding?)


I think one more issue is the size of the resulting kernel.
The filter2D function returns an "output image of the same size and the same number of channels as src". However, the combined kernel increases is size (the combined size should be f1-size + f2-size - 1). So before you apply filter2D, you should add a black border to the first kernel.