Convolution without any padding-opencv Python
<p>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.</p>

<p>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 <a href="http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.convolve2d.html" rel="nofollow"><code>scipy</code>'s 2D convolution method</a> with the <code>'valid'</code> option.  </p>

<p>As such, assuming that your image is stored in <code>A</code> and your kernel is stored in <code>B</code>, 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 <code>C</code>.</p>

<pre><code>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
</code></pre>

<p>Take note that <code>cv2.filter2D</code> performs <strong>correlation</strong>, 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 <code>cv2.filter2D</code>.  You can do that by simply doing:</p>

<pre><code>B = B[::-1,::-1]
</code></pre>

<p>In order to compare, we can show that the above code is equivalent to use <code>scipy</code>'s <code>convolve2D</code> function.  Here's a reproducible IPython session that shows us this:</p>

<pre><code>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)
</code></pre>

<p>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 <code>(1/25)</code> for each element so this would essentially implement a 5 x 5 average filter.  We thus use <code>cv2.filter2D</code> and <code>scipy.signal.convolve2d</code> to extract out only the valid portions of the convolution result.  As far as precision goes, <code>C</code> which is the output of <code>cv2.filter2D</code> and <code>C2</code> which is the output of <code>convolve2d</code> are both equivalent.  Take special note of not only the actual contents but the shape of both output arrays.</p>

<p>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:</p>

<pre><code>C_copy = A.copy()
C_copy[H[0]:-H[0],H[1]:-H[1]] = C 
</code></pre>

python opencv numpy image-processing