Просмотр исходного кода

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

Jayke Meijer 14 лет назад
Родитель
Сommit
8495200047

+ 0 - 6
src/Character.py

@@ -6,12 +6,6 @@ class Character:
         self.corners = corners
         self.image   = image
 
-    # Testing purposes
-    def show(self):
-        from pylab import imshow, show
-        imshow(self.data, cmap="gray")
-        show()
-
     def get_feature_vector(self):
         pattern = LocalBinaryPatternizer(self.image)
 

+ 2 - 2
src/Classifier.py

@@ -1,5 +1,5 @@
 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
 
 
@@ -13,7 +13,7 @@ class Classifier:
             f.close()
         else:
             self.param = svm_parameter()
-            self.param.kernel_type = LINEAR
+            self.param.kernel_type = 2
             self.param.C = c
             self.character_map = {}
             self.model = None

+ 53 - 53
src/ClassifierTest.py

@@ -3,63 +3,63 @@ from LicensePlate import LicensePlate
 from Classifier import Classifier
 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'))
 
 # Train the classifier with the learning set
-classifier = Classifier(c=3)
+classifier = Classifier(c=30)
 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 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:
 
     def __init__(self, scale):
         self.scale = scale
-        
+
     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):
-        '''Sample a one-dimensional Gaussian function of scale s'''
+        """Sample a one-dimensional Gaussian function of scale s."""
         radius = int(ceil(3 * self.scale))
         size = 2 * radius + 1
-        
+
         result = zeros(size)
-        # Sample the Gaussian function    
+        # Sample the Gaussian function
         result = array([self.gaussian(x - radius) for x in xrange(size)])
         # The sum of all kernel values is equal to one
-        result /= result.sum() 
+        result /= result.sum()
 
         return result
 
     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()
         image = convolve1d(image.data, kernel, axis=0, mode='nearest')
         return GrayscaleImage(None, convolve1d(image, kernel, axis=1, mode='nearest'))
-        
+
     def filter(self, image):
         kernel = self.get_1d_gaussian_kernel()
         image.data = convolve1d(image.data, kernel, axis=0, mode='nearest')
         image.data = convolve1d(image.data, kernel, axis=1, mode='nearest')
-        
+
     def get_scale(self):
       return self.scale
-      
+
     def set_scale(self, scale):
         self.scale = float(scale)
 

+ 23 - 24
src/GrayscaleImage.py

@@ -1,5 +1,4 @@
 from pylab import imshow, imread, show
-from scipy.misc import imresize
 from matplotlib.pyplot import hist
 from scipy.misc import imresize, imsave
 
@@ -8,21 +7,21 @@ class GrayscaleImage:
     def __init__(self, image_path = None, data = None):
         if image_path != None:
             self.data = imread(image_path)
-            
-            extension = image_path.split('.',3)[-1]
-            
+
+            extension = image_path.split('.', 3)[-1]
+
             if extension == "jpg":
               self.data = self.data[::-1]
-              
+
             self.convert_to_grayscale()
         elif data != None:
             self.data = data
-    
+
     def __iter__(self):
         self.__i_x = -1
         self.__i_y = 0
         return self
-            
+
     def next(self):
         self.__i_x += 1
         if self.__i_x  == self.width:
@@ -30,47 +29,47 @@ class GrayscaleImage:
             self.__i_y += 1
         if self.__i_y == self.height:
             raise StopIteration
-        
+
         return  self.__i_y, self.__i_x, self[self.__i_y, self.__i_x]
-            
+
     def __getitem__(self, position):
         return self.data[position]
-        
+
     def convert_to_grayscale(self):
         if len(self.data.shape) > 2:
           self.data = self.data[:,:,:3].sum(axis=2) / 3
-        
+
     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]
-                              
+
     def show(self):
         imshow(self.data, cmap="gray")
         show()
-    
+
     def make_histogram(self):
         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)
-        
+
     def get_shape(self):
         return self.data.shape
-        
+
     shape = property(get_shape)
-    
+
     def get_width(self):
         return self.get_shape()[1]
-        
+
     width = property(get_width)
-        
+
     def get_height(self):
         return self.get_shape()[0]
-        
+
     height = property(get_height)
-        
+
     def in_bounds(self, y, x):
         return x >= 0 and x < self.width and y >= 0 and y < self.height
-        
+
     def save(self, path):
         imsave(path, self.data)

+ 5 - 4
src/Histogram.py

@@ -4,14 +4,15 @@ class Histogram:
         self.bins = [0] * bins
         self.min = min
         self.max = max
-        
+
     def add(self, number):
         bin_index = self.get_bin_index(number)
         self.bins[bin_index] += 1
-        
+
     def remove(self, number):
         bin_index = self.get_bin_index(number)
         self.bins[bin_index] -= 1
-        
+
     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 GrayscaleImage import GrayscaleImage
 
 class LetterCropper:
 
     def __init__(self, threshold = 0.9):
         self.threshold = threshold
-        
+
     def crop_to_letter(self, image):
         self.image = image
         self.determine_letter_bounds()
@@ -24,10 +22,10 @@ class LetterCropper:
                 if y < min_y: min_y = y
                 if x > max_x: max_x = x
                 if y > max_y: max_y = y
-        
+
         self.letter_bounds = Rectangle(
-            min_x, 
-            min_y, 
+            min_x,
+            min_y,
             max_x - min_x ,
             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 Error import Error
 from Point import Point
 from Character import Character
 from GrayscaleImage import GrayscaleImage
 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:
 
     def __init__(self, folder_nr, file_nr):
@@ -37,14 +30,14 @@ class LicensePlate:
         N = max(y0, y1, y2, y3) - min(y0, y1, y2, y3)
 
         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))
@@ -53,7 +46,9 @@ class LicensePlate:
         for i in range(0, M):
             for j in range(0, N):
                 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])
 
         return data
@@ -75,9 +70,7 @@ class LicensePlate:
     def pV(self, x, y):
         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):
             x_low  = floor(x)
             x_high = floor(x + 1)
@@ -161,4 +154,4 @@ class LicensePlate:
         if corner.nodeName == "point":
             corners.append(Point(corner))
 
-      return corners
+      return corners

+ 0 - 1
src/LocalBinaryPatternizer.py

@@ -1,5 +1,4 @@
 from Histogram import Histogram
-from numpy import zeros, byte
 from math import ceil
 
 class LocalBinaryPatternizer:

+ 1 - 4
src/LocalBinaryPatternizerTest.py

@@ -1,12 +1,9 @@
 from GrayscaleImage import GrayscaleImage
 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")
 
 lbp = LocalBinaryPatternizer(image)
 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
 
 class NormalizedCharacterImage(GrayscaleImage):
-    
+
     def __init__(self, image=None, data=None, size=(60, 40), blur=1.1, crop_threshold=0.9):
         if image != None:
             GrayscaleImage.__init__(self, data=deepcopy(image.data))
@@ -22,13 +22,13 @@ class NormalizedCharacterImage(GrayscaleImage):
         self.data -= self.data.min()
         self.data /= self.data.max()
 
-    def gausse_filter(self):    
+    def gausse_filter(self):
         filter = GaussianFilter(1.1)
         filter.filter(self)
-        
+
     def crop_to_letter(self):
         cropper = LetterCropper(0.9)
         cropper.crop_to_letter(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:
 
     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 NormalizedCharacterImage import NormalizedCharacterImage 
-from LetterCropper import LetterCropper
+from NormalizedCharacterImage import NormalizedCharacterImage
 
 image = GrayscaleImage("../images/test10.png")
 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()