瀏覽代碼

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

Taddeüs Kroes 14 年之前
父節點
當前提交
d60f777ce0

二進制
images/test10.png


二進制
images/test9.png


+ 0 - 29
src/FilterNoise.py

@@ -1,29 +0,0 @@
-from scipy.ndimage import convolve1d
-from pylab import ceil, zeros, pi, e, exp, sqrt, array
-
-def f(x, s):
-    """Return the value of a 1D Gaussian function for a given x and scale."""
-    return exp(-(x ** 2 / (2 * s ** 2))) / (sqrt(2 * pi) * s)
-
-                                                             
-def gauss1(s, order=0):
-    """Sample a one-dimensional Gaussian function of scale s."""
-    s = float(s)
-    r = int(ceil(3 * s))
-    size = 2 * r + 1
-    W = zeros(size)
-
-    # Sample the Gaussian function
-    W = array([f(x - r, s) for x in xrange(size)])
-
-    if not order:
-        # Make sure that the sum of all kernel values is equal to one
-        W /= W.sum()
-
-    return W
-    
-def filterNoise(image, s):
-    '''Apply a gaussian blur to an image, to suppress noise.'''
-    filt = gauss1(s)
-    image = convolve1d(image.data, filt, axis=0, mode='nearest')
-    return convolve1d(image, filt, axis=1, mode='nearest')

+ 0 - 11
src/FilterNoiseTest.py

@@ -1,11 +0,0 @@
-from FilterNoise import filterNoise
-from GrayscaleImage import GrayscaleImage
-
-# Get the image
-image = GrayscaleImage('../images/plate.png')
-
-output_image = filterNoise(image, 1.4)
-
-# Show the licenseplate                 
-output_image = GrayscaleImage(None, output_image)
-output_image.show()

+ 44 - 0
src/GaussianFilter.py

@@ -0,0 +1,44 @@
+from GrayscaleImage import GrayscaleImage
+from scipy.ndimage import convolve1d
+from pylab import ceil, zeros, pi, e, 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)
+
+    def get_1d_gaussian_kernel(self):
+        '''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    
+        result = array([self.gaussian(x - radius) for x in xrange(size)])
+        # The sum of all kernel values is equal to one
+        result /= result.sum() 
+
+        return result
+
+    def get_filtered_copy(self, image):
+        '''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)
+
+    scale = property(get_scale, set_scale)

+ 9 - 0
src/GaussianFilterTest.py

@@ -0,0 +1,9 @@
+from FilterNoise import GaussianFilter
+from GrayscaleImage import GrayscaleImage
+
+image = GrayscaleImage('../images/plate.png')
+
+filter = GaussianFilter(1.4)
+output_image = filter.get_filtered_copy(image)
+
+output_image.show()

+ 0 - 65
src/GetPlate.py

