In [4]:
from PIL import Image
from glob import glob
import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina' # linux only
%matplotlib inline
import numpy as np

def charclass(png):     # extract character class name from file name
        return png.split('__')[1][:-4]

allpngs = sorted( glob('pngs/*.png') )

h,w,_ = np.array(Image.open(allpngs[0])).shape
h,w
selection = sorted({charclass(png) for png in allpngs}) # ['8','9','minus'] # 

pngs = [png for png in allpngs if charclass(png) in selection]
WT = np.empty( (len(selection), h*w ) )

def get_avg(pngs):
    h,w,_ = np.array(Image.open(pngs[0])).shape
    avg = np.zeros((h,w))
    for png in pngs:
        a = 255 - np.array(Image.open(png))[:,:,0]  # NOTE I AM INVERTING THE IMAGE: MUST DO THIS CONSISTENTLY
        avg += a
    avg /= len(pngs)
    return avg

# Initially set weights for each class as the average over all training images in the class (normalized)
WT = np.empty( (len(selection), h*w ) )
for j,cc in enumerate(selection):
    spngs = [png for png in pngs if charclass(png)==cc]
    WT[j] = get_avg(spngs).reshape(h*w)
    WT[j] /= np.linalg.norm(WT[j])  # make the rows of W **unit** vectors

# Load flattened images as columns of big array X
X = np.empty((h*w,len(pngs)))
for i,png in enumerate(pngs):
    X[:,i] = 255 - np.array(Image.open(png))[:,:,0].reshape(h*w)

# Get the true class numbers of all the images
y = [selection.index(charclass(png)) for png in pngs]  # true classes of images
np.random.choice(y,10)

# Find the predicted class numbers
ypredicted = np.argmax(WT@X, axis=0)

percent_accuracy = 100*(ypredicted==y).sum()/len(pngs)
print('accuracy is {}%'.format(round(percent_accuracy)))
accuracy is 88.0%

Testing on the training data is not a valid thing to do.

In [7]:
# a legitimate test on some other images

allpngs = sorted( glob('testpngs/*.png') )
pngs = [png for png in allpngs if charclass(png) in selection]

# Load flattened images as columns of big array X
X = np.empty((h*w,len(pngs)))
for i,png in enumerate(pngs):
    X[:,i] = 255 - np.array(Image.open(png))[:,:,0].reshape(h*w)

# Get the true class numbers of all the images
y = [selection.index(charclass(png)) for png in pngs]  # true classes of images
np.random.choice(y,10)

# Find the predicted class numbers
ypredicted = np.argmax(WT@X, axis=0)

percent_accuracy = 100*(ypredicted==y).sum()/len(pngs)
print('accuracy is {}%'.format(round(percent_accuracy)))
accuracy is 86.0%

Still quite good!

In [7]:
from IPython.display import Image as ipdimage
ipdimage('20191113_151604_cropped.jpg',width=800)
Out[7]: