Commit d60f777c authored by Taddeüs Kroes's avatar Taddeüs Kroes

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

parents e88b8344 b49213eb
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')
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)
from FilterNoise import filterNoise
from FilterNoise import GaussianFilter
from GrayscaleImage import GrayscaleImage
# Get the image
image = GrayscaleImage('../images/plate.png')
output_image = filterNoise(image, 1.4)
filter = GaussianFilter(1.4)
output_image = filter.get_filtered_copy(image)
# Show the licenseplate
output_image = GrayscaleImage(None, output_image)
output_image.show()
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
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()
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)
#!/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()
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
)
\ No newline at end of file
)
......@@ -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]
\ No newline at end of file
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)
\ No newline at end of file
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
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()
\ 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