python opencv车牌图像校正
1.OpenCV--图片处理操作
2.python opencv车牌图像校正
车牌图片
代码
# -*- coding: UTF-8 -*-
import cv2
import numpy as np
# 预处理
def imgProcess(path):
img = cv2.imread(path)
# 统一规定大小
img = cv2.resize(img, (640, 480))
# 高斯模糊
img_Gas = cv2.GaussianBlur(img, (5, 5), 0)
# RGB通道分离
img_B = cv2.split(img_Gas)[0]
img_G = cv2.split(img_Gas)[1]
img_R = cv2.split(img_Gas)[2]
# 读取灰度图和HSV空间图
img_gray = cv2.cvtColor(img_Gas, cv2.COLOR_BGR2GRAY)
img_HSV = cv2.cvtColor(img_Gas, cv2.COLOR_BGR2HSV)
return img, img_Gas, img_B, img_G, img_R, img_gray, img_HSV
# 初步识别
def preIdentification(img_gray, img_HSV, img_B, img_R):
"""
图像二值化
:param img_gray:
:param img_HSV:
:param img_B:
:param img_R:
:return:
"""
for i in range(480):
for j in range(640):
# 普通蓝色车牌,同时排除透明反光物质的干扰
if ((img_HSV[:, :, 0][i, j]-115)**2 < 15**2) and (img_B[i, j] > 70) and (img_R[i, j] < 40):
img_gray[i, j] = 255
else:
img_gray[i, j] = 0
# 定义核
kernel_small = np.ones((3, 3))
kernel_big = np.ones((7, 7))
img_gray = cv2.GaussianBlur(img_gray, (5, 5), 0) # 高斯平滑
img_di = cv2.dilate(img_gray, kernel_small, iterations=5) # 腐蚀5次
img_close = cv2.morphologyEx(img_di, cv2.MORPH_CLOSE, kernel_big) # 闭操作
img_close = cv2.GaussianBlur(img_close, (5, 5), 0) # 高斯平滑
_, img_bin = cv2.threshold(img_close, 100, 255, cv2.THRESH_BINARY) # 二值化
return img_bin
# 定位
def fixPosition(img, img_bin):
"""
对二值化后的图片进行车牌定位,根据车牌区域的大致长宽比进行筛选,获得车牌最可能得区域
:param img:
:param img_bin:
:return:
"""
# 检测所有外轮廓,只留矩形的四个顶点
contours, _ = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# print(f'contours={contours}')
# 形状及大小筛选校验
det_x_max = 0
det_y_max = 0
num = 0
for i in range(len(contours)):
# print('i=', contours[i])
x_min = np.min(contours[i][:, :, 0])
x_max = np.max(contours[i][:, :, 0])
y_min = np.min(contours[i][:, :, 1])
y_max = np.max(contours[i][:, :, 1])
det_x = x_max - x_min
det_y = y_max - y_min
print(f'det_x={det_x}, det_y={det_y}')
if (det_x / det_y > 1.8) and (det_x > det_x_max) and (det_y > det_y_max):
det_y_max = det_y
det_x_max = det_x
num = i
# 获取最可疑区域轮廓点集
points = np.array(contours[num][:, 0])
print(f'points={points}')
return points
# img_lic_canny = cv2.Canny(img_lic_bin, 100, 200)
def findVertices(points):
"""
# 获取最小外接矩阵,中心点坐标,宽高,旋转角度
:param points:
:return:
"""
rect = cv2.minAreaRect(points) # 生成最小外接矩形,返回最小外接矩形的中心(x,y),(宽度,高度),旋转角度
print(f'rect={rect}')
# 获取矩形四个顶点,浮点型
box = cv2.boxPoints(rect)
print(f'box={box}')
# 取整
box = np.int0(box)
# 获取四个顶点坐标
left_point_x = np.min(box[:, 0])
right_point_x = np.max(box[:, 0])
top_point_y = np.min(box[:, 1])
bottom_point_y = np.max(box[:, 1])
left_point_y = box[:, 1][np.where(box[:, 0] == left_point_x)][0]
right_point_y = box[:, 1][np.where(box[:, 0] == right_point_x)][0]
top_point_x = box[:, 0][np.where(box[:, 1] == top_point_y)][0]
bottom_point_x = box[:, 0][np.where(box[:, 1] == bottom_point_y)][0]
# 上下左右四个点坐标
vertices = np.array([[top_point_x, top_point_y], [bottom_point_x, bottom_point_y], [left_point_x, left_point_y],
[right_point_x, right_point_y]])
print(f'vertices={vertices}')
return vertices, rect
def tiltCorrection(vertices, rect):
# 畸变情况1
if rect[2] > -45: # 倾斜角度
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]])
# 畸变情况2
elif rect[2] < -45:
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)
return point_set_0, point_set_1, new_box
def transform(img, point_set_0, point_set_1):
# 变换矩阵
mat = cv2.getPerspectiveTransform(point_set_0, point_set_1)
# 投影变换
lic = cv2.warpPerspective(img, mat, (440, 140))
return lic
def main():
# 图片路径
path = "./car_license.png"
# 图像预处理
img, img_Gas, img_B, img_G, img_R, img_gray, img_HSV = imgProcess(path)
# 初步识别
img_bin = preIdentification(img_gray, img_HSV, img_B, img_R)
# print('img_bin=', img_bin)
points = fixPosition(img, img_bin)
vertices, rect = findVertices(points)
point_set_0, point_set_1, new_box = tiltCorrection(vertices, rect)
img_draw = cv2.drawContours(img.copy(), [new_box], -1, (0, 0, 255), 3)
lic = transform(img, point_set_0, point_set_1)
# 原图上框出车牌
cv2.namedWindow("Image")
cv2.imshow("Image", img_draw)
# 二值化图像
cv2.namedWindow("Image_Bin")
cv2.imshow("Image_Bin", img_bin) # 二值化后的图片
# 显示校正后的车牌
cv2.namedWindow("Lic")
cv2.imshow("Lic", lic)
# 暂停、关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具