In [2]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

1 to 1 convolution

This will be our filter — it tests the presence of a horizontal line:

In [3]:
conv_hline = [
    [-1,-1,-1],
    [ 2, 2, 2],
    [-1,-1,-1]
]
plt.imshow(conv_hline, cmap='gray_r')
Out[3]:
<matplotlib.image.AxesImage at 0x7f938140e080>

Dot product between a horizontal line and the horizontal line filter:

In [4]:
data = [
    [0,0,0],
    [1,1,1],
    [0,0,0]
]
s = np.tensordot(data, conv_hline)

plt.imshow(data, cmap='gray_r')
plt.title('Dot product: {:.2f}'.format(s))
Out[4]:
Text(0.5, 1.0, 'Dot product: 6.00')

Dot product between a vertical line and the horizontal line filter:

In [5]:
data = [
    [1,0,0],
    [1,0,0],
    [1,0,0]
]
s = np.tensordot(data, conv_hline)

plt.imshow(data, cmap='gray_r')
plt.title('Dot product: {:.2f}'.format(s))
Out[5]:
Text(0.5, 1.0, 'Dot product: 0.00')

Sliding convolution

Now, we want to detect parts of an image that contain certain features, such as horizontal lines.

In [6]:
img = plt.imread('https://i.imgur.com/BeRusDc.png')

plt.imshow(img, cmap='gray')
Out[6]:
<matplotlib.image.AxesImage at 0x7f9380a08f28>
In [7]:
img.shape
Out[7]:
(188, 233)

We will apply our 3x3 filter on 3x3 pixels of the image, sliding from top to bottom, left to right.

In [8]:
height, width = img.shape
res = []

for i in range(height-3+1):
    line = []

    for j in range(width-3+1):
        s = np.tensordot(img[i:i+3,j:j+3], conv_hline)

        line.append(float(s))

    res.append(line)

The dot product of all 3x3 pixels convoluted with the horizontal line filter is now an image that only contains horizontal lines.

In [9]:
img_h = np.array(res).reshape(height-3+1, -1)
img_h.shape
Out[9]:
(186, 231)
In [10]:
plt.imshow(img_h, cmap='gray_r')
Out[10]:
<matplotlib.image.AxesImage at 0x7f93809bd358>

Combining convolutions

We will do the same thing with vertical lines.

In [11]:
conv_vline = [
    [-1,2,-1],
    [-1,2,-1],
    [-1,2,-1]
]
plt.imshow(conv_vline, cmap='gray_r')
Out[11]:
<matplotlib.image.AxesImage at 0x7f938005f908>
In [12]:
height, width = img.shape
res = []

for i in range(height-3+1):
    line = []

    for j in range(width-3+1):
        s = np.tensordot(img[i:i+3,j:j+3], conv_vline)

        line.append(float(s))

    res.append(line)
In [13]:
img_v = np.array(res).reshape(height-3+1, -1)
img_v.shape
Out[13]:
(186, 231)
In [14]:
plt.imshow(img_v, cmap='gray_r')
Out[14]:
<matplotlib.image.AxesImage at 0x7f937af95898>

If we add the two, the image now contains horizontal and vertical lines. We basically just simplified the initial image.

In [15]:
plt.imshow(img_v + img_h, cmap='gray_r')
Out[15]:
<matplotlib.image.AxesImage at 0x7f937af7a3c8>