unknown 14 yıl önce
ebeveyn
işleme
4b6c52d567
5 değiştirilmiş dosya ile 146 ekleme ve 59 silme
  1. 10 26
      src/Character.py
  2. 6 0
      src/GrayscaleImage.py
  3. 114 23
      src/LicensePlate.py
  4. 13 7
      src/Point.py
  5. 3 3
      src/license_xml_tester.py

+ 10 - 26
src/Character.py

@@ -1,28 +1,12 @@
-from Point import Point
-
 # TODO cleanup the getElements stuff
 class Character:
-    def __init__(self, character):
-        self.dom     = character
-        self.value   = self.get_node("char").firstChild.data
-
-        self.set_corners()
-        print self.corners
-
-    def set_corners(self):
-        corners = self.get_children("quadrangle")
-  
-        self.corners = []
-
-        for corner in corners:
-          if corner.nodeName == "point":
-              self.corners.append(Point(corner))
-
-    def get_node(self, node, dom=None):
-        if not dom:
-            dom = self.dom
-
-        return dom.getElementsByTagName(node)[0]
-
-    def get_children(self, node, dom=None):
-        return self.get_node(node, dom).childNodes
+    def __init__(self, value, corners, image):
+        self.value   = value
+        self.corners = corners
+        self.image   = image
+        
+    # Testing purposes
+    def show(self):
+        from pylab import imshow, show
+        imshow(self.data, cmap="gray")
+        show()

+ 6 - 0
src/GrayscaleImage.py

@@ -8,6 +8,12 @@ class GrayscaleImage:
     def __init__(self, image_path = None, data = None):
         if image_path:
             self.data = imread(image_path)
+            
+            extension = image_path.split('.',3)[-1]
+            
+            if extension == "jpg":
+              self.data = self.data[::-1]
+              
             self.convert_to_grayscale()
         elif data:
             self.data = data

+ 114 - 23
src/LicensePlate.py

@@ -1,25 +1,109 @@
+from pylab import array, zeros, inv, dot, svd, shape, floor
 from xml.dom.minidom import parse 
 from Error import Error
 from Point import Point
 from Character import Character
+from GrayscaleImage import GrayscaleImage
 
+'''
+    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, file_path):
+    def __init__(self, xml_title):
         try:
-            self.dom = parse(file_path)
+            self.dom = parse('../XML/' + str(xml_title))
         except IOError:
             Error("Incorrect file name given.")
-            return None
         else:
             properties = self.get_properties()
 
-            self.image  = str(properties['uii']) + '.' + str(properties['type'])
-            self.width  = properties['width']
-            self.height = properties['height']
+            self.image  = GrayscaleImage('../images/' + str(properties['uii']) + '.' + str(properties['type']))
+            self.width  = int(properties['width'])
+            self.height = int(properties['height'])
 
-            info = self.set_plate()
+            self.read_xml()
+            
+    # sets the entire license plate of an image
+    def retrieve_data(self, corners):    
+        x0, y0 = corners[0].to_tuple()
+        x1, y1 = corners[1].to_tuple()
+        x2, y2 = corners[2].to_tuple()
+        x3, y3 = corners[3].to_tuple()
+        
+        M = max(x0, x1, x2, x3) - min(x0, x1, x2, x3)
+        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]
+        ])
+        
+        P = inv(self.get_transformation_matrix(matrix))
+        data = array([zeros(M, float)] * N)
 
+        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]
+                data[j][i] = self.pV(or_coor_h[0], or_coor_h[1])
+                
+        return data
+                
+    def get_transformation_matrix(self, matrix):
+        # 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(matrix)
+        p = V[8][:]
+        
+        return array([
+            [ p[0], p[1], p[2] ], 
+            [ p[3], p[4], p[5] ], 
+            [ p[6], p[7], p[8] ]
+        ])
+            
+    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.'''
+        if image.in_bounds(x, y):
+            x_low  = floor(x)
+            x_high = floor(x + 1)
+            y_low  = floor(y)
+            y_high = floor(y + 1)
+            x_y    = (x_high - x_low) * (y_high - y_low)
+            
+            a = x_high - x
+            b = y_high - y
+            c = x - x_low
+            d = y - y_low
+            
+            return image[x_low,  y_low] / x_y * a * b \
+                + image[x_high,  y_low] / x_y * c * b \
+                + image[x_low , y_high] / x_y * a * d \
+                + image[x_high, y_high] / x_y * c * d
+            
+        return 0
+    
+    # Testing purposes
+    def show(self):
+        from pylab import imshow, show
+        imshow(self.data, cmap="gray")
+        show()
+        
     def get_properties(self):
         children = self.get_children("properties")
 
@@ -34,7 +118,7 @@ class LicensePlate:
         return properties
 
     # TODO : create function for location / characters as they do the same
-    def set_plate(self):
+    def read_xml(self):
         children = self.get_children("plate") # most recent version
         
         for child in children:
@@ -43,26 +127,22 @@ class LicensePlate:
             elif child.nodeName == "identification-letters":
               self.country = child.firstChild.data
             elif child.nodeName == "location":
-                corners = self.get_children("quadrangle", child)
-          
-                self.corners = []
-
-                for corner in corners:
-                  if corner.nodeName == "point":
-                      self.corners.append(Point(corner))
-
+                self.corners = self.get_corners(child)
             elif child.nodeName == "characters":
-                characters = child.childNodes
+                nodes = child.childNodes
   
-                self.license_characters = []
+                self.characters = []
 
-                for character in characters:
+                for character in nodes:
                   if character.nodeName == "character":
-                    self.license_characters.append(Character(character))
-
+                    value   = self.get_node("char", character).firstChild.data
+                    corners = self.get_corners(character)
+                    data    = self.retrieve_data(corners)
+                    image   = NormalizedCharacterImage(data=data)
+                    
+                    self.characters.append(Character(value, corners, image))
             else:
                 pass
-                #print child.nodeName
             
     def get_node(self, node, dom=None):
         if not dom:
@@ -71,4 +151,15 @@ class LicensePlate:
         return dom.getElementsByTagName(node)[0]
 
     def get_children(self, node, dom=None):
-        return self.get_node(node, dom).childNodes
+        return self.get_node(node, dom).childNodes
+        
+    def get_corners(self, child):
+      nodes = self.get_children("quadrangle", child)
+          
+      corners = []
+
+      for corner in nodes:
+        if corner.nodeName == "point":
+            corners.append(Point(corner))
+            
+      return corners

+ 13 - 7
src/Point.py

@@ -1,8 +1,14 @@
 class Point:
-    def __init__(self, corner = None, coordinates = None):
-        if corner != None:
-            self.x = corner.getAttribute("x")
-            self.y = corner.getAttribute("y")
-        elif coordinates != None:
-            self.x = coordinates[0]
-            self.y = coordinates[1]
+    def __init__(self, x_or_corner=None, y=None):
+        if y != None:
+            self.x = x_or_corner
+            self.y = y
+        else:
+            self.x = int(x_or_corner.getAttribute("x"))
+            self.y = int(x_or_corner.getAttribute("y"))
+
+    def to_tuple(self):
+        return self.x, self.y
+        
+    def __str__(self):
+        return str(self.x) + " " + str(self.y)

+ 3 - 3
src/license_xml_tester.py

@@ -29,7 +29,7 @@ from LicensePlate import LicensePlate
  
 '''
 
-plate = LicensePlate("../XML/test.info") # some xml file from rein
+plate = LicensePlate("../XML/0000/00991_000000.info") # some xml file from rein
 
-for corner in plate.corners:
-  print corner.x, corner.y
+print plate.characters[0].value
+#plate.characters[0].show()