Mauro Gentile
Mauro Gentile

Reputation: 1511

Unnormalized gaussian kernel in cv2

I need to convolve my image with an normalised Gaussian kernel. Of course I can define a function myself but I would rather prefer to use a cv2 function that will for sure be more efficient.

cv2.GaussianBlur is normalised and apparently it does not have options for switching off the normalisation.

Any hints?

Upvotes: 0

Views: 1254

Answers (1)

Rotem
Rotem

Reputation: 32084

In case you have the filtered image of normalized kernel, and the sum of the unnormalized kernel, all you have to do, is multiply the normalized image by the sum.

The rules of convolution is that you can switch the order:
Multiply the kernel by scaler, and filtering the image, is the same as filtering the image and multiply the result by scalar.

The following Python code demonstrates the solution:

# https://stackoverflow.com/questions/29731726/how-to-calculate-a-gaussian-kernel-matrix-efficiently-in-numpy
def gkern(kernlen=21, nsig=3):
    """Returns a 2D Gaussian kernel."""

    x = np.linspace(-nsig, nsig, kernlen+1)
    kern1d = np.diff(st.norm.cdf(x))
    kern2d = np.outer(kern1d, kern1d)
    return (kern2d/kern2d.sum(), kern2d.sum())

# Normalized Gaussian kernel
norm_h, norm_h_sum = gkern(21, 3)

# Simulate un-normalized kernel (sum = 3)
h = norm_h*3
h_sum = h.sum()

# Create random 160x120 image of type float32
img = np.float32(np.random.rand(120, 160))

# Filter with norm_h kernel
img_norm_h = cv2.filter2D(img, -1, norm_h)

# Filter with h kernel
img_h = cv2.filter2D(img, -1, h)

# Multiply img_norm_h by h_sum for getting the same result as img_h
img_norm_h_by_sum = img_norm_h * h_sum

max_abs_diff = np.max(cv2.absdiff(img_h, img_norm_h_by_sum))

print("max_abs_diff = {}".format(max_abs_diff))

Note:
Gaussian filter can be implemented as separable filter, so cv2.GaussianBlur is probably more efficient than using cv2.filter2D.
cv2.filter2D was used for demonstrating the principle.


Comparing with cv2.GaussianBlur:

# Filter and multiply by sum
img_blur = cv2.GaussianBlur(img, (21, 21), 3) * norm_h_sum

# Multiply by sum and filter
img_h = cv2.filter2D(img, -1, norm_h*norm_h_sum)

img_blur_max_abs_diff = np.max(cv2.absdiff(img_blur, img_h))

print("img_blur_max_abs_diff = {}".format(img_blur_max_abs_diff))

Upvotes: 4

Related Questions