In [7]:
import logging
import math
import ast

class SudokuMatrix(object):
    """Build monochrome matrix of the sudoku board.
        You can add new scans to the matrix and then you can normalize the
        results. Each scan is an arc of measurements.
    """

    # The radius of the circle covered by the scanning device.
    k_scanner_radius_mm = 48
    # A map from coordinates to a list of measurements for that point in space.
    measurements = {}

    def add_scan(self, cx, cy, degrees, measures):
        """cx, cy center of the measuring device
            degrees the size of the arc measured
            measures the samples gathered while measuring (we assume these are
                uniformly distributed along the movement arc).
        """
        if len(measures) < 1:
            logging.exception("No measurements provided")
        for i in range(0, len(measures)):
            deg_moved = degrees * i / len(measures)
            angle = math.radians(degrees / 2 - deg_moved)
            a = self.k_scanner_radius_mm * math.cos(angle)
            b = self.k_scanner_radius_mm * math.sin(angle)
            px = cx - b
            py = cy + a
            # x axis sampling is twice as much as y axis
            p = (int(math.floor(px * 2)), int(math.floor(py)))
            if p not in self.measurements:
                self.measurements[p] = []
            self.measurements[p].append(measures[i])
            print(px, py, measures[i])
        print('Scan added')

    def to_str(self):
        return str(self.measurements)
        
    def dump_to_file(self, filename):
        with open(filename, 'w') as f:
            f.write(str(self.measurements))
            f.close()

    def load_from_file(self, filename):
        fstr = ""
        try:
            with open(filename, 'r') as f:
                fstr = f.read()
                f.close()
            self.measurements = ast.literal_eval(fstr)
        except Exception as e:
            print('Unable to load file:')
            print(str(e))

In [125]:
import numpy as np

def load_scan(file_name):
    m = SudokuMatrix()
    m.load_from_file('/home/ch/ev3dev/share/ev3-repo/' + file_name)
    return m
    
def build_matrix(m):
    """
      Convert the measurements in a SudokuMatrix into a numpy array.
    """
    a = m.measurements
    aav = dict()
    minx = 1 << 20
    maxx = - (1 << 20)
    miny = 1 << 20
    maxy = - (1 << 20)
    
    for k, v in a.iteritems():
        aav[k] = sum(v)/len(v)
        minx = min(minx, k[0])
        maxx = max(maxx, k[0])
        miny = min(miny, k[1])
        maxy = max(maxy, k[1])
        
    arr = []
    for i in range(minx, maxx):
        arr.append([])
        for j in range(miny, maxy):
            arr[i - minx].append(aav.get((i, j), 0))
    return np.array(arr)    

def center_of_mass(matrix):
    total = 0.0
    mx = 0.0
    my = 0.0
    for i in xrange(0, len(matrix)):
        for j in xrange(0, len(matrix[i])):
            total += matrix[i][j]
            mx += matrix[i][j] * i
            my += matrix[i][j] * j
    return [mx / total, my / total]

def distance(p1, p2):
    return math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]))
            
def center_of_mass_filter(image):
    k_kernel_size = 8
    res = np.zeros(image.shape)
    
    for i in xrange(k_kernel_size, len(image) - k_kernel_size + 1):
        for j in xrange(k_kernel_size, len(image[i]) - k_kernel_size + 1):
            cm = center_of_mass(image[i - k_kernel_size: i + k_kernel_size, j - k_kernel_size: j + k_kernel_size])
            d1 = abs(cm[0] - k_kernel_size)
            d2 = abs(cm[1] - k_kernel_size)
            res[i][j] = 100 if d1 < 0.2 and d2 < 0.2 else 0 
    return res

In [53]:
m = load_scan('slim_left.txt')
arr_left = build_matrix(m)
m = load_scan('slim_center.txt')
arr_center = build_matrix(m)
m = load_scan('slim_right.txt')
arr_right = build_matrix(m)

In [54]:
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

In [55]:
plt.subplot(1, 3, 1)
plt.imshow(np.rot90(arr_right), cmap=plt.cm.gray, interpolation='none')
plt.subplot(1, 3, 2)
plt.imshow(np.rot90(arr_center), cmap=plt.cm.gray, interpolation='none')
plt.subplot(1, 3, 3)
plt.imshow(np.rot90(arr_left), cmap=plt.cm.gray, interpolation='none')
plt.show()



In [126]:
s = center_of_mass_filter(arr_right)

In [127]:
plt.imshow(np.rot90(s), cmap=plt.cm.gray, interpolation='none')


Out[127]:
<matplotlib.image.AxesImage at 0x7f896d86a250>

In [143]:
from skimage import data, io
from skimage.transform import resize
import skimage as si
import skimage.filter as skf
import skimage.restoration as skr
im = skf.sobel(np.rot90(arr_right.astype(np.float64)))
thresh = skf.threshold_otsu(im)
plt.imshow(im > thresh, cmap=plt.cm.gray, interpolation='none')


Out[143]:
<matplotlib.image.AxesImage at 0x7f895e8bd490>

