Browse Source

python code format

v2
xg.gao 5 years ago
parent
commit
184531c058
5 changed files with 99 additions and 109 deletions
  1. +3
    -2
      hyperlpr_pip_pkg/demo.py
  2. +6
    -6
      hyperlpr_pip_pkg/hyperlpr/__init__.py
  3. +83
    -95
      hyperlpr_pip_pkg/hyperlpr/hyperlpr.py
  4. +7
    -5
      hyperlpr_pip_pkg/hyperlpr/table_chs.py
  5. +0
    -1
      hyperlpr_pip_pkg/setup.py

+ 3
- 2
hyperlpr_pip_pkg/demo.py View File

@@ -1,4 +1,5 @@
from hyperlpr import *
import cv2
from hyperlpr import *

image = cv2.imread("./test_images/test_db2.jpg")
print(HyperLPR_plate_recognition(image,16,charSelectionDeskew=False,DB=True))
print(HyperLPR_plate_recognition(image, 16, charSelectionDeskew=False, DB=True))

+ 6
- 6
hyperlpr_pip_pkg/hyperlpr/__init__.py View File

@@ -1,8 +1,8 @@
name = "hyperlpr_python_pkg"
import sys
from .hyperlpr import LPR
import os
from .hyperlpr import LPR

PR = LPR(os.path.join(os.path.split(os.path.realpath(__file__))[0], "models"))


PR = LPR(os.path.join(os.path.split(os.path.realpath(__file__))[0],"models"))
def HyperLPR_plate_recognition(Input_BGR,minSize=30,charSelectionDeskew=True , region = "CH",DB=True):
return PR.plate_recognition(Input_BGR,minSize,charSelectionDeskew,DB)
def HyperLPR_plate_recognition(Input_BGR, minSize=30, charSelectionDeskew=True, region="CH", DB=True):
return PR.plate_recognition(Input_BGR, minSize, charSelectionDeskew, DB)

+ 83
- 95
hyperlpr_pip_pkg/hyperlpr/hyperlpr.py View File

@@ -1,42 +1,42 @@
#coding=utf-8
import os
import cv2
import numpy as np
import os
from .table_chs import chars


class LPR:


class LPR():
def __init__(self,folder):
def __init__(self, folder):
"""
Init the recognition instance.

:param model_detection: opencv cascade model which detecting license plate.
:param model_finemapping: finemapping model which deskew the license plate
:param model_rec: CNN based sequence recognition model trained with CTC loss.
:param model_detection: opencv cascade model which detecting license plate.
:param model_finemapping: finemapping model which deskew the license plate
:param model_rec: CNN based sequence recognition model trained with CTC loss.
"""

charLocPath= os.path.join(folder,"cascade/char/char_single.xml")
detectorPath = os.path.join(folder,"cascade/detector/detector_ch.xml")
detectorPathDB = os.path.join(folder,"cascade/detector/cascade_double.xml")
modelRecognitionPath = [os.path.join(folder,"dnn/SegmenationFree-Inception.prototxt"),os.path.join(folder,"dnn/SegmenationFree-Inception.caffemodel")]
modelFineMappingPath= [os.path.join(folder,"dnn/HorizonalFinemapping.prototxt"),os.path.join(folder,"dnn/HorizonalFinemapping.caffemodel")]
mini_ssd_path= [os.path.join(folder,"dnn/mininet_ssd_v1.prototxt"),os.path.join(folder,"dnn/mininet_ssd_v1.caffemodel")]
refine_net_path = [os.path.join(folder,"dnn/refinenet.prototxt"),os.path.join(folder,"dnn/refinenet.caffemodel")]
charLocPath = os.path.join(folder, "cascade/char/char_single.xml")
detectorPath = os.path.join(folder, "cascade/detector/detector_ch.xml")
detectorPathDB = os.path.join(folder, "cascade/detector/cascade_double.xml")
modelRecognitionPath = [os.path.join(folder, "dnn/SegmenationFree-Inception.prototxt"),
os.path.join(folder, "dnn/SegmenationFree-Inception.caffemodel")]
modelFineMappingPath = [os.path.join(folder, "dnn/HorizonalFinemapping.prototxt"),
os.path.join(folder, "dnn/HorizonalFinemapping.caffemodel")]
mini_ssd_path = [os.path.join(folder, "dnn/mininet_ssd_v1.prototxt"),
os.path.join(folder, "dnn/mininet_ssd_v1.caffemodel")]
refine_net_path = [os.path.join(folder, "dnn/refinenet.prototxt"),
os.path.join(folder, "dnn/refinenet.caffemodel")]

self.detector = cv2.CascadeClassifier(detectorPath)
self.detectorDB = cv2.CascadeClassifier(detectorPathDB)
self.charLoc = cv2.CascadeClassifier(charLocPath)
self.modelRecognition = cv2.dnn.readNetFromCaffe(*modelRecognitionPath)
self.ssd_detection = cv2.dnn.readNetFromCaffe(*mini_ssd_path)
self.refine_net = cv2.dnn.readNetFromCaffe(*refine_net_path)
self.refine_net = cv2.dnn.readNetFromCaffe(*refine_net_path)

def detect_ssd(self,im):
def detect_ssd(self, im):
"""
Detect the approximate location of plate via single shot detector based on modified mobilenet.
:param im: input image (BGR) .
:return: [[cropped,x1,y2,x2,y2] ,... ]
:param im: input image (BGR) .
:return: [[cropped,x1,y2,x2,y2] ,... ]
"""
_im = im.copy()
pixel_means = [0.406, 0.456, 0.485]
@@ -58,22 +58,22 @@ class LPR():
y1 = int(detection[4] * rows)
x2 = int(detection[5] * cols)
y2 = int(detection[6] * rows)
x1 = max(x1,0)
y1 = max(y1,0)
x2 = min(x2,im.shape[1]-1)
y2 = min(y2,im.shape[0]-1)
cropped = _im[y1:y2,x1:x2]
cropped_images.append([cropped ,[x1,y1,x2,y2]])
x1 = max(x1, 0)
y1 = max(y1, 0)
x2 = min(x2, im.shape[1]-1)
y2 = min(y2, im.shape[0]-1)
cropped = _im[y1:y2, x1:x2]
cropped_images.append([cropped, [x1, y1, x2, y2]])
return cropped_images

def detect_traditional(self,image_gray,resize_h = 720,en_scale =1.1,minSize = 30,DB=True):
def detect_traditional(self, image_gray, resize_h=720, en_scale=1.1, minSize=30, DB=True):
"""
Detect the approximate location of plate via opencv build-in cascade detection.
:param image_gray: input single channel image (gray) .
:param resize_h: adjust input image size to a fixed size.
:param en_scale: the ratio of image between every scale of images in cascade detection.
:param minSize: minSize of plate increase this parameter can increase the speed of detection.
:return: the results.
:param image_gray: input single channel image (gray) .
:param resize_h: adjust input image size to a fixed size.
:param en_scale: the ratio of image between every scale of images in cascade detection.
:param minSize: minSize of plate increase this parameter can increase the speed of detection.
:return: the results.
"""
if DB:
watches = self.detectorDB.detectMultiScale(image_gray, en_scale, 3, minSize=(minSize*4, minSize))
@@ -89,23 +89,22 @@ class LPR():
y1 = int(y)
x2 = int(x+w)
y2 = int(y+h)
x1 = max(x1,0)
y1 = max(y1,0)
x2 = min(x2,image_gray.shape[1]-1)
y2 = min(y2,image_gray.shape[0]-1)
cropped = image_gray[y1:y2,x1:x2]
cropped_images.append([cropped ,[x1,y1,x2,y2]])
x1 = max(x1, 0)
y1 = max(y1, 0)
x2 = min(x2, image_gray.shape[1]-1)
y2 = min(y2, image_gray.shape[0]-1)
cropped = image_gray[y1:y2, x1:x2]
cropped_images.append([cropped, [x1, y1, x2, y2]])
return cropped_images


def loose_crop(self,image, box, aspect_ratio, padding_ratio=1.7):
def loose_crop(self, image, box, aspect_ratio, padding_ratio=1.7):
"""
Crop the image with an extend rectangle.
:param image: input image (BGR).
:param box: origin bounding box.
:param aspect_ratio: the aspect ratio that need to keep.
:param padding_ratio: padding ratio of origin rectangle.
:return: the cropped image
:param image: input image (BGR).
:param box: origin bounding box.
:param aspect_ratio: the aspect ratio that need to keep.
:param padding_ratio: padding ratio of origin rectangle.
:return: the cropped image
"""
x1, y1, x2, y2 = box
cx, cy = ((x2 + x1) // 2, (y2 + y1) // 2)
@@ -121,11 +120,10 @@ class LPR():
cropped = image[y1:y2, x1:x2]
return cropped


def decode_ctc(self,y_pred):
def decode_ctc(self, y_pred):
"""
Decode the results from the last layer of recognition model.
:param y_pred: the feature map output last feature map.
Decode the results from the last layer of recognition model.
:param y_pred: the feature map output last feature map.
:return: decode results.
"""
results = ""
@@ -133,14 +131,14 @@ class LPR():
y_pred = y_pred.T
table_pred = y_pred
res = table_pred.argmax(axis=1)
for i,one in enumerate(res):
if one<len(chars) and (i==0 or (one!=res[i-1])):
results+= chars[one]
confidence+=table_pred[i][one]
confidence/= len(results)
return results,confidence
def fit_ransac(self,pts, zero_add=0):
for i, one in enumerate(res):
if one < len(chars) and (i == 0 or (one != res[i-1])):
results += chars[one]
confidence += table_pred[i][one]
confidence /= len(results)
return results, confidence
def fit_ransac(self, pts, zero_add=0):
"""
fit a line and use RANSAC algorithm to reject outlier.
:param pts: input pts
@@ -153,15 +151,14 @@ class LPR():
return lefty + 30 + zero_add, righty + 30 + zero_add
return 0, 0

def fine_mapping(self,image_rgb):
def fine_mapping(self, image_rgb):
"""
fit plate upper and lower with multi-threshold method to segment single character.
:param image_rgb:
:return: fined image.
"""

line_upper = [];
line_lower = [];
line_upper = []
line_lower = []
line_experiment = []
if image_rgb.ndim == 3:
gray_image = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2GRAY)
@@ -169,15 +166,16 @@ class LPR():
gray_image = image_rgb

for k in np.linspace(-50, 0, 16):
binary_niblack = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 17,k)
binary_niblack = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 17, k)
if cv2.__version__[0] == "4":
contours, hierarchy = cv2.findContours(binary_niblack.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
contours, hierarchy = cv2.findContours(binary_niblack.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
else:
imagex, contours, hierarchy = cv2.findContours(binary_niblack.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
imagex, contours, hierarchy = cv2.findContours(binary_niblack.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
bdbox = cv2.boundingRect(contour)
if ((bdbox[3] / float(bdbox[2]) > 0.7 and bdbox[3] * bdbox[2] > 100 and bdbox[3] * bdbox[2] < 1200) or (
bdbox[3] / float(bdbox[2]) > 3 and bdbox[3] * bdbox[2] < 100)):
threshold1 = bdbox[3] / float(bdbox[2])
threshold2 = bdbox[3] * bdbox[2]
if (threshold1 > 0.7 and 100 < threshold2 < 1200) or (threshold1 > 3 and threshold2 < 100):
line_upper.append([bdbox[0], bdbox[1]])
line_lower.append([bdbox[0] + bdbox[2], bdbox[1] + bdbox[3]])
line_experiment.append([bdbox[0], bdbox[1]])
@@ -192,17 +190,14 @@ class LPR():
image = cv2.warpPerspective(rgb, mat, (136, 36), flags=cv2.INTER_CUBIC)
return image


def fine_mapping_by_selecting(self,image_rgb,line_upper,line_lower ):
def fine_mapping_by_selecting(self, image_rgb, line_upper, line_lower):
"""
fit plate upper and lower with detecting character boundingbox
fit plate upper and lower with detecting character bounding box
:param image_rgb: input image
:param line_upper: padding of upper
:param line_lower: padding of lower
:return: fined image.
"""


rgb = cv2.copyMakeBorder(image_rgb, 30, 30, 0, 0, cv2.BORDER_REPLICATE)
leftyA, rightyA = self.fit_ransac(np.array(line_lower), 3)
leftyB, rightyB = self.fit_ransac(np.array(line_upper), -3)
@@ -213,10 +208,10 @@ class LPR():
image = cv2.warpPerspective(rgb, mat, (136, 36), flags=cv2.INTER_CUBIC)
return image

def to_refine(self,image, pts, scale=3.0):
def to_refine(self, image, pts, scale=3.0):
"""
refine the image by input points.
:param image_rgb: input image
:param image: input image
:param pts: points
"""
x1, y1, x2, y2, x3, y3, x4, y4 = pts.ravel()
@@ -241,7 +236,7 @@ class LPR():
def affine_crop(self, image, pts):
"""
crop a image by affine transform.
:param image_rgb: input image
:param image: input image
:param pts: points
"""
x1, y1, x2, y2, x3, y3, x4, y4 = pts.ravel()
@@ -252,13 +247,12 @@ class LPR():
warped = cv2.warpPerspective(image, mat, dsize)
return warped

def finetune(self,image_, stage=2):
def finetune(self, image_, stage=2):
"""
cascade fine tune a image by regress four corner of plate.
:param image_rgb: input image
:param image_: input image
:param stages: cascade stage
"""

tof = image_.copy()
image = cv2.resize(tof, (120, 48))
blob = cv2.dnn.blobFromImage(image, size=(120, 48), swapRB=False, mean=(127.5, 127.5, 127.5), scalefactor=0.0078125, crop=False)
@@ -273,22 +267,20 @@ class LPR():
cropped = self.affine_crop(g, pts)
return cropped


def segmentation_free_recognition(self,src):
def segmentation_free_recognition(self, src):
"""
return: ctc decode results
"""
temp = cv2.resize(src,( 160,40))
temp = cv2.resize(src, (160, 40))
temp = temp.transpose(1, 0, 2)
blob = cv2.dnn.blobFromImage(temp, 1/255.0, (40, 160), (0,0,0), False, False)
blob = cv2.dnn.blobFromImage(temp, 1/255.0, (40, 160), (0, 0, 0), False, False)
self.modelRecognition.setInput(blob)
y_pred = self.modelRecognition.forward()[0]
y_pred = y_pred[:,2:,:]
y_pred = y_pred[:, 2:, :]
y_pred = np.squeeze(y_pred)
return self.decode_ctc(y_pred)


def plate_recognition(self,image,minSize=30,charSelectionDeskew=True,DB = True, mode='ssd'):
def plate_recognition(self, image, minSize=30, charSelectionDeskew=True, DB=True, mode='ssd'):
"""
the simple pipline consists of detection . deskew , fine mapping alignment, recognition.
:param image: the input BGR image from imread used by opencv
@@ -312,26 +304,22 @@ class LPR():
else:
images = self.detect_ssd(image)
res_set = []
for j,plate in enumerate(images):
plate,[left,top,right,bottom] = plate
for j, plate in enumerate(images):
plate, [left, top, right, bottom] = plate
print(left, top, right, bottom)
if DB:
w, h = right - left, bottom - top
plate = image[top:bottom,left:right,:]
crop_up = plate[int(h * 0.05):int((h) * 0.4), int(w * 0.2):int(w * 0.75)]
crop_down = plate[int((h) * 0.4):int(h), int(w * 0.05):w]
plate = image[top:bottom, left:right, :]
crop_up = plate[int(h * 0.05):int(h * 0.4), int(w * 0.2):int(w * 0.75)]
crop_down = plate[int(h * 0.4):int(h), int(w * 0.05):w]
crop_up = cv2.resize(crop_up, (64, 40))
crop_down = cv2.resize(crop_down, (96, 40))
cropped_finetuned = np.concatenate([crop_up, crop_down], 1)
# cv2.imshow("crop",plate)
# cv2.waitKey(0)
else:

cropped = self.loose_crop(image, [left, top, right, bottom], 120 / 48)
cropped_finetuned = self.finetune(cropped)
res, confidence = self.segmentation_free_recognition(cropped_finetuned)
res_set.append([res,confidence,[left,top,right,bottom ]])
res_set.append([res, confidence, [left, top, right, bottom]])
return res_set


#

+ 7
- 5
hyperlpr_pip_pkg/hyperlpr/table_chs.py View File

@@ -1,5 +1,7 @@
chars = [u"京", u"沪", u"津", u"渝", u"冀", u"晋", u"蒙", u"辽", u"吉", u"黑", u"苏", u"浙", u"皖", u"闽", u"赣", u"鲁", u"豫", u"鄂", u"湘", u"粤", u"桂",
u"琼", u"川", u"贵", u"云", u"藏", u"陕", u"甘", u"青", u"宁", u"新", u"0", u"1", u"2", u"3", u"4", u"5", u"6", u"7", u"8", u"9", u"A",
u"B", u"C", u"D", u"E", u"F", u"G", u"H", u"J", u"K", u"L", u"M", u"N", u"P", u"Q", u"R", u"S", u"T", u"U", u"V", u"W", u"X",
u"Y", u"Z",u"港",u"学",u"使",u"警",u"澳",u"挂",u"军",u"北",u"南",u"广",u"沈",u"兰",u"成",u"济",u"海",u"民",u"航",u"空"
]
chars = [
u"京", u"沪", u"津", u"渝", u"冀", u"晋", u"蒙", u"辽", u"吉", u"黑", u"苏", u"浙", u"皖", u"闽", u"赣", u"鲁",
u"豫", u"鄂", u"湘", u"粤", u"桂", u"琼", u"川", u"贵", u"云", u"藏", u"陕", u"甘", u"青", u"宁", u"新", u"0",
u"1", u"2", u"3", u"4", u"5", u"6", u"7", u"8", u"9", u"A", u"B", u"C", u"D", u"E", u"F", u"G", u"H", u"J", u"K",
u"L", u"M", u"N", u"P", u"Q", u"R", u"S", u"T", u"U", u"V", u"W", u"X", u"Y", u"Z", u"港", u"学", u"使", u"警",
u"澳", u"挂", u"军", u"北", u"南", u"广", u"沈", u"兰", u"成", u"济", u"海", u"民", u"航", u"空"
]

+ 0
- 1
hyperlpr_pip_pkg/setup.py View File

@@ -29,5 +29,4 @@ setuptools.setup(
"models/dnn/*.*"
]
},

)

Loading…
Cancel
Save