@@ -1,65 +0,0 @@
-from pylab import array, zeros, inv, dot, svd, shape
-from Interpolation import pV
-
-def getPlateAt(image, points, M, N):
-    '''Returns an image of size MxN of the licenseplate (or any rectangular 
-    object) defined by 4 corner points.'''
-    # Construct the matrix M
-    x1_a, y1_a = 0, 0
-    x2_a, y2_a = M, 0
-    x3_a, y3_a = M, N
-    x4_a, y4_a = 0, N
-    
-    p_i = []
-    
-    for point in points:
-        p_i.append([point.x, point.y])
-    
-    mat_M = array([[p_i[0][0], p_i[0][1], 1, 0,  0,  0, \
-                        -x1_a * p_i[0][0], -x1_a * p_i[0][1], -x1_a], \
-                   [0,  0,  0, p_i[0][0], p_i[0][1], 1, \
-                        -y1_a * p_i[0][0], -y1_a * p_i[0][1], -y1_a], \
-                   [p_i[1][0], p_i[1][1], 1, 0,  0,  0, \
-                        -x2_a * p_i[1][0], -x2_a * p_i[1][1], -x2_a], \
-                   [0,  0,  0, p_i[1][0], p_i[1][1], 1, \
-                        -y2_a * p_i[1][0], -y2_a * p_i[1][1], -y2_a], \
-                   [p_i[2][0], p_i[2][1], 1, 0,  0,  0, \
-                        -x3_a * p_i[2][0], -x3_a * p_i[2][1], -x3_a], \
-                   [0,  0,  0, p_i[2][0], p_i[2][1], 1, \
-                        -y3_a * p_i[2][0], -y3_a * p_i[2][1], -y3_a], \
-                   [p_i[3][0], p_i[3][1], 1, 0,  0,  0, \
-                        -x4_a * p_i[3][0], -x4_a * p_i[3][1], -x4_a], \
-                   [0,  0,  0, p_i[3][0], p_i[3][1], 1, \
-                        -y4_a * p_i[3][0], -y4_a * p_i[3][1], -y4_a]])
-    
-    # Get the vector p and the values that are in there by taking the SVD. 
-    # Since D is diagonal with the eigenvalues sorted from large to small on
-    # the diagonal, the optimal q in min ||Dq|| is q = [[0]..[1]]. Therefore, 
-    # p = Vq means p is the last column in V.
-    U, D, V = svd(mat_M)
-    p = V[8][:]                
-    a, b, c, d, e, f, g, h, i = p[0], \
-                                p[1], \
-                                p[2], \
-                                p[3], \
-                                p[4], \
-                                p[5], \
-                                p[6], \
-                                p[7], \
-                                p[8]
-    
-    # P is the resulting matrix that describes the transformation
-    P = array([[a, b, c], \
-               [d, e, f], \
-               [g, h, i]])
-    
-    # Create the new image
-    b = array([zeros(M, float)] * N)
-    for i in range(0, M):
-        for j in range(0, N):
-            or_coor = dot(inv(P),([[i],[j],[1]]))
-            or_coor_h = or_coor[1][0] / or_coor[2][0], \
-                      or_coor[0][0] / or_coor[2][0]
-            b[j][i] = pV(image, or_coor_h[0], or_coor_h[1])
-    
-    return b

+ 0 - 19
src/GetPlateTest.py

@@ -1,19 +0,0 @@
-from GetPlate import getPlateAt
-from GrayscaleImage import GrayscaleImage
-from Point import Point
-
-# Define the corners of the licenseplate
-points = [Point(None, (310, 383)), \
-          Point(None, (382, 381)), \
-          Point(None, (382, 396)), \
-          Point(None, (310, 398))]
-
-# Get the image
-image = GrayscaleImage('../images/test_plate.png')
-
-# Let the code get the licenseplate
-output_image = getPlateAt(image, points, 100, 20)
-
-# Show the licenseplate                 
-output_image = GrayscaleImage(None, output_image)
-output_image.show()

+ 17 - 2
src/GrayscaleImage.py

@@ -1,5 +1,7 @@
 from pylab import imshow, imread, show
 from scipy.misc import imresize
+from matplotlib.pyplot import hist
+from scipy.misc import imresize, imsave
 
 class GrayscaleImage:
 
@@ -29,7 +31,8 @@ class GrayscaleImage:
         return self.data[position]
         
     def convert_to_grayscale(self):
-        self.data = self.data.sum(axis=2) / 3
+        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, 
@@ -39,21 +42,33 @@ class GrayscaleImage:
         imshow(self.data, cmap="gray")
         show()
     
-    # size is of type float
+    def make_histogram(self):
+        return hist(self.data)
+        
+    # size is of type tuple of integers (DEFAULT = (50, 50))
     def resize(self, size):
+        print size
+        
+    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)

+ 0 - 74
src/LBP.py

@@ -1,74 +0,0 @@
-#!/usr/bin/python
-import Image
-from numpy import array, zeros, byte
-from matplotlib.pyplot import imshow, subplot, show, axis
-
-# Divide the examined window to cells (e.g. 16x16 pixels for each cell).
-
-# For each pixel in a cell, compare the pixel to each of its 8 neighbors
-# (on its left-top, left-middle, left-bottom, right-top, etc.). Follow the
-# pixels along a circle, i.e. clockwise or counter-clockwise.
-
-# Where the center pixel's value is greater than the neighbor, write "1".
-# Otherwise, write "0". This gives an 8-digit binary number (which is usually
-# converted to decimal for convenience).
-
-# Compute the histogram, over the cell, of the frequency of each "number"
-# occurring (i.e., each combination of which pixels are smaller and which are
-# greater than the center).
-
-# Optionally normalize the histogram. Concatenate normalized histograms of all
-# cells. This gives the feature vector for the window.
-
-CELL_SIZE = 16
-
-def domain_iterator(shape):
-    """Iterate over the pixels of an image."""
-    for y in xrange(shape[0]):
-        for x in xrange(shape[1]):
-            yield y, x
-
-image = array(Image.open('../images/test.png').convert('L'))
-
-def in_image(y, x, F):
-    """Check if given pixel coordinates are within the bounds of image F."""
-    return 0 <= y < F.shape[0] and 0 <= x < F.shape[1]
-
-def features(image):
-    """Compare each pixel to each of its eight neigheach pixel to each of its
-    eight neighbours."""
-    features = zeros(image.shape, dtype=byte)
-
-    def cmp_pixels(y, x, p):
-        """Check if two pixels (y, x) and p are in the image, and if the value
-        at (y, x) is larger than the value at p."""
-        return in_image(y, x, image) and image[y, x] > p
-
-    for y, x in domain_iterator(features.shape):
-        p = image[y, x]
-
-        # Walk around the pixel in counter-clokwise order, shifting 1 bit less
-        # at each neighbour starting at 7 in the top-left corner. This gives a
-        # 8-bit feature number of a pixel
-        features[y, x] = byte(cmp_pixels(y - 1, x - 1, p)) << 7 \
-                         | byte(cmp_pixels(y - 1, x, p)) << 6 \
-                         | byte(cmp_pixels(y - 1, x + 1, p)) << 5 \
-                         | byte(cmp_pixels(y, x + 1, p)) << 4 \
-                         | byte(cmp_pixels(y + 1, x + 1, p)) << 3 \
-                         | byte(cmp_pixels(y + 1, x, p)) << 2 \
-                         | byte(cmp_pixels(y + 1, x - 1, p)) << 1 \
-                         | byte(cmp_pixels(y, x - 1, p))
-
-    return features
-
-def feature_vectors(image):
-    """Create cell histograms of an image"""
-    F = features(image)
-
-V = feature_vectors(image)
-subplot(121)
-imshow(image, cmap='gray')
-subplot(122)
-imshow(V, cmap='gray')
-axis('off')
-show()

+ 9 - 10
src/LetterCropper.py

@@ -1,25 +1,24 @@
 from copy import deepcopy
 from Rectangle import Rectangle
+from GrayscaleImage import GrayscaleImage
 
 class LetterCropper:
 
-    def __init__(self, image, threshold = 0.9):
-        self.source_image = image
+    def __init__(self, threshold = 0.9):
         self.threshold = threshold
         
-    def get_cropped_letter(self):
+    def crop_to_letter(self, image):
+        self.image = image
         self.determine_letter_bounds()
-        self.result_image = deepcopy(self.source_image)
-        self.result_image.crop(self.letter_bounds)
-        return self.result_image
+        self.image.crop(self.letter_bounds)
 
     def determine_letter_bounds(self):
-        min_x = self.source_image.width
+        min_x = self.image.width
         max_x = 0
-        min_y = self.source_image.height
+        min_y = self.image.height
         max_y = 0
 
-        for y, x, value in self.source_image:
+        for y, x, value in self.image:
             if value < self.threshold:
                 if x < min_x: min_x = x
                 if y < min_y: min_y = y
@@ -31,4 +30,4 @@ class LetterCropper:
             min_y, 
             max_x - min_x ,
             max_y - min_y
-        )
+        )

+ 1 - 6
src/LocalBinaryPatternizer.py

@@ -9,7 +9,6 @@ class LocalBinaryPatternizer:
         self.image = image
         self.setup_histograms()
 
-        
     def setup_histograms(self):
         cells_in_width = int(ceil(self.image.width / float(self.cell_size)))
         cells_in_height = int(ceil(self.image.height / float(self.cell_size)))
@@ -19,7 +18,6 @@ class LocalBinaryPatternizer:
             for j in xrange(cells_in_width):
                 self.features[i].append(Histogram(256,0,256))
 
-                
     def create_features_vector(self):
         ''' Walk around the pixels in clokwise order, shifting 1 bit less
             at each neighbour starting at 7 in the top-left corner. This gives a
@@ -40,14 +38,11 @@ class LocalBinaryPatternizer:
 
         return self.get_features_as_array()
     
-    
     def is_pixel_darker(self, y, x, value):
         return self.image.in_bounds(y, x) and self.image[y, x] > value
         
-        
     def get_cell_index(self, y, x):
         return (y / self.cell_size, x / self.cell_size)
         
-        
     def get_features_as_array(self):
-        return [item for sublist in self.features for item in sublist]
+        return [item for sublist in self.features for item in sublist]

+ 31 - 0
src/NormalizedCharacterImage.py

@@ -0,0 +1,31 @@
+from copy import deepcopy
+from GrayscaleImage import GrayscaleImage
+from LetterCropper import LetterCropper
+from GaussianFilter import GaussianFilter
+
+class NormalizedCharacterImage(GrayscaleImage):
+    
+    def __init__(self, image, size=(60, 40), blur=1.1, crop_threshold=0.9):
+        GrayscaleImage.__init__(self, data=deepcopy(image.data))
+        self.blur = blur
+        self.crop_threshold = crop_threshold
+        self.size = size
+        self.gausse_filter()
+        self.increase_contrast()
+        self.crop_to_letter()
+        self.resize()
+
+    def increase_contrast(self):
+        self.data -= self.data.min()
+        self.data /= self.data.max()
+
+    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)

+ 0 - 17
src/NormalizedImage.py

@@ -1,17 +0,0 @@
-from copy import deepcopy
-class NormalizedImage:
-    
-    DEFAULT_SIZE = 100.0
-    
-    def __init__(self, image, size=DEFAULT_SIZE):
-        self.source_image = image
-        self.size = size
-
-    def add_padding(self):
-        pass
-
-    # normalize img
-    def get_normalized_letter(self):
-        self.result_image = deepcopy(self.source_image)
-        self.result_image.resize(self.size / self.source_image.height)
-        return self.result_image

+ 4 - 48
src/combined_test.py

@@ -1,51 +1,7 @@
 from GrayscaleImage import GrayscaleImage
-from LocalBinaryPatternizer import LocalBinaryPatternizer
+from NormalizedCharacterImage import NormalizedCharacterImage 
 from LetterCropper import LetterCropper
-from matplotlib.pyplot import imshow, subplot, show, axis
-from NormalizedImage import NormalizedImage
 
-# Comment added by Richard Torenvliet
-# Steps in this test files are
-# 1. crop image 
-# 2. resize to default hight (in future also to width)
-# 3. preform LBP
-# 4. construct feature vector
-# 5. plot
-
-# Image is now an instance of class GrayscaleImage
-# GrayscaleImage has functions like resize, crop etc.
-image = GrayscaleImage("../images/test.png")
-
-# Crops image; param threshold is optional: LetterCropper(image, threshold=0.9)
-# image: GrayscaleImage, threshold: float
-cropper = LetterCropper(image, 0.9)
-cropped_letter = cropper.get_cropped_letter()
-
-# Show difference in shape
-print cropped_letter.shape
-
-# Resizes image; param size is optional: NormalizedImage(image, size=DEFAULT)
-# image: GrayscaleImage, size: float
-norm = NormalizedImage(cropped_letter)
-resized = norm.get_normalized_letter()
-
-# Difference is noticable
-print resized.shape
-
-lbp = LocalBinaryPatternizer(resized)
-feature_vector = lbp.create_features_vector()
-feature_vector /= 255 # Prepare for displaying -> 0 - 255 -> 0 - 1
-        
-subplot(141)
-imshow(image.data, cmap='gray')
-
-subplot(142)
-imshow(cropped_letter.data, cmap='gray')
-
-subplot(143)
-imshow(resized.data, cmap='gray')
-subplot(144)
-imshow(feature_vector, cmap='gray')
-
-axis('off')
-show()
+image = GrayscaleImage("../images/test10.png")
+normalized_character_image = NormalizedCharacterImage(image)
+normalized_character_image.show()