最后
针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。
上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
由于字符颜色与车牌底色不同,因此车牌区域中存在大量的颜色突变信息,这就为跳变次数法的实施创造了条件。所谓的跳变是指由字符区域过渡到非字符区域或者由非字符区域过渡到字符区域。具体做法是从上至下扫描出二值化后的车牌图像,找到跳变次数超过预先设定阈值的第一行,且之后连续3行跳变次数均超过阈值,则认定该行为车牌字符上边界;同理,从下至上扫描车牌图像,找到突变次数超过预先设定阈值的一行,且之后连续3行突变次数均超过阈值,则该行为车牌字符下边界。在确定车牌上下边界的前提下,接着确定车牌字符的左边界、右边界。因为车牌中可能存在数字1,数字1的跳变次数为2,为了防止滤除掉阿拉伯数字1,设定跳变次数的阈值为2。具体做法是从左至右扫描车牌图像,依次统计每列的跳变次数。找到跳变次数超过阈值的第一行,且之后连续3列跳变次数均超过阈值,则该行为车牌字符左边界;同理,找到车牌字符右边界。去除前后效果分别如图3-8和图3-9所示。
去除边框及铆钉后,图像上仍有一些残留的噪声点,这些残留的噪声点会对垂直投影法划分字符操作产生不良影响。因此,对去除边框和铆钉后的图像进行形态学腐蚀处理是非常有必要而且是至关重要的,腐蚀处理在去掉车牌字符区域残留噪声的同时,也可以对字符进行细化,形态学腐蚀处理效果如图3-10所示。
去除边框、铆钉,以及对字符进行细化处理后,接下来需要将车牌字符区域划分为单个字符。本文采取基于垂直投影法的字符划分方法[7][8]来划分车牌字符区域,依据车牌特点可知,每个字符之间都存在一定的纯黑区域。二值化后,字符区域为白色,车牌中的非字符区域为黑色。
划分单个字符的原理及具体流程如图3-11所示。首先计算每列中白色像素点个数,垂直投影后得到直方图,如图3-12所示,并以此来判断各个字符的起始位置。然后从左至右扫描投影直方图,找到存在白色像素点的第一列,则认定为该列是车牌第一个字符的左边界。若上一列存在白色像素点,而下一列是不存在白色像素点的黑色区域,则认定该列为第一个字符的右边界,同理,便可分割出其余6个车牌字符左右边界。投影得到的图像如图3-12所示,划分出的单个字符如图3-13所示。
由于从采集图像中提取出的车牌大小不完全相同,这就导致了划分出来的单个字符的尺寸可能不同,为了能够适应已经训练好的车牌字符识别网络,需要对划分出的单个车牌字符进行归一化处理,使得从采集图像中定位出的车牌在字符分割操作完成后,所获取的车牌单个字符图像大小都为20_20像素[2],如图3-11所示。这里至于为什么都归一化为20_20像素,是因为我的神经网络的输入都是20*20像素的。
for rect in car_contours:
rect = (rect[0], (rect[1][0]+20, rect[1][1]+5), rect[2])
box = cv2.boxPoints(rect)
#图像矫正 cv2.getAffineTransform(pos1,pos2),其中两个位置就是变换前后的对应位置关系。输出的就是仿射矩阵M,最后这个矩阵会被传给函数 cv2.warpAffine() 来实现仿射变换
if rect[2] > ANGLE: #正角度
new_right_point_x = vertices[0, 0]
new_right_point_y = int(vertices[1, 1] - (vertices[0, 0] - vertices[1, 0]) / (vertices[3, 0] - vertices[1, 0]) * (vertices[1, 1] - vertices[3, 1]))
new_left_point_x = vertices[1, 0]
new_left_point_y = int(vertices[0, 1] + (vertices[0, 0] - vertices[1, 0]) / (vertices[0, 0] - vertices[2, 0]) * (vertices[2, 1] - vertices[0, 1]))
point_set_1 = np.float32([[440, 0], [0, 0], [0, 140], [440, 140]])
elif rect[2] < ANGLE: #负角度
new_right_point_x = vertices[1, 0]
new_right_point_y = int(vertices[0, 1] + (vertices[1, 0] - vertices[0, 0]) / (vertices[3, 0] - vertices[0, 0]) * (vertices[3, 1] - vertices[0, 1]))
new_left_point_x = vertices[0, 0]
new_left_point_y = int(vertices[1, 1] - (vertices[1, 0] - vertices[0, 0]) / (vertices[1, 0] - vertices[2, 0]) * (vertices[1, 1] - vertices[2, 1]))
point_set_1 = np.float32([[0, 0], [0, 140], [440, 140], [440, 0]])
new_box = np.array([(vertices[0, 0], vertices[0, 1]), (new_left_point_x, new_left_point_y), (vertices[1, 0], vertices[1, 1]),(new_right_point_x, new_right_point_y)])
point_set_0 = np.float32(new_box)
mat = cv2.getPerspectiveTransform(point_set_0, point_set_1)
dst = cv2.warpPerspective(img, mat, (440, 140))
cv_show(‘dst’,dst)
#-------------------------------字符分割-------------------------------------
plate_original = dst.copy()
img_aussian = cv2.GaussianBlur(dst,(5,5),1)
cv_show(‘img_aussian’,img_aussian)
#中值滤波
dst = cv2.medianBlur(img_aussian,3)
对车牌进行精准定位
img_B = cv2.split(dst)[0]
img_G = cv2.split(dst)[1]
img_R = cv2.split(dst)[2]
for i in range(dst.shape[:2][0]):
for j in range(dst.shape[:2][1]):
if abs(img_B[i,j] - Blue) < THRESHOLD and abs(img_G[i,j] - Green) <THRESHOLD and abs(img_R[i,j] - Red) < THRESHOLD:
dst[i][j][0] = 0
dst[i][j][1] = 0
dst[i][j][2] = 0
else:
dst[i][j][0] = 255
dst[i][j][1] = 255
dst[i][j][2] = 255
cv_show(‘dst’,dst)
灰度化
gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
cv_show(‘gray’,gray)
#-------------------------------跳变次数去掉铆钉和边框----------------------------------
times_row = [] #存储哪些行符合跳变次数的阈值
for row in range(LICENSE_HIGH): # 按行检测 白字黑底
pc = 0
for col in range(LICENSE_WIDTH):
if col != LICENSE_WIDTH-1:
if gray[row][col+1] != gray[row][col]:
pc = pc + 1
times_row.append(pc)
print(“每行的跳变次数:”,times_row)
#找车牌的下边缘-从下往上扫描
row_end = 0
row_start = 0
for row in range(LICENSE_HIGH-2):
if times_row[row] < 16:
continue
elif times_row[row+1] < 16:
continue
elif times_row[row+2] < 16:
continue
else:
row_end = row + 2
print(“row_end”,row_end)
#找车牌的上边缘-从上往下扫描
i = LICENSE_HIGH-1
row_num = [] #记录row_start可能的位置
while i > 1:
if times_row[i] < 16:
i = i - 1
continue
elif times_row[i-1] < 16:
i = i - 1
continue
elif times_row[i-2] < 16:
i = i - 1
continue
else:
row_start = i - 2
row_num.append(row_start)
i = i - 1
print(“row_num”,row_num)
#确定row_start最终位置
for i in range(len(row_num)):
if i != len(row_num)-1:
if abs(row_num[i] - row_num[i+1])>3:
row_start = row_num[i]
print(“row_start”,row_start)
times_col = [0]
for col in range(LICENSE_WIDTH):
pc = 0
for row in range(LICENSE_HIGH):
if row != LICENSE_HIGH-1:
if gray[row,col] != gray[row+1,col]:
pc = pc + 1
times_col.append(pc)
print(“每列的跳变次数”,times_col)
找车牌的左右边缘-从左到右扫描
col_start = 0
col_end = 0
for col in range(len(times_col)):
if times_col[col] > 2:
col_end = col
print(‘col_end’,col_end)
j = LICENSE_WIDTH-1
while j >= 0:
if times_col[j] > 2:
col_start = j
j = j-1
print(‘col_start’,col_start)
将车牌非字符区域变成纯黑色
for i in range(LICENSE_HIGH):
if i > row_end or i < row_start:
gray[i] = 0
for j in range(LICENSE_WIDTH):
if j < col_start or j > col_end:
gray[:,j] = 0
cv_show(“res”,gray)
分享
首先分享一份学习大纲,内容较多,涵盖了互联网行业所有的流行以及核心技术,以截图形式分享:
(亿级流量性能调优实战+一线大厂分布式实战+架构师筑基必备技能+设计思想开源框架解读+性能直线提升架构技术+高效存储让项目性能起飞+分布式扩展到微服务架构…实在是太多了)
其次分享一些技术知识,以截图形式分享一部分:
Tomcat架构解析:
算法训练+高分宝典:
Spring Cloud+Docker微服务实战:
最后分享一波面试资料:
切莫死记硬背,小心面试官直接让你出门右拐
1000道互联网Java面试题:
Java高级架构面试知识整理:
(img-XHkc6fkF-1714892557430)]
最后分享一波面试资料:
切莫死记硬背,小心面试官直接让你出门右拐
1000道互联网Java面试题:
[外链图片转存中…(img-n4oJ1JtN-1714892557431)]
Java高级架构面试知识整理:
[外链图片转存中…(img-5huL2tpb-1714892557431)]