Edge letter recognition prototype model


In [1]:
import cv2
import numpy as np

from shredsim import classifier
from shredsim import utils
from shredsim import dataset
from shredsim import border as border_m

import matplotlib
matplotlib.rc('font', family='Arial')
%pylab inline


gnumpy: failed to import cudamat. Using npmat instead. No GPU will be used.
Populating the interactive namespace from numpy and matplotlib
/Users/yvaravva/.virtualenvs/shred/lib/python2.7/site-packages/nolearn/dbn.py:17: UserWarning: 
The nolearn.dbn module will be removed in nolearn 0.6.  If you want to
continue to use this module, please consider copying the code into
your own project.  And take a look at Lasagne and nolearn.lasagne for
a better neural net toolkit.

  """)

In [2]:
source, shred_config = utils.load_targets()
mask = shred_config.mask
imshow(source, cmap='gray')
print "Document used for training/testing."


Document used for training/testing.

In [3]:
graph = utils.cut_to_shreds(source.shape, shred_config)
print 'Total shreds:',len(graph)

for node in graph.nodes():
    if not utils.is_good_node(source[graph.node[node]['slice']]):
        graph.remove_node(node)
print "'Good', non-empty shreds:", len(graph)


Total shreds: 282
'Good', non-empty shreds: 123

In [4]:
pattern = np.zeros(source.shape)
for n in graph:
    pattern[dataset.to_slice(n, shred_config.mask.shape)] = shred_config.mask
imshow(pattern, cmap='gray')
print "Non-empty shreds layout."


Non-empty shreds layout.

In [5]:
# Pick random shred for further processing.
import random
key1 = random.choice(graph.nodes())
# Apply shred mask to a random rectangular doc slice.
subplot(131)
title("Mask")
imshow(mask, cmap='gray')
subplot(132)
title("Doc region")
imshow(source[graph.node[key1]['slice']], cmap='gray')
subplot(133)
title("Masked region")
imshow(utils.masked_shred(source[graph.node[key1]['slice']], mask), cmap='gray')
print mask.shape


(587, 119)

In [6]:
# Pad shred mask and determine border points.
# A window slides over border points to find partial characters.

padded_mask = dataset.pad_image(mask, dataset.WINDOW_SIDE)

border_obj = border_m.ShredMaskBorder(padded_mask)
border = border_obj.get_border_mask()
figure(num=None, figsize=(5, 10), facecolor='w', edgecolor='k')
subplot(131)
title("Padded mask")
imshow(padded_mask, cmap='gray')
subplot(132)
title("Inner border")
imshow(border, cmap='gray')
subplot(133)
title("Inner border position")
imshow(cv2.bitwise_xor(padded_mask, border), cmap='gray')

border_points = border_obj.get_border_points()  # Coordinates within padded mask/shred image.
print padded_mask.shape


(687, 219)

In [7]:
all_samples, all_labels = classifier.get_dataset()
print len(all_samples)


145287

In [14]:
import os, sys
sys.path.append(os.path.dirname(classifier.__file__))

In [15]:
cl = classifier.get_classifier()
cl2 = classifier.get_classifier(classifier_type='lsh')

In [16]:
shred = utils.masked_shred(source[graph.node[key1]['slice']], mask)

padded_shred = dataset.pad_image(shred, dataset.WINDOW_SIDE)
imshow(shred, cmap='gray')

# Windows from this shred's borders.
samples = []
sample_coords = []
c = 0
for b in border_points:   
    window_origin = b - dataset.WINDOW_SHAPE / 2
    window_slice_index = dataset.to_slice(window_origin, dataset.WINDOW_SHAPE)
    window = padded_shred[window_slice_index]

    mask_window = padded_mask[window_slice_index]
    outermost = utils.preserve_outermost(window, mask_window)
    
    if not utils.is_good_node(outermost):
        continue
    
    sample = (outermost / 255.).flatten()
    samples.append(sample)
    sample_coords.append(window_origin)
    
    c += 1

    #output = padded_shred.copy()
    #cv2.imshow("Window", window)
    #cv2.rectangle(output, tuple((b-window_shape/2)[::-1]), tuple((b + window_shape/2)[::-1]), (255,0,0,255))
    #cv2.imshow("Shred", output)
    #cv2.waitKey(10)
samples = np.array(samples)
print samples.shape


(736, 2500)

In [17]:
res = cl.predict(samples)

In [18]:
#res2 = cl2.predict(samples)

In [19]:
import collections

found_labels = set(res)
num_labels = len(found_labels)
colors = np.random.randint(0, 256, size=(num_labels, 4))
colors[:, 3] = 255

label2color = dict(zip(found_labels, colors))
print "Total labels:", num_labels

top_labels_to_pick = 7
top_labels = [x[0] for x in collections.Counter(res).most_common(top_labels_to_pick)]

row_height = 80
legend = np.ones(((top_labels_to_pick+1) * row_height, 400, 3), dtype=shred.dtype) * 255

output = cv2.cvtColor(padded_shred.copy(), cv2.cv.CV_GRAY2BGRA)
for coords, label in zip(sample_coords, res):
    if label not in top_labels: continue
    coords = coords +  dataset.WINDOW_SHAPE / 2
    cv2.circle(output, (coords[1], coords[0]), 5, label2color[label], thickness=-1)

    
covered_area = cv2.dilate(border, np.ones(dataset.WINDOW_SHAPE/2))
        
figure(num=None, figsize=(15, 10))
subplot(171)
imshow(dataset.pad_image(source[graph.node[key1]['slice']], dataset.WINDOW_SIDE), cmap='gray')
subplot(172)
imshow(padded_mask, cmap='gray')
subplot(173)
imshow(padded_shred, cmap='gray')
subplot(174)
imshow(covered_area, cmap='gray')
subplot(175)
imshow(cv2.bitwise_and(padded_shred, padded_shred, mask=covered_area), cmap='gray')
subplot(176)
imshow(output)
subplot(177)
    
for i, label in enumerate(top_labels):
    cv2.circle(legend, (30, (i+1) * row_height), 15, label2color[label][:3], thickness=-1)
    text(60, (i+1.1) * row_height, unicode("%s (%d)" % (label, collections.Counter(res)[label]), 'utf-8'), color='black', fontsize=20)

imshow(legend)


Total labels: 37
Out[19]:
<matplotlib.image.AxesImage at 0x113a45f10>

In [20]:
i = np.random.randint(0, len(res))

print i, len(res)

image = (samples[i] * 255).reshape(dataset.WINDOW_SHAPE).astype("uint8")

output = padded_shred.copy()
point_a = sample_coords[i] [::-1]
point_b = tuple(point_a + dataset.WINDOW_SHAPE)
cv2.rectangle(output, tuple(point_a), point_b, (250), 2)

subplot(141)
imshow(utils.preserve_outermost(image, mask_window), cmap='gray')
subplot(142)
imshow(output, cmap='gray')

proba = cl.predict_proba(samples[i:i+1])[0]
proba = (proba*100).astype('int8')

cl2_prediction = cl2.predict(samples[i:i+1])

subplot(122)
plt.bar(range(len(proba)), proba, align='center')
_ = plt.xticks(range(len(proba)), map(lambda x: unicode(x, 'utf-8'), cl._dbn.classes_), rotation=25)

print "Sample window classification"
for c, prob in zip(cl._dbn.classes_[proba>0], proba[proba>0]):
    print c, prob

print "Custom super classifier prediction:", cl2_prediction[0]


29 736
Sample window classification
И_ 2
Й_ 92
Ю_ 3
Custom super classifier prediction: Ш_

In [21]:
flat_image = image.flatten().astype(np.float32)
all_distances = [np.linalg.norm(flat_image - sample) for sample in all_samples]

In [22]:
closest_idx = np.argmin(all_distances)
closest = all_samples[closest_idx].reshape(dataset.WINDOW_SHAPE)
closest_label = all_labels[closest_idx]

subplot(121)
title("Window image")
imshow(image, 'gray')
subplot(122)
title("Closest match from the dataset")
imshow(closest, 'gray')

print "Bitwise closest image"
print "Closest label:", closest_label, "distance:", all_distances[closest_idx], "idx:", closest_idx


Bitwise closest image
Closest label: Ш_ distance: 3685.36 idx: 116037

In [23]:
with classifier.Profile("DBN prediction"):
    print cl.predict(np.array([samples[i]]))[0]
with classifier.Profile("DBNNN prediction"):
    print cl2.predict(np.array([samples[i]]))[0]


Й_
Ш_

In [24]:
(trainX, testX, trainY, testY) = classifier.train_test_split(
            all_samples / 255.0, all_labels, test_size = 0.1)

In [25]:
print len(testX)


14529

In [26]:
with classifier.Profile("cl report"):
    preds = cl.predict(testX)
    print classifier.classification_report(testY, preds)


             precision    recall  f1-score   support

          0       0.85      0.89      0.87       171
          1       0.77      0.83      0.80        93
          2       0.95      0.94      0.94       192
          3       0.87      0.90      0.88       162
          4       0.80      0.75      0.77       186
          5       0.83      0.78      0.81       167
          6       0.84      0.79      0.82       188
          7       0.96      0.99      0.97       156
          8       0.83      0.89      0.86       141
          9       0.75      0.79      0.77       154
        І_       0.41      0.66      0.51       109
      Ї_       0.63      0.62      0.62       125
        А_       0.90      0.87      0.88       272
        Б_       0.75      0.73      0.74       256
        В_       0.70      0.80      0.74       251
        Г_       0.61      0.64      0.63       197
        Д_       0.70      0.58      0.64       331
        Е_       0.80      0.78      0.79       222
        Ж_       0.80      0.75      0.78       374
        З_       0.91      0.87      0.89       245
        И_       0.65      0.73      0.69       260
      Й_       0.68      0.63      0.65       326
        К_       0.73      0.76      0.75       292
        Л_       0.67      0.68      0.67       244
        М_       0.77      0.78      0.78       310
        Н_       0.79      0.93      0.85       247
        О_       0.70      0.79      0.74       250
        П_       0.58      0.56      0.57       264
        Р_       0.75      0.70      0.72       196
        С_       0.84      0.87      0.86       243
        Т_       0.71      0.69      0.70       222
        У_       0.88      0.92      0.90       286
        Ф_       0.86      0.98      0.92       212
        Х_       0.84      0.88      0.86       254
        Ц_       0.64      0.64      0.64       335
        Ч_       0.83      0.83      0.83       247
        Ш_       0.57      0.61      0.59       345
        Щ_       0.63      0.56      0.59       442
        Ь_       0.69      0.60      0.64       217
        Ю_       0.62      0.54      0.58       344
        Я_       0.71      0.75      0.73       237
         а       0.95      0.82      0.88       109
         б       0.78      0.70      0.74       171
         в       0.90      0.85      0.88        99
         г       0.87      0.80      0.83        98
         д       0.92      0.88      0.90       160
         е       0.87      0.90      0.88       108
         ж       0.75      0.82      0.78       180
         з       0.81      0.89      0.85       102
         и       0.82      0.77      0.79       133
       й       0.80      0.81      0.81       183
         к       0.79      0.77      0.78       138
         л       0.78      0.72      0.75       129
         м       0.89      0.80      0.84       148
         н       0.94      0.97      0.96       121
         о       0.71      0.73      0.72       109
         п       0.84      0.85      0.85       133
         р       0.71      0.82      0.76       173
         с       0.88      0.77      0.82       100
         т       0.78      0.62      0.69       129
         у       0.86      0.83      0.84       183
         ф       0.83      0.89      0.86       340
         х       0.81      0.82      0.81       104
         ц       0.62      0.54      0.58       145
         ч       0.91      0.89      0.90       103
         ш       0.56      0.62      0.59       193
         щ       0.53      0.53      0.53       212
         ь       0.94      0.97      0.96       102
         ю       0.81      0.82      0.82       199
         я       0.93      0.81      0.87       113
         і       0.86      0.91      0.88        74
       ї       0.88      0.83      0.86       103
        №       0.77      0.75      0.76       370

avg / total       0.76      0.76      0.76     14529


In [27]:
with classifier.Profile("cl2 report"):
    preds = cl2.predict(testX)
    print classifier.classification_report(testY, preds)


             precision    recall  f1-score   support

          0       1.00      1.00      1.00       171
          1       1.00      1.00      1.00        93
          2       1.00      1.00      1.00       192
          3       1.00      1.00      1.00       162
          4       1.00      1.00      1.00       186
          5       1.00      1.00      1.00       167
          6       1.00      1.00      1.00       188
          7       1.00      1.00      1.00       156
          8       1.00      1.00      1.00       141
          9       1.00      1.00      1.00       154
        І_       0.69      0.73      0.71       109
      Ї_       0.75      0.71      0.73       125
        А_       1.00      1.00      1.00       272
        Б_       1.00      1.00      1.00       256
        В_       1.00      1.00      1.00       251
        Г_       1.00      1.00      1.00       197
        Д_       1.00      1.00      1.00       331
        Е_       1.00      1.00      1.00       222
        Ж_       1.00      1.00      1.00       374
        З_       1.00      1.00      1.00       245
        И_       0.78      0.74      0.76       260
      Й_       0.80      0.84      0.82       326
        К_       1.00      1.00      1.00       292
        Л_       1.00      1.00      1.00       244
        М_       1.00      1.00      1.00       310
        Н_       1.00      1.00      1.00       247
        О_       1.00      1.00      1.00       250
        П_       1.00      0.99      0.99       264
        Р_       1.00      1.00      1.00       196
        С_       1.00      1.00      1.00       243
        Т_       0.99      1.00      0.99       222
        У_       1.00      1.00      1.00       286
        Ф_       1.00      1.00      1.00       212
        Х_       1.00      1.00      1.00       254
        Ц_       1.00      1.00      1.00       335
        Ч_       1.00      1.00      1.00       247
        Ш_       1.00      1.00      1.00       345
        Щ_       1.00      1.00      1.00       442
        Ь_       1.00      1.00      1.00       217
        Ю_       1.00      1.00      1.00       344
        Я_       1.00      1.00      1.00       237
         а       1.00      1.00      1.00       109
         б       1.00      1.00      1.00       171
         в       1.00      1.00      1.00        99
         г       1.00      1.00      1.00        98
         д       1.00      1.00      1.00       160
         е       1.00      1.00      1.00       108
         ж       1.00      1.00      1.00       180
         з       1.00      1.00      1.00       102
         и       0.96      0.92      0.94       133
       й       0.95      0.97      0.96       183
         к       1.00      1.00      1.00       138
         л       1.00      1.00      1.00       129
         м       1.00      1.00      1.00       148
         н       1.00      1.00      1.00       121
         о       1.00      1.00      1.00       109
         п       1.00      1.00      1.00       133
         р       1.00      1.00      1.00       173
         с       1.00      1.00      1.00       100
         т       1.00      1.00      1.00       129
         у       1.00      1.00      1.00       183
         ф       1.00      1.00      1.00       340
         х       1.00      1.00      1.00       104
         ц       1.00      1.00      1.00       145
         ч       1.00      1.00      1.00       103
         ш       1.00      1.00      1.00       193
         щ       1.00      1.00      1.00       212
         ь       1.00      1.00      1.00       102
         ю       1.00      1.00      1.00       199
         я       1.00      1.00      1.00       113
         і       1.00      1.00      1.00        74
       ї       1.00      1.00      1.00       103
        №       1.00      1.00      1.00       370

avg / total       0.99      0.99      0.99     14529