In [232]:
# Author: Gael Varoquaux <gael dot varoquaux at normalesup dot org>
# License: BSD 3 clause

# Standard scientific Python imports
import matplotlib.pyplot as plt

# Import datasets, classifiers and performance metrics
from sklearn import datasets, svm, metrics
from sklearn.ensemble import GradientBoostingClassifier

# The digits dataset
digits = datasets.load_digits()

# The data that we are interested in is made of 8x8 images of digits, let's
# have a look at the first 3 images, stored in the `images` attribute of the
# dataset.  If we were working from image files, we could load them using
# pylab.imread.  Note that each image must have the same size. For these
# images, we know which digit they represent: it is given in the 'target' of
# the dataset.
def dou(matrix):
    dr = []
    for row in matrix:
        q = []
        for j in row:
            q += [j, j]        
        dr += [q, q]
    return dr

images_and_labels = list(zip(digits.images, digits.target))
for index, (image, label) in enumerate(images_and_labels[:4]):
    plt.subplot(2, 4, index + 1)
    plt.axis('off')
    plt.imshow(dou(image), cmap=plt.cm.gray_r, interpolation='none')
    plt.title('Training: %i' % label)

# To apply a classifier on this data, we need to flatten the image, to
# turn the data in a (samples, feature) matrix:
n_samples = len(digits.images)

# Resize the images
big_images = np.asarray([skf.threshold_adaptive(np.asarray(dou(im)), 16).astype(np.int32) for im in digits.images])
data = big_images.reshape((n_samples, -1))

# Create a classifier: a support vector classifier
classifier = svm.SVC(gamma=0.001)

# We learn the digits on the first half of the digits
classifier.fit(data[:n_samples / 2], digits.target[:n_samples / 2])

# Now predict the value of the digit on the second half:
expected = digits.target[n_samples / 2:]
predicted = classifier.predict(data[n_samples / 2:])

print("Classification report for classifier %s:\n%s\n"
      % (classifier, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))

images_and_predictions = list(zip(digits.images[n_samples / 2:], predicted))
for index, (image, prediction) in enumerate(images_and_predictions[:4]):
    plt.subplot(2, 4, index + 5)
    plt.axis('off')
    plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')
    plt.title('Prediction: %i' % prediction)

plt.show()


Classification report for classifier SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0, degree=3,
  gamma=0.001, kernel='rbf', max_iter=-1, probability=False,
  random_state=None, shrinking=True, tol=0.001, verbose=False):
             precision    recall  f1-score   support

          0       0.97      0.98      0.97        88
          1       0.93      0.85      0.89        91
          2       0.87      0.87      0.87        86
          3       0.87      0.85      0.86        91
          4       0.99      0.92      0.96        92
          5       0.85      0.87      0.86        91
          6       0.97      0.98      0.97        91
          7       0.89      0.94      0.92        89
          8       0.92      0.74      0.82        88
          9       0.72      0.91      0.81        92

avg / total       0.90      0.89      0.89       899


Confusion matrix:
[[86  0  0  0  0  1  0  0  1  0]
 [ 0 77  6  1  0  0  1  0  1  5]
 [ 1  0 75  6  0  0  0  0  1  3]
 [ 0  1  1 77  0  3  0  4  1  4]
 [ 2  1  0  0 85  1  0  2  1  0]
 [ 0  0  0  0  0 79  1  0  0 11]
 [ 0  1  1  0  0  0 89  0  0  0]
 [ 0  1  1  0  1  2  0 84  0  0]
 [ 0  2  2  3  0  4  1  2 65  9]
 [ 0  0  0  2  0  3  0  2  1 84]]

In [170]:
print np.max(digits.images)
seven_normalized = (3 - ((seven - np.min(seven)) * 4 / (np.max(seven) - np.min(seven)))) * 4
print classifier.predict(np.asarray(dou(digits.images[17])).flatten())
print classifier.predict(seven_normalized.astype(np.float64).flatten())


16.0
[7]
[8]

In [171]:
seven_normalized


Out[171]:
array([[ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  4,  0,  4,  4,  8,  4,  8,  4,  4,  4,  0,  0],
       [ 0,  0,  0,  4,  8,  8, 12,  8, 12, 12,  8,  8,  4,  4,  0,  0],
       [ 0,  0,  4,  8,  8,  8,  8,  8,  8,  8, 12, 12,  4,  0,  0,  0],
       [ 0,  0,  0,  4,  0,  0,  4,  8,  8, 12, 12, 12,  4,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  4, 12, 12,  8,  4,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  4,  8, 12, 12,  8,  4,  0,  0,  0,  0],
       [ 0,  0, -4,  0,  0,  0, 12, 12, 12, 12,  4,  4,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  4,  4, 12, 12, 12,  8,  4,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  8,  8, 12, 12,  8,  4,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  4,  8, 12, 12, 12,  4,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  4,  4,  8,  4,  4,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  4,  0,  4,  0,  4,  0,  4,  0,  4,  4,  0,  0]])

