瀏覽代碼

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

Jayke Meijer 14 年之前
父節點
當前提交
8495200047

+ 0 - 6
src/Character.py

@@ -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)
 
 

+ 2 - 2
src/Classifier.py

@@ -1,5 +1,5 @@
 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:
             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

+ 53 - 53
src/ClassifierTest.py

@@ -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 = []
-#
-#for i in range(9):
-#    for j in range(100):
-#        try:
-#            filename = '%04d/00991_%04d%02d.info' % (i, i, j)
-#            print 'loading file "%s"' % filename
-#            plate = LicensePlate(i, j)
-#
-#            if hasattr(plate, 'characters'):
-#                chars.extend(plate.characters)
-#        except:
-#            print 'epic fail'
-#
-#print 'loaded %d chars' % len(chars)
-#
-#dump(chars, file('chars', 'w+'))
+chars = []
+
+for i in range(9):
+    for j in range(100):
+        try:
+            filename = '%04d/00991_%04d%02d.info' % (i, i, j)
+            print 'loading file "%s"' % filename
+            plate = LicensePlate(i, j)
+
+            if hasattr(plate, 'characters'):
+                chars.extend(plate.characters)
+        except:
+            print 'epic fail'
+
+print 'loaded %d chars' % len(chars)
+
+dump(chars, file('chars', 'w+'))
 #----------------------------------------------------------------
 #----------------------------------------------------------------
-#chars = load(file('chars', 'r'))
-#learned = []
-#learning_set = []
-#test_set = []
-#
-#for char in chars:
-#    if learned.count(char.value) > 80:
-#        test_set.append(char)
-#    else:
-#        learning_set.append(char)
-#        learned.append(char.value)
-#
-#dump(learning_set, file('learning_set', 'w+'))
-#dump(test_set, file('test_set', 'w+'))
+chars = load(file('chars', 'r'))
+learned = []
+learning_set = []
+test_set = []
+
+for char in chars:
+    if learned.count(char.value) > 80:
+        test_set.append(char)
+    else:
+        learning_set.append(char)
+        learned.append(char.value)
+
+dump(learning_set, file('learning_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')
-#test_set = load(file('test_set', 'r'))
-#l = len(test_set)
-#matches = 0
-#
-#for i, char in enumerate(test_set):
-#    prediction = classifier.classify(char)
-#
-#    if char.value == prediction:
-#        print ':) ------> Successfully recognized "%s"' % char.value
-#        matches += 1
-#    else:
-#        print ':( Expected character "%s", got "%s"' \
-#                % (char.value, prediction),
-#
-#    print '  --  %d of %d (%d%% done)' % (i + 1, l, int(100 * (i + 1) / l))
-#
-#print '\n%d matches (%d%%), %d fails' % (matches, \
-#        int(100 * matches / len(test_set)), \
-#        len(test_set) - matches)
+classifier = Classifier(filename='classifier')
+test_set = load(file('test_set', 'r'))
+l = len(test_set)
+matches = 0
+
+for i, char in enumerate(test_set):
+    prediction = classifier.classify(char)
+
+    if char.value == prediction:
+        print ':) ------> Successfully recognized "%s"' % char.value,
+        matches += 1
+    else:
+        print ':( Expected character "%s", got "%s"' \
+                % (char.value, prediction),
+
+    print '  --  %d of %d (%d%% done)' % (i + 1, l, int(100 * (i + 1) / l))
+
+print '\n%d matches (%d%%), %d fails' % (matches, \
+        int(100 * matches / len(test_set)), \
+        len(test_set) - matches)

+ 0 - 17
src/Error.py

@@ -1,17 +0,0 @@
-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"

+ 13 - 12
src/GaussianFilter.py

@@ -1,43 +1,44 @@
 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 exp(-(x ** 2 / (2 * self.scale ** 2))) / (sqrt(2 * pi) * self.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)
 
 
     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)
 
 

+ 23 - 24
src/GrayscaleImage.py

@@ -1,5 +1,4 @@
 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:
     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:
             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)

+ 5 - 4
src/Histogram.py

@@ -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))
+

+ 4 - 6
src/LetterCropper.py

@@ -1,12 +1,10 @@
-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:
                 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_y, 
+            min_x,
+            min_y,
             max_x - min_x ,
             max_x - min_x ,
             max_y - min_y
             max_y - min_y
         )
         )

+ 14 - 21
src/LicensePlate.py

@@ -1,17 +1,10 @@
-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:
         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],
-          [ 0,  0, 0, x0, y0, 1,    0,    0, 0],
-          [x1, y1, 1,  0,  0, 0, -M*x0, -M*y1, -M],
-          [ 0,  0, 0, x1, y1, 1,    0,    0, 0],
-          [x2, y2, 1,  0,  0, 0, -M*x2, -M*y2, -M],
-          [ 0,  0, 0, x2, y2, 1, -N*x2, -N*y2, -N],
-          [x3, y3, 1,  0,  0, 0,    0,    0, 0],
-          [ 0,  0, 0, x3, y3, 1, -N*x3, -N*y3, -N]
+          [x0, y0, 1,  0,  0, 0,       0,       0,  0],
+          [ 0,  0, 0, x0, y0, 1,       0,       0,  0],
+          [x1, y1, 1,  0,  0, 0, -M * x0, -M * y1, -M],
+          [ 0,  0, 0, x1, y1, 1,       0,       0,  0],
+          [x2, y2, 1,  0,  0, 0, -M * x2, -M * y2, -M],
+          [ 0,  0, 0, x2, y2, 1, -N * x2, -N * y2, -N],
+          [x3, y3, 1,  0,  0, 0,       0,       0,  0],
+          [ 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:
         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:
     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
-        necessary integers, so the value is interpolated from its neighbouring
-        pixels.'''
+        #Get the value of a point (interpolated x, y) in the given image
         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:
         if corner.nodeName == "point":
         if corner.nodeName == "point":
             corners.append(Point(corner))
             corners.append(Point(corner))
 
 
-      return corners
+      return corners

+ 0 - 1
src/LocalBinaryPatternizer.py

@@ -1,5 +1,4 @@
 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:

+ 1 - 4
src/LocalBinaryPatternizerTest.py

@@ -1,12 +1,9 @@
 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

+ 4 - 4
src/NormalizedCharacterImage.py

@@ -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):
         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)

+ 4 - 4
src/Rectangle.py

@@ -1,7 +1,7 @@
 class Rectangle:
 class Rectangle:
 
 
     def __init__(self, x, y, width, height):
     def __init__(self, x, y, width, height):
-        self.x = x;
-        self.y = y;
-        self.width = width;
-        self.height = height;
+        self.x = x
+        self.y = y
+        self.width = width
+        self.height = height

+ 2 - 3
src/combined_test.py

@@ -1,7 +1,6 @@
 from GrayscaleImage import GrayscaleImage
 from GrayscaleImage import GrayscaleImage
-from NormalizedCharacterImage import NormalizedCharacterImage 
-from LetterCropper import LetterCropper
+from NormalizedCharacterImage import NormalizedCharacterImage
 
 
 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()

+ 0 - 35
src/license_xml_tester.py

@@ -1,35 +0,0 @@
-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()