Is there any function in Opencv-python that can convolve an image with a kernel without any padding ? Basically, I want an image in which convolution takes place only in the regions where the kernel and the portion of the image fully overlaps.
OpenCV only supports convolving an image where the output returned is the same size as the input image. As such, you can still use OpenCV's filter functions, but simply ignore those pixels along the edges where the kernel didn't fully encapsulate itself inside the image. Assuming that your image kernel is odd, you can simply divide each of the dimensions by half, take the floor (or round down) and use these to cut away the information that isn't valid and return what is left. As Divakar mentioned, this is the same method as using scipy
's 2D convolution method with the 'valid'
option.
As such, assuming that your image is stored in A
and your kernel is stored in B
, you would simply do the following to get the filtered image where the kernel was fully encapsulated inside the image. Take note that we're going to assume that the kernel is odd and the output is stored in C
.
import cv2
import numpy as np
A = cv2.imread('...') # Load in image here
B = (1.0/25.0)*np.ones((5,5)) # Specify kernel here
C = cv2.filter2D(A, -1, B) # Convolve
H = np.floor(np.array(B.shape)/2).astype(np.int) # Find half dims of kernel
C = C[H[0]:-H[0],H[1]:-H[1]] # Cut away unwanted information
Take note that cv2.filter2D
performs correlation, not convolution. However if the kernel is symmetric (that is if you take the transpose and it equals itself), correlation and convolution are equivalent. If this is not the case, you will need to perform a 180 degree rotation of the kernel before using cv2.filter2D
. You can do that by simply doing:
B = B[::-1,::-1]
In order to compare, we can show that the above code is equivalent to use scipy
's convolve2D
function. Here's a reproducible IPython session that shows us this:
In [41]: import cv2
In [42]: import numpy as np
In [43]: from scipy.signal import convolve2d
In [44]: A = np.reshape(np.arange(49), (7,7)).astype(np.float32)
In [45]: A
Out[45]:
array([[ 0., 1., 2., 3., 4., 5., 6.],
[ 7., 8., 9., 10., 11., 12., 13.],
[ 14., 15., 16., 17., 18., 19., 20.],
[ 21., 22., 23., 24., 25., 26., 27.],
[ 28., 29., 30., 31., 32., 33., 34.],
[ 35., 36., 37., 38., 39., 40., 41.],
[ 42., 43., 44., 45., 46., 47., 48.]], dtype=float32)
In [46]: B = (1.0/25.0)*np.ones((5,5), dtype=np.float32)
In [47]: B
Out[47]:
array([[ 0.04, 0.04, 0.04, 0.04, 0.04],
[ 0.04, 0.04, 0.04, 0.04, 0.04],
[ 0.04, 0.04, 0.04, 0.04, 0.04],
[ 0.04, 0.04, 0.04, 0.04, 0.04],
[ 0.04, 0.04, 0.04, 0.04, 0.04]], dtype=float32)
In [48]: C = cv2.filter2D(A, -1, B)
In [49]: H = np.floor(np.array(B.shape)/2).astype(np.int)
In [50]: C = C[H[0]:-H[0],H[1]:-H[1]]
In [51]: C
Out[51]:
array([[ 15.99999809, 16.99999809, 18. ],
[ 22.99999809, 24. , 24.99999809],
[ 29.99999809, 30.99999809, 31.99999809]], dtype=float32)
In [52]: C2 = convolve2d(A, B, mode='valid')
In [53]: C2
Out[53]:
array([[ 15.99999905, 17.00000191, 18.00000191],
[ 22.99999809, 23.99999809, 24.99999809],
[ 29.99999809, 30.99999809, 31.99999809]], dtype=float32)
The example is quite simple to understand. I declare a dummy matrix of 7 x 7 where the values increase from 0 to 48 row-wise. I also declare a 5 x 5 kernel of (1/25)
for each element so this would essentially implement a 5 x 5 average filter. We thus use cv2.filter2D
and scipy.signal.convolve2d
to extract out only the valid portions of the convolution result. As far as precision goes, C
which is the output of cv2.filter2D
and C2
which is the output of convolve2d
are both equivalent. Take special note of not only the actual contents but the shape of both output arrays.
However, if you wish to keep the size of the original image and replace the affected pixels by the filtered results, simply make a copy of the original image and use the same indexing logic that was used to cut away the information that was invalid with replacing those pixels in the copy with the convolved result:
C_copy = A.copy()
C_copy[H[0]:-H[0],H[1]:-H[1]] = C
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With