In [168]:
np.asarray(dou(digits.images[17])).astype(np.int32)


Out[168]:
array([[ 0,  0,  0,  0,  1,  1,  8,  8, 15, 15, 10, 10,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  1,  1,  8,  8, 15, 15, 10, 10,  0,  0,  0,  0],
       [ 0,  0,  3,  3, 13, 13, 15, 15, 14, 14, 14, 14,  0,  0,  0,  0],
       [ 0,  0,  3,  3, 13, 13, 15, 15, 14, 14, 14, 14,  0,  0,  0,  0],
       [ 0,  0,  5,  5, 10, 10,  0,  0, 10, 10, 12, 12,  0,  0,  0,  0],
       [ 0,  0,  5,  5, 10, 10,  0,  0, 10, 10, 12, 12,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  3,  3,  5,  5, 15, 15, 10, 10,  2,  2,  0,  0],
       [ 0,  0,  0,  0,  3,  3,  5,  5, 15, 15, 10, 10,  2,  2,  0,  0],
       [ 0,  0,  0,  0, 16, 16, 16, 16, 16, 16, 16, 16, 12, 12,  0,  0],
       [ 0,  0,  0,  0, 16, 16, 16, 16, 16, 16, 16, 16, 12, 12,  0,  0],
       [ 0,  0,  1,  1,  8,  8, 12, 12, 14, 14,  8,  8,  3,  3,  0,  0],
       [ 0,  0,  1,  1,  8,  8, 12, 12, 14, 14,  8,  8,  3,  3,  0,  0],
       [ 0,  0,  0,  0,  0,  0, 10, 10, 13, 13,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0, 10, 10, 13, 13,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0, 11, 11,  9,  9,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0, 11, 11,  9,  9,  0,  0,  0,  0,  0,  0]], dtype=int32)

In [172]:
for index, (image, label) in enumerate(images_and_labels[16:20]):
    plt.subplot(2, 4, index + 1)
    plt.axis('off')
    plt.imshow(dou(seven_normalized), cmap=plt.cm.gray_r, interpolation='nearest')
    plt.title('Training: %i' % label)



In [251]:
from sklearn.ensemble import GradientBoostingClassifier
# BDT
classifier_BDT = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0, max_depth=12, random_state=3)

# We learn the digits on the first half of the digits
classifier_BDT.fit(data[:n_samples / 2], digits.target[:n_samples / 2])

# Now predict the value of the digit on the second half:
expected = digits.target[n_samples / 2:]
predicted = classifier_BDT.predict(data[n_samples / 2:])

print("Classification report for classifier %s:\n%s\n"
      % (classifier_BDT, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))


Classification report for classifier GradientBoostingClassifier(init=None, learning_rate=1.0, loss='deviance',
              max_depth=12, max_features=None, max_leaf_nodes=None,
              min_samples_leaf=1, min_samples_split=2, n_estimators=100,
              random_state=3, subsample=1.0, verbose=0, warm_start=False):
             precision    recall  f1-score   support

          0       0.94      0.97      0.96        88
          1       0.90      0.82      0.86        91
          2       0.85      0.90      0.87        86
          3       0.84      0.74      0.78        91
          4       0.96      0.71      0.81        92
          5       0.89      0.88      0.88        91
          6       0.96      0.97      0.96        91
          7       0.90      0.90      0.90        89
          8       0.77      0.61      0.68        88
          9       0.56      0.89      0.69        92

avg / total       0.86      0.84      0.84       899


Confusion matrix:
[[85  0  2  0  0  1  0  0  0  0]
 [ 0 75  2  2  1  0  0  0  3  8]
 [ 1  1 77  1  0  1  0  2  1  2]
 [ 0  3  5 67  0  1  0  2  3 10]
 [ 4  0  0  0 65  0  1  3  3 16]
 [ 0  0  0  0  2 80  2  0  0  7]
 [ 0  1  0  0  0  0 88  0  1  1]
 [ 0  0  0  0  0  1  1 80  3  4]
 [ 0  3  5  7  0  2  0  1 54 16]
 [ 0  0  0  3  0  4  0  1  2 82]]

In [253]:
print np.max(digits.images)
seven_normalized = (3 - ((seven - np.min(seven)) * 4 / (np.max(seven) - np.min(seven)))) * 4
seven_t = 1 - skf.threshold_adaptive(seven.astype(np.float64), 16)
six_t = 1 - skf.threshold_adaptive(six.astype(np.float64), 16)
print classifier_BDT.predict(np.asarray(dou(digits.images[17])).flatten())
print classifier_BDT.predict(seven_t.flatten())


16.0
[4]
[8]

In [82]:
mo = one - np.min(one)
len((mo.astype(np.float64) / np.max(mo) * 2 - 1).flatten())


Out[82]:
196

In [5]:
import os


Out[5]:
<module 'posixpath' from '/home/ch/anaconda/lib/python2.7/posixpath.pyc'>

In [59]:
#### Detect where digits are.
np.max(arr_right)


Out[59]:
85

In [ ]: