Commit 84952000 authored by Jayke Meijer's avatar Jayke Meijer

Merge branch 'master' of github.com:taddeus/licenseplates

parents 93292816 a68fe0cd
...@@ -6,12 +6,6 @@ class Character: ...@@ -6,12 +6,6 @@ class Character:
self.corners = corners self.corners = corners
self.image = image self.image = image
# Testing purposes
def show(self):
from pylab import imshow, show
imshow(self.data, cmap="gray")
show()
def get_feature_vector(self): def get_feature_vector(self):
pattern = LocalBinaryPatternizer(self.image) pattern = LocalBinaryPatternizer(self.image)
......
from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \ from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \
LINEAR, svm_save_model, svm_load_model svm_save_model, svm_load_model
from cPickle import dump, load from cPickle import dump, load
...@@ -13,7 +13,7 @@ class Classifier: ...@@ -13,7 +13,7 @@ class Classifier:
f.close() f.close()
else: else:
self.param = svm_parameter() self.param = svm_parameter()
self.param.kernel_type = LINEAR self.param.kernel_type = 2
self.param.C = c self.param.C = c
self.character_map = {} self.character_map = {}
self.model = None self.model = None
......
...@@ -3,63 +3,63 @@ from LicensePlate import LicensePlate ...@@ -3,63 +3,63 @@ from LicensePlate import LicensePlate
from Classifier import Classifier from Classifier import Classifier
from cPickle import dump, load from cPickle import dump, load
#chars = [] chars = []
#
#for i in range(9): for i in range(9):
# for j in range(100): for j in range(100):
# try: try:
# filename = '%04d/00991_%04d%02d.info' % (i, i, j) filename = '%04d/00991_%04d%02d.info' % (i, i, j)
# print 'loading file "%s"' % filename print 'loading file "%s"' % filename
# plate = LicensePlate(i, j) plate = LicensePlate(i, j)
#
# if hasattr(plate, 'characters'): if hasattr(plate, 'characters'):
# chars.extend(plate.characters) chars.extend(plate.characters)
# except: except:
# print 'epic fail' print 'epic fail'
#
#print 'loaded %d chars' % len(chars) print 'loaded %d chars' % len(chars)
#
#dump(chars, file('chars', 'w+')) dump(chars, file('chars', 'w+'))
#---------------------------------------------------------------- #----------------------------------------------------------------
#chars = load(file('chars', 'r')) chars = load(file('chars', 'r'))
#learned = [] learned = []
#learning_set = [] learning_set = []
#test_set = [] test_set = []
#
#for char in chars: for char in chars:
# if learned.count(char.value) > 80: if learned.count(char.value) > 80:
# test_set.append(char) test_set.append(char)
# else: else:
# learning_set.append(char) learning_set.append(char)
# learned.append(char.value) learned.append(char.value)
#
#dump(learning_set, file('learning_set', 'w+')) dump(learning_set, file('learning_set', 'w+'))
#dump(test_set, file('test_set', 'w+')) dump(test_set, file('test_set', 'w+'))
#---------------------------------------------------------------- #----------------------------------------------------------------
learning_set = load(file('learning_set', 'r')) learning_set = load(file('learning_set', 'r'))
# Train the classifier with the learning set # Train the classifier with the learning set
classifier = Classifier(c=3) classifier = Classifier(c=30)
classifier.train(learning_set) classifier.train(learning_set)
#classifier.save('classifier') classifier.save('classifier')
#---------------------------------------------------------------- #----------------------------------------------------------------
#classifier = Classifier(filename='classifier') classifier = Classifier(filename='classifier')
#test_set = load(file('test_set', 'r')) test_set = load(file('test_set', 'r'))
#l = len(test_set) l = len(test_set)
#matches = 0 matches = 0
#
#for i, char in enumerate(test_set): for i, char in enumerate(test_set):
# prediction = classifier.classify(char) prediction = classifier.classify(char)
#
# if char.value == prediction: if char.value == prediction:
# print ':) ------> Successfully recognized "%s"' % char.value print ':) ------> Successfully recognized "%s"' % char.value,
# matches += 1 matches += 1
# else: else:
# print ':( Expected character "%s", got "%s"' \ print ':( Expected character "%s", got "%s"' \
# % (char.value, prediction), % (char.value, prediction),
#
# print ' -- %d of %d (%d%% done)' % (i + 1, l, int(100 * (i + 1) / l)) print ' -- %d of %d (%d%% done)' % (i + 1, l, int(100 * (i + 1) / l))
#
#print '\n%d matches (%d%%), %d fails' % (matches, \ print '\n%d matches (%d%%), %d fails' % (matches, \
# int(100 * matches / len(test_set)), \ int(100 * matches / len(test_set)), \
# len(test_set) - matches) len(test_set) - matches)
import traceback, os.path
class Error:
def __init__(self, message=None):
stack = traceback.extract_stack()
origin_of_call = stack[0]
where_it_went_wrong = stack[1]
if message:
print message, "\n"
print "Error in", origin_of_call[0], "on line", origin_of_call[1]
print " : ", origin_of_call[3], "\n"
# Inside try function, so -2 lines as exept and Error() are 2 lines
print "Function called in", where_it_went_wrong[0]
print "around line", (where_it_went_wrong[1] - 2), "\n"
\ No newline at end of file
from GrayscaleImage import GrayscaleImage from GrayscaleImage import GrayscaleImage
from scipy.ndimage import convolve1d from scipy.ndimage import convolve1d
from pylab import ceil, zeros, pi, e, exp, sqrt, array from pylab import ceil, zeros, pi, exp, sqrt, array
class GaussianFilter: class GaussianFilter:
def __init__(self, scale): def __init__(self, scale):
self.scale = scale self.scale = scale
def gaussian(self, x): def gaussian(self, x):
'''Return the value of a 1D Gaussian function for a given x and scale''' """Return the value of a 1D Gaussian function for a given x."""
return exp(-(x ** 2 / (2 * self.scale ** 2))) / (sqrt(2 * pi) * self.scale) return exp(-(x ** 2 / (2 * self.scale ** 2))) \
/ (sqrt(2 * pi) * self.scale)
def get_1d_gaussian_kernel(self): def get_1d_gaussian_kernel(self):
'''Sample a one-dimensional Gaussian function of scale s''' """Sample a one-dimensional Gaussian function of scale s."""
radius = int(ceil(3 * self.scale)) radius = int(ceil(3 * self.scale))
size = 2 * radius + 1 size = 2 * radius + 1
result = zeros(size) result = zeros(size)
# Sample the Gaussian function # Sample the Gaussian function
result = array([self.gaussian(x - radius) for x in xrange(size)]) result = array([self.gaussian(x - radius) for x in xrange(size)])
# The sum of all kernel values is equal to one # The sum of all kernel values is equal to one
result /= result.sum() result /= result.sum()
return result return result
def get_filtered_copy(self, image): def get_filtered_copy(self, image):
'''Apply a gaussian blur to an image, to suppress noise.''' """Apply a gaussian blur to an image, to suppress noise."""
kernel = self.get_1d_gaussian_kernel() kernel = self.get_1d_gaussian_kernel()
image = convolve1d(image.data, kernel, axis=0, mode='nearest') image = convolve1d(image.data, kernel, axis=0, mode='nearest')
return GrayscaleImage(None, convolve1d(image, kernel, axis=1, mode='nearest')) return GrayscaleImage(None, convolve1d(image, kernel, axis=1, mode='nearest'))
def filter(self, image): def filter(self, image):
kernel = self.get_1d_gaussian_kernel() kernel = self.get_1d_gaussian_kernel()
image.data = convolve1d(image.data, kernel, axis=0, mode='nearest') image.data = convolve1d(image.data, kernel, axis=0, mode='nearest')
image.data = convolve1d(image.data, kernel, axis=1, mode='nearest') image.data = convolve1d(image.data, kernel, axis=1, mode='nearest')
def get_scale(self): def get_scale(self):
return self.scale return self.scale
def set_scale(self, scale): def set_scale(self, scale):
self.scale = float(scale) self.scale = float(scale)
......
from pylab import imshow, imread, show from pylab import imshow, imread, show
from scipy.misc import imresize
from matplotlib.pyplot import hist from matplotlib.pyplot import hist
from scipy.misc import imresize, imsave from scipy.misc import imresize, imsave
...@@ -8,21 +7,21 @@ class GrayscaleImage: ...@@ -8,21 +7,21 @@ class GrayscaleImage:
def __init__(self, image_path = None, data = None): def __init__(self, image_path = None, data = None):
if image_path != None: if image_path != None:
self.data = imread(image_path) self.data = imread(image_path)
extension = image_path.split('.',3)[-1] extension = image_path.split('.', 3)[-1]
if extension == "jpg": if extension == "jpg":
self.data = self.data[::-1] self.data = self.data[::-1]
self.convert_to_grayscale() self.convert_to_grayscale()
elif data != None: elif data != None:
self.data = data self.data = data
def __iter__(self): def __iter__(self):
self.__i_x = -1 self.__i_x = -1
self.__i_y = 0 self.__i_y = 0
return self return self
def next(self): def next(self):
self.__i_x += 1 self.__i_x += 1
if self.__i_x == self.width: if self.__i_x == self.width:
...@@ -30,47 +29,47 @@ class GrayscaleImage: ...@@ -30,47 +29,47 @@ class GrayscaleImage:
self.__i_y += 1 self.__i_y += 1
if self.__i_y == self.height: if self.__i_y == self.height:
raise StopIteration raise StopIteration
return self.__i_y, self.__i_x, self[self.__i_y, self.__i_x] return self.__i_y, self.__i_x, self[self.__i_y, self.__i_x]
def __getitem__(self, position): def __getitem__(self, position):
return self.data[position] return self.data[position]
def convert_to_grayscale(self): def convert_to_grayscale(self):
if len(self.data.shape) > 2: if len(self.data.shape) > 2:
self.data = self.data[:,:,:3].sum(axis=2) / 3 self.data = self.data[:,:,:3].sum(axis=2) / 3
def crop(self, rectangle): def crop(self, rectangle):
self.data = self.data[rectangle.y : rectangle.y + rectangle.height, self.data = self.data[rectangle.y : rectangle.y + rectangle.height,
rectangle.x : rectangle.x + rectangle.width] rectangle.x : rectangle.x + rectangle.width]
def show(self): def show(self):
imshow(self.data, cmap="gray") imshow(self.data, cmap="gray")
show() show()
def make_histogram(self): def make_histogram(self):
return hist(self.data) return hist(self.data)
def resize(self, size): # size is of type float def resize(self, size): # size is of type float
self.data = imresize(self.data, size) self.data = imresize(self.data, size)
def get_shape(self): def get_shape(self):
return self.data.shape return self.data.shape
shape = property(get_shape) shape = property(get_shape)
def get_width(self): def get_width(self):
return self.get_shape()[1] return self.get_shape()[1]
width = property(get_width) width = property(get_width)
def get_height(self): def get_height(self):
return self.get_shape()[0] return self.get_shape()[0]
height = property(get_height) height = property(get_height)
def in_bounds(self, y, x): def in_bounds(self, y, x):
return x >= 0 and x < self.width and y >= 0 and y < self.height return x >= 0 and x < self.width and y >= 0 and y < self.height
def save(self, path): def save(self, path):
imsave(path, self.data) imsave(path, self.data)
...@@ -4,14 +4,15 @@ class Histogram: ...@@ -4,14 +4,15 @@ class Histogram:
self.bins = [0] * bins self.bins = [0] * bins
self.min = min self.min = min
self.max = max self.max = max
def add(self, number): def add(self, number):
bin_index = self.get_bin_index(number) bin_index = self.get_bin_index(number)
self.bins[bin_index] += 1 self.bins[bin_index] += 1
def remove(self, number): def remove(self, number):
bin_index = self.get_bin_index(number) bin_index = self.get_bin_index(number)
self.bins[bin_index] -= 1 self.bins[bin_index] -= 1
def get_bin_index(self, number): def get_bin_index(self, number):
return (number - self.min) / ((self.max - self.min) / len(self.bins)) return (number - self.min) / ((self.max - self.min) / len(self.bins))
\ No newline at end of file
from copy import deepcopy
from Rectangle import Rectangle from Rectangle import Rectangle
from GrayscaleImage import GrayscaleImage
class LetterCropper: class LetterCropper:
def __init__(self, threshold = 0.9): def __init__(self, threshold = 0.9):
self.threshold = threshold self.threshold = threshold
def crop_to_letter(self, image): def crop_to_letter(self, image):
self.image = image self.image = image
self.determine_letter_bounds() self.determine_letter_bounds()
...@@ -24,10 +22,10 @@ class LetterCropper: ...@@ -24,10 +22,10 @@ class LetterCropper:
if y < min_y: min_y = y if y < min_y: min_y = y
if x > max_x: max_x = x if x > max_x: max_x = x
if y > max_y: max_y = y if y > max_y: max_y = y
self.letter_bounds = Rectangle( self.letter_bounds = Rectangle(
min_x, min_x,
min_y, min_y,
max_x - min_x , max_x - min_x ,
max_y - min_y max_y - min_y
) )
from pylab import array, zeros, inv, dot, svd, shape, floor from pylab import array, zeros, inv, dot, svd, floor
from xml.dom.minidom import parse from xml.dom.minidom import parse
from Error import Error
from Point import Point from Point import Point
from Character import Character from Character import Character
from GrayscaleImage import GrayscaleImage from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage from NormalizedCharacterImage import NormalizedCharacterImage
'''
Creates a license plate object based on an XML file. The image should be
placed in a folder 'images' the xml file in a folder 'xml'
TODO: perhaps remove non required XML lookups
'''
class LicensePlate: class LicensePlate:
def __init__(self, folder_nr, file_nr): def __init__(self, folder_nr, file_nr):
...@@ -37,14 +30,14 @@ class LicensePlate: ...@@ -37,14 +30,14 @@ class LicensePlate:
N = max(y0, y1, y2, y3) - min(y0, y1, y2, y3) N = max(y0, y1, y2, y3) - min(y0, y1, y2, y3)
matrix = array([ matrix = array([
[x0, y0, 1, 0, 0, 0, 0, 0, 0], [x0, y0, 1, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, x0, y0, 1, 0, 0, 0], [ 0, 0, 0, x0, y0, 1, 0, 0, 0],
[x1, y1, 1, 0, 0, 0, -M*x0, -M*y1, -M], [x1, y1, 1, 0, 0, 0, -M * x0, -M * y1, -M],
[ 0, 0, 0, x1, y1, 1, 0, 0, 0], [ 0, 0, 0, x1, y1, 1, 0, 0, 0],
[x2, y2, 1, 0, 0, 0, -M*x2, -M*y2, -M], [x2, y2, 1, 0, 0, 0, -M * x2, -M * y2, -M],
[ 0, 0, 0, x2, y2, 1, -N*x2, -N*y2, -N], [ 0, 0, 0, x2, y2, 1, -N * x2, -N * y2, -N],
[x3, y3, 1, 0, 0, 0, 0, 0, 0], [x3, y3, 1, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, x3, y3, 1, -N*x3, -N*y3, -N] [ 0, 0, 0, x3, y3, 1, -N * x3, -N * y3, -N]
]) ])
P = inv(self.get_transformation_matrix(matrix)) P = inv(self.get_transformation_matrix(matrix))
...@@ -53,7 +46,9 @@ class LicensePlate: ...@@ -53,7 +46,9 @@ class LicensePlate:
for i in range(0, M): for i in range(0, M):
for j in range(0, N): for j in range(0, N):
or_coor = dot(P, ([[i],[j],[1]])) or_coor = dot(P, ([[i],[j],[1]]))
or_coor_h = or_coor[1][0] / or_coor[2][0], or_coor[0][0] / or_coor[2][0] or_coor_h = (or_coor[1][0] / or_coor[2][0],
or_coor[0][0] / or_coor[2][0])
data[j][i] = self.pV(or_coor_h[0], or_coor_h[1]) data[j][i] = self.pV(or_coor_h[0], or_coor_h[1])
return data return data
...@@ -75,9 +70,7 @@ class LicensePlate: ...@@ -75,9 +70,7 @@ class LicensePlate:
def pV(self, x, y): def pV(self, x, y):
image = self.image image = self.image
'''Get the value of a point x,y in the given image, where x and y are not #Get the value of a point (interpolated x, y) in the given image
necessary integers, so the value is interpolated from its neighbouring
pixels.'''
if image.in_bounds(x, y): if image.in_bounds(x, y):
x_low = floor(x) x_low = floor(x)
x_high = floor(x + 1) x_high = floor(x + 1)
...@@ -161,4 +154,4 @@ class LicensePlate: ...@@ -161,4 +154,4 @@ class LicensePlate:
if corner.nodeName == "point": if corner.nodeName == "point":
corners.append(Point(corner)) corners.append(Point(corner))
return corners return corners
\ No newline at end of file
from Histogram import Histogram from Histogram import Histogram
from numpy import zeros, byte
from math import ceil from math import ceil
class LocalBinaryPatternizer: class LocalBinaryPatternizer:
......
from GrayscaleImage import GrayscaleImage from GrayscaleImage import GrayscaleImage
from LocalBinaryPatternizer import LocalBinaryPatternizer from LocalBinaryPatternizer import LocalBinaryPatternizer
from LetterCropper import LetterCropper
from matplotlib.pyplot import imshow, subplot, show, axis, bar
from numpy import arange
image = GrayscaleImage("../images/test.png") image = GrayscaleImage("../images/test.png")
lbp = LocalBinaryPatternizer(image) lbp = LocalBinaryPatternizer(image)
histograms = lbp.create_features_vector() histograms = lbp.create_features_vector()
print histograms print histograms
\ No newline at end of file
...@@ -4,7 +4,7 @@ from LetterCropper import LetterCropper ...@@ -4,7 +4,7 @@ from LetterCropper import LetterCropper
from GaussianFilter import GaussianFilter from GaussianFilter import GaussianFilter
class NormalizedCharacterImage(GrayscaleImage): class NormalizedCharacterImage(GrayscaleImage):
def __init__(self, image=None, data=None, size=(60, 40), blur=1.1, crop_threshold=0.9): def __init__(self, image=None, data=None, size=(60, 40), blur=1.1, crop_threshold=0.9):
if image != None: if image != None:
GrayscaleImage.__init__(self, data=deepcopy(image.data)) GrayscaleImage.__init__(self, data=deepcopy(image.data))
...@@ -22,13 +22,13 @@ class NormalizedCharacterImage(GrayscaleImage): ...@@ -22,13 +22,13 @@ class NormalizedCharacterImage(GrayscaleImage):
self.data -= self.data.min() self.data -= self.data.min()
self.data /= self.data.max() self.data /= self.data.max()
def gausse_filter(self): def gausse_filter(self):
filter = GaussianFilter(1.1) filter = GaussianFilter(1.1)
filter.filter(self) filter.filter(self)
def crop_to_letter(self): def crop_to_letter(self):
cropper = LetterCropper(0.9) cropper = LetterCropper(0.9)
cropper.crop_to_letter(self) cropper.crop_to_letter(self)
def resize(self): def resize(self):
GrayscaleImage.resize(self, self.size) GrayscaleImage.resize(self, self.size)
\ No newline at end of file
class Rectangle: class Rectangle:
def __init__(self, x, y, width, height): def __init__(self, x, y, width, height):
self.x = x; self.x = x
self.y = y; self.y = y
self.width = width; self.width = width
self.height = height; self.height = height
from GrayscaleImage import GrayscaleImage from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage from NormalizedCharacterImage import NormalizedCharacterImage
from LetterCropper import LetterCropper
image = GrayscaleImage("../images/test10.png") image = GrayscaleImage("../images/test10.png")
normalized_character_image = NormalizedCharacterImage(image) normalized_character_image = NormalizedCharacterImage(image)
normalized_character_image.show() normalized_character_image.show()
\ No newline at end of file
from LicensePlate import LicensePlate
'''
create new LicensePlate object:
i.e you can do
plate = LicensePlate("../XML/test.info") # some xml file from rein
now available:
plate.image
plate.width
plate.height
Are the entire image widht / height and image is the corresponding image file
provided by rein (i.e other folder somewhere)
plate.corners
plate.license_full # the entire license plate as a string so 2334AB
plate.characters # for each character from license_full a Character object
exists, kinda same as the license plate. You have a value
= the character / number
a corners -> i.e list of points (Point objects)
TODO had to go so this text is full of crap maybe, anyway enjoy
'''
plate = LicensePlate("../XML/0000/00991_000000.info") # some xml file from rein
print plate.characters[0].value
#plate.characters[0].show()
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment