ifi-up_point>2:
is_peak=False
wave_peaks.append((up_point,i))
elifnotis_peakandx>=threshold:
is_peak=True
up_point=i
ifis_peakandup_point!
=-1andi-up_point>4:
wave_peaks.append((up_point,i))
returnwave_peaks
#根据找出的波峰,分隔图片,从而得到逐个字符图片
defseperate_card(img,waves):
part_cards=[]
forwaveinwaves:
part_cards.append(img[:
wave[0]:
wave[1]])
returnpart_cards
#来自opencv的sample,用于svm训练
defdeskew(img):
m=cv2.moments(img)
ifabs(m['mu02'])<1e-2:
returnimg.copy()
skew=m['mu11']/m['mu02']
M=np.float32([[1,skew,-0.5*SZ*skew],[0,1,0]])
img=cv2.warpAffine(img,M,(SZ,SZ),flags=cv2.WARP_INVERSE_MAP|cv2.INTER_LINEAR)
returnimg
#来自opencv的sample,用于svm训练
defpreprocess_hog(digits):
samples=[]
forimgindigits:
gx=cv2.Sobel(img,cv2.CV_32F,1,0)
gy=cv2.Sobel(img,cv2.CV_32F,0,1)
mag,ang=cv2.cartToPolar(gx,gy)
bin_n=16
bin=np.int32(bin_n*ang/(2*np.pi))
bin_cells=bin[:
10,:
10],bin[10:
:
10],bin[:
10,10:
],bin[10:
10:
]
mag_cells=mag[:
10,:
10],mag[10:
:
10],mag[:
10,10:
],mag[10:
10:
]
hists=[np.bincount(b.ravel(),m.ravel(),bin_n)forb,minzip(bin_cells,mag_cells)]
hist=np.hstack(hists)
#transformtoHellingerkernel
eps=1e-7
hist/=hist.sum()+eps
hist=np.sqrt(hist)
hist/=norm(hist)+eps
samples.append(hist)
returnnp.float32(samples)
#不能保证包括所有省份
provinces=[
"zh_cuan","川",
"zh_e","鄂",
"zh_gan","赣",
"zh_gan1","甘",
"zh_gui","贵",
"zh_gui1","桂",
"zh_hei","黑",
"zh_hu","沪",
"zh_ji","冀",
"zh_jin","津",
"zh_jing","京",
"zh_jl","吉",
"zh_liao","辽",
"zh_lu","鲁",
"zh_meng","蒙",
"zh_min","闽",
"zh_ning","宁",
"zh_qing","靑",
"zh_qiong","琼",
"zh_shan","陕",
"zh_su","苏",
"zh_sx","晋",
"zh_wan","皖",
"zh_xiang","湘",
"zh_xin","新",
"zh_yu","豫",
"zh_yu1","渝",
"zh_yue","粤",
"zh_yun","云",
"zh_zang","藏",
"zh_zhe","浙"
]
classStatModel(object):
defload(self,fn):
self.model=self.model.load(fn)
defsave(self,fn):
self.model.save(fn)
classSVM(StatModel):
def__init__(self,C=1,gamma=0.5):
self.model=cv2.ml.SVM_create()
self.model.setGamma(gamma)
self.model.setC(C)
self.model.setKernel(cv2.ml.SVM_RBF)
self.model.setType(cv2.ml.SVM_C_SVC)
#训练svm
deftrain(self,samples,responses):
self.model.train(samples,cv2.ml.ROW_SAMPLE,responses)
#字符识别
defpredict(self,samples):
r=self.model.predict(samples)
returnr[1].ravel()
classCardPredictor:
def__init__(self):
#车牌识别的部分参数保存在js中,便于根据图片分辨率做调整
f=open('config.js')
j=json.load(f)
forcinj["config"]:
print(c)
ifc["open"]:
self.cfg=c.copy()
break
else:
raiseRuntimeError('没有设置有效配置参数')
def__del__(self):
self.save_traindata()
deftrain_svm(self):
#识别英文字母和数字
self.model=SVM(C=1,gamma=0.5)
#识别中文
self.modelchinese=SVM(C=1,gamma=0.5)
ifos.path.exists("svm.dat"):
self.model.load("svm.dat")
else:
chars_train=[]
chars_label=[]
forroot,dirs,filesinos.walk("train\\chars2"):
iflen(os.path.basename(root))>1:
continue
root_int=ord(os.path.basename(root))
forfilenameinfiles:
filepath=os.path.join(root,filename)
digit_img=cv2.imread(filepath)
digit_img=cv2.cvtColor(digit_img,cv2.COLOR_BGR2GRAY)
chars_train.append(digit_img)
#chars_label.append
(1)
chars_label.append(root_int)
chars_train=list(map(deskew,chars_train))
chars_train=preprocess_hog(chars_train)
#chars_train=chars_train.reshape(-1,20,20).astype(np.float32)
chars_label=np.array(chars_label)
print(chars_train.shape)
self.model.train(chars_train,chars_label)
ifos.path.exists("svmchinese.dat"):
self.modelchinese.load("svmchinese.dat")
else:
chars_train=[]
chars_label=[]
forroot,dirs,filesinos.walk("train\\charsChinese"):
ifnotos.path.basename(root).startswith("zh_"):
continue
pinyin=os.path.basename(root)
index=provinces.index(pinyin)+PROVINCE_START+1#1是拼音对应的汉字
forfilenameinfiles:
filepath=os.path.join(root,filename)
digit_img=cv2.imread(filepath)
digit_img=cv2.cvtColor(digit_img,cv2.COLOR_BGR2GRAY)
chars_train.append(digit_img)
#chars_label.append
(1)
chars_label.append(index)
chars_train=list(map(deskew,chars_train))
chars_train=preprocess_hog(chars_train)
#chars_train=chars_train.reshape(-1,20,20).astype(np.float32)
chars_label=np.array(chars_label)
print(chars_train.shape)
self.modelchinese.train(chars_train,chars_label)
defsave_traindata(self):
ifnotos.path.exists("svm.dat"):
self.model.save("svm.dat")
ifnotos.path.exists("svmchinese.dat"):
self.modelchinese.save("svmchinese.dat")
defaccurate_place(self,card_img_hsv,limit1,limit2,color):
row_num,col_num=card_img_hsv.shape[:
2]
xl=col_num
xr=0
yh=0
yl=row_num
#col_num_limit=self.cfg["col_num_limit"]
row_num_limit=self.cfg["row_num_limit"]
col_num_limit=col_num*0.8ifcolor!
="green"elsecol_num*0.5#绿色有渐变
foriinrange(row_num):
count=0
forjinrange(col_num):
H=card_img_hsv.item(i,j,0)
S=card_img_hsv.item(i,j,1)
V=card_img_hsv.item(i,j,2)
iflimit1count+=1
ifcount>col_num_limit:
ifyl>i:
yl=i
ifyhyh=i
forjinrange(col_num):
count=0
foriinrange(row_num):
H=card_img_hsv.item(i,j,0)
S=card_img_hsv.item(i,j,1)
V=card_img_hsv.item(i,j,2)
iflimit1count+=1
ifcount>row_num-row_num_limit:
ifxl>j:
xl=j
ifxrxr=j
returnxl,xr,yh,yl
defpredict(self,car_pic):
iftype(car_pic)==type(""):
img=imreadex(car_pic)
else:
img=car_pic
pic_hight,pic_width=img.shape[:
2]
ifpic_width>MAX_WIDTH:
resize_rate=MAX_WIDTH/pic_width
img=cv2.resize(img,(MAX_WIDTH,int(pic_hight*resize_rate)),interpolation=cv2.INTER_AREA)
blur=self.cfg["blur"]
#高斯去噪
ifblur>0:
img=cv2.GaussianBlur(img,(blur,blur),0)#图片分辨率调整
oldimg=img
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#equ=cv2.equalizeHist(img)
#img=np.hstack((img,equ))
#去掉图像中不会是车牌的区域
kernel=np.ones((20,20),np.uint8)
img_opening=cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
img_opening=cv2.addWeighted(img,1,img_opening,-1,0);
#找到图像边缘
ret,img_thresh=cv2.threshold(img_opening,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
img_edge=cv2.Canny(img_thresh,100,200)
#使用开运算和闭运算让图像边缘成为一个整体
kernel=np.ones((self.cfg["morphologyr"],self.cfg["morphologyc"]),np.uint8)
img_edge1=cv2.morphologyEx(img_edge,cv2.MORPH_CLOSE,kernel)
img_edge2=cv2.morphologyEx(img_edge1,cv2.MORPH_OPEN,kernel)
#查找图像边缘整体形成的矩形区域,可能有很多,车牌就在其中一个矩形区域中
image,contours,hierarchy=cv2.findContours(img_edge2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
contours=[cntforcntincontoursifcv2.contourArea(cnt)>Min_Area]
print('len(contours)',len(contours))
#一一排除不是车牌的矩形区域
car_contours=[]
forcntincontours:
rect=cv2.minAreaRect(cnt)
area_width,area_height=rect[1]
ifarea_widtharea_width,area_height=area_height,area_width
wh_ratio=area_width/area_height
#print(wh_ratio)
#要求矩形区域长宽比在2到5.5之间,2到5.5是车牌的长宽比,其余的矩形排除
ifwh_ratio>2andwh_ratio<5.5:
car_contours.append(rect)
box=cv2.boxPoints(rect)
box=np.int0(box)
#oldimg=cv2.drawContours(oldimg,[box],0,(0,0,255),2)
#cv2.imshow("edge4",oldimg)
#print(rect)
print(len(car_contours))
print("精确定位")
card_imgs=[]
#矩形区域可能是倾斜的矩形,需要矫正,以便使用颜色定位
forrectincar_contours:
ifrect[2]>-1andrect[2]<1:
#创造角度,使得左、高、右、低拿到正确的值
angle=1
else:
angle=rect[2]
rect=(rect[0],(rect[1][0]+5,rect[1][1]+5),angle)#扩大范围,避免车牌边缘被排除
box=cv2.boxPoints(rect)
heigth_point=right_point=[0,0]
left_point=low_point=[pic_width,pic_hight]
forpointinbox:
ifleft_point[0]>point[0]:
left_point=point
iflow_point[1]>point[1]:
low_point=point
ifheigth_point[1]heigth_point=point
ifright_point[0]right_point=point
ifleft_point[1]<=right_point[1]:
#正角度
new_right_point=[right_point[0],heigth_point[1]]
pts2=np.float32([left_point,heigth_point,new_right_point])#字符只是高度需要改变
pts1=np.float32([left_point,heigth_point,right_point])
M=cv2.getAffineTransform(pts1,pts2)
dst=cv2.warpAffine(oldimg,M,(pic_width,pic_hight))
point_limit(new_right_point)
point_limit(heigth_point)
point_limit(left_point)
card_img=dst[int(left_point[1]):
int(heigth_point[1]),int(left_point[0]):
int(new_right_point[0])]
card_imgs.append(card_img)