融合了hyperlpr3和opencv 来检测车牌
通过图片检测车牌的系统,使用了pyqt和hyperlpr3结合来进行检测,可以保存检测的结果到excel文件
亲自测试修改代码,运行正常并且不依赖百度网络api, 纯本地运行,融合了2个车牌检测模型,
第一个模型使用opencv 来模糊图像,然后进行边缘检测和轮廓检测,然后通过几何条件,矩形长宽,比例过滤轮廓,最后通过颜色过滤轮廓,得到车牌的轮廓区域;
第二个模型使用 vlpr 库来进行车牌检测;
然后把结果显示在左侧,并可以对结果进行输出。
我的工作是融合了两个车牌检测的模型,并且把所以的代码融合到了一个python文件,使得系统更加精简,容易修改。
# -*- coding: utf-8 -*-
# 通过图片检测车牌的系统,使用了pyqt和hyperlpr3结合来进行检测,可以保存检测的结果到excel文件
import sys, os, xlwt, time, json #
from sys import exit, argv
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import cv2
import hyperlpr3 as lpr3
# pip install hyperlpr3 -i https://pypi.tuna.tsinghua.edu.cn/simple/
import cv2 as cv
big = False
def drawRectBox(image, rect, addText, fontC):
cv.rectangle(image, (int(round(rect[0])), int(round(rect[1]))),
(int(round(rect[2]) + 8), int(round(rect[3]) + 8)),
(0, 0, 255), 2)
cv.rectangle(image, (int(rect[0] - 1), int(rect[1]) - 16), (int(rect[0] + 75), int(rect[1])), (0, 0, 255), -1, cv.LINE_AA)
img = Image.fromarray(image)
draw = ImageDraw.Draw(img)
draw.text((int(rect[0] + 1), int(rect[1] - 16)), addText, (255, 255, 255), font=fontC)
imagex = np.array(img)
return imagex
# Instantiate object
catcher = lpr3.LicensePlateCatcher()
class PlateRecognition():
def __init__(self):
self.MAX_WIDTH = 1000 # 原始图片最大宽度
self.Min_Area = 2000 # 车牌区域允许最大面积
self.PROVINCE_START = 1000
# 省份代码保存在provinces.json中
self.provinces = json.loads('["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", "浙"]')
# 车牌类型保存在cardtype.json中,便于调整
self.cardtype = json.loads('{"blue": "蓝色牌照", "green": "绿色牌照", "yellow": "黄色牌照"}')
# 字母所代表的地区保存在Prefecture.json中,便于更新
self.Prefecture = json.loads('{"冀": {"A": ["河北省", "石家庄市"], "B": ["河北省", "唐山市"], "C": ["河北省", "秦皇岛市"], "D": ["河北省", "邯郸市"], "E": ["河北省", "邢台市"], "F": ["河北省", "保定市"], "G": ["河北省", "张家口市"], "H": ["河北省", "承德市"], "J": ["河北省", "沧州市"], "R": ["河北省", "廊坊市"], "S": ["河北省", "沧州市"], "T": ["河北省", "衡水市"]}, "辽": {"A": ["辽宁省", "沈阳市"], "B": ["辽宁省", "大连市"], "C": ["辽宁省", "鞍山市"], "D": ["辽宁省", "抚顺市"], "E": ["辽宁省", "本溪市"], "F": ["辽宁省", "丹东市"], "G": ["辽宁省", "锦州市"], "H": ["辽宁省", "营口市"], "J": ["辽宁省", "阜新市"], "K": ["辽宁省", "辽阳市"], "L": ["辽宁省", "盘锦市"], "M": ["辽宁省", "铁岭市"], "N": ["辽宁省", "朝阳市"], "P": ["辽宁省", "葫芦岛市"]}, "皖": {"A": ["安徽省", "合肥市"], "B": ["安徽省", "芜湖市"], "C": ["安徽省", "蚌埠市"], "D": ["安徽省", "淮南市"], "E": ["安徽省", "马鞍山市"], "F": ["安徽省", "淮北市"], "G": ["安徽省", "铜陵市"], "H": ["安徽省", "安庆市"], "J": ["安徽省", "黄山市"], "K": ["安徽省", "阜阳市"], "L": ["安徽省", "宿州市"], "M": ["安徽省", "滁州市"], "N": ["安徽省", "六安市"], "P": ["安徽省", "宣城市"], "Q": ["安徽省", "巢湖市"], "R": ["安徽省", "池州市"], "S": ["安徽省", "亳州市"]}, "苏": {"A": ["江苏省", "南京市"], "B": ["江苏省", "无锡市"], "C": ["江苏省", "徐州市"], "D": ["江苏省", "常州市"], "E": ["江苏省", "苏州市"], "F": ["江苏省", "南通市"], "G": ["江苏省", "连云港市"], "H": ["江苏省", "淮安市"], "J": ["江苏省", "盐城市"], "K": ["江苏省", "扬州市"], "L": ["江苏省", "镇江市"], "M": ["江苏省", "泰州市"], "N": ["江苏省", "宿迁市"]}, "鄂": {"A": ["湖北省", "武汉市"], "B": ["湖北省", "黄石市"], "C": ["湖北省", "十堰市"], "D": ["湖北省", "荆州市"], "E": ["湖北省", "宜昌市"], "F": ["湖北省", "襄樊市"], "G": ["湖北省", "鄂州市"], "H": ["湖北省", "荆门市"], "J": ["湖北省", "黄冈市"], "K": ["湖北省", "孝感市"], "L": ["湖北省", "咸宁市"], "M": ["湖北省", "仙桃市"], "N": ["湖北省", "潜江市"], "P": ["湖北省", "神农架林区"], "Q": ["湖北省", "恩施土家族苗族自治州"], "R": ["湖北省", "天门市"], "S": ["湖北省", "随州市"]}, "晋": {"A": ["山西省", "太原市"], "B": ["山西省", "大同市"], "C": ["山西省", "阳泉市"], "D": ["山西省", "长治市"], "E": ["山西省", "晋城市"], "F": ["山西省", "朔州市"], "H": ["山西省", "忻州市"], "J": ["山西省", "吕梁市"], "K": ["山西省", "晋中市"], "L": ["山西省", "临汾市"], "M": ["山西省", "运城市"]}, "吉": {"A": ["吉林省", "长春市"], "B": ["吉林省", "吉林市"], "C": ["吉林省", "四平市"], "D": ["吉林省", "辽源市"], "E": ["吉林省", "通化市"], "F": ["吉林省", "白山市"], "G": ["吉林省", "白城市"], "H": ["吉林省", "延边朝鲜族自治州"], "J": ["吉林省", "松原市"], "K": ["吉林省", "长白朝鲜族自治县"]}, "粤": {"A": ["广东省", "广州市"], "B": ["广东省", "深圳市"], "C": ["广东省", "珠海市"], "D": ["广东省", "汕头市"], "E": ["广东省", "佛山市"], "F": ["广东省", "韶关市"], "G": ["广东省", "湛江市"], "H": ["广东省", "肇庆市"], "J": ["广东省", "江门市"], "K": ["广东省", "茂名市"], "L": ["广东省", "惠州市"], "M": ["广东省", "梅州市"], "N": ["广东省", "汕尾市"], "P": ["广东省", "河源市"], "Q": ["广东省", "阳江市"], "R": ["广东省", "清远市"], "S": ["广东省", "东莞市"], "T": ["广东省", "中山市"], "U": ["广东省", "潮州市"], "V": ["广东省", "揭阳市"], "W": ["广东省", "云浮市"], "X": ["广东省", "顺德区"], "Y": ["广东省", "南海区"], "Z": ["广东省", "港澳进入内地车辆"]}, "藏": {"A": ["西藏自治区", "拉萨市"], "B": ["西藏自治区", "昌都地区"], "C": ["西藏自治区", "山南地区"], "D": ["西藏自治区", "日喀则地区"], "E": ["西藏自治区", "那曲地区"], "F": ["西藏自治区", "阿里地区"], "G": ["西藏自治区", "林芝地区"], "H": ["西藏自治区", "驻四川省天全县车辆管理所"], "J": ["西藏自治区", "驻青海省格尔木市车辆管理所"]}, "渝": {"A": ["重庆市"], "B": ["重庆市"], "C": ["重庆市"], "F": ["重庆市"], "G": ["重庆市"], "H": ["重庆市"]}, "沪": {"A": ["上海市"], "B": ["上海市"], "C": ["上海市"], "D": ["上海市"], "R": ["上海市"]}, "豫": {"A": ["河南省", "郑州市"], "B": ["河南省", "开封市"], "C": ["河南省", "洛阳市"], "D": ["河南省", "平顶山市"], "E": ["河南省", "安阳市"], "F": ["河南省", "鹤壁市"], "G": ["河南省", "新乡市"], "H": ["河南省", "焦作市"], "J": ["河南省", "濮阳市"], "K": ["河南省", "许昌市"], "L": ["河南省", "漯河市"], "M": ["河南省", "三门峡市"], "N": ["河南省", "商丘市"], "P": ["河南省", "周口市"], "Q": ["河南省", "驻马店市"], "R": ["河南省", "南阳市"], "S": ["河南省", "信阳市"], "U": ["河南省", "济源市"]}, "黑": {"A": ["黑龙江省", "哈尔滨市"], "B": ["黑龙江省", "齐齐哈尔市"], "C": ["黑龙江省", "牡丹江市"], "D": ["黑龙江省", "佳木斯市"], "E": ["黑龙江省", "大庆市"], "F": ["黑龙江省", "伊春市"], "G": ["黑龙江省", "鸡西市"], "H": ["黑龙江省", "鹤岗市"], "J": ["黑龙江省", "双鸭山市"], "K": ["黑龙江省", "七台河市"], "L": ["黑龙江省", "松花江地区(已并入哈尔滨市,车牌未改)"], "M": ["黑龙江省", "绥化市"], "N": ["黑龙江省", "黑河市"], "P": ["黑龙江省", "大兴安岭地区"], "R": ["黑龙江省", "农垦系统"]}, "鲁": {"A": ["山东省", "济南市"], "B": ["山东省", "青岛市"], "C": ["山东省", "淄博市"], "D": ["山东省", "枣庄市"], "E": ["山东省", "东营市"], "F": ["山东省", "烟台市"], "G": ["山东省", "潍坊市"], "H": ["山东省", "济宁市"], "J": ["山东省", "泰安市"], "K": ["山东省", "威海市"], "L": ["山东省", "日照市"], "M": ["山东省", "滨州市"], "N": ["山东省", "德州市"], "P": ["山东省", "聊城市"], "Q": ["山东省", "临沂市"], "R": ["山东省", "菏泽市"], "S": ["山东省", "莱芜市"], "U": ["山东省", "青岛市"], "V": ["山东省", "潍坊市"], "Y": ["山东省", "烟台市"]}, "浙": {"A": ["浙江省", "杭州市"], "B": ["浙江省", "宁波市"], "C": ["浙江省", "温州市"], "D": ["浙江省", "绍兴市"], "E": ["浙江省", "湖州市"], "F": ["浙江省", "嘉兴市"], "G": ["浙江省", "金华市"], "H": ["浙江省", "衢州市"], "J": ["浙江省", "台州市"], "K": ["浙江省", "丽水市"], "L": ["浙江省", "舟山市"]}, "桂": {"A": ["广西省", "南宁市"], "B": ["广西省", "柳州市"], "C": ["广西省", "桂林市"], "D": ["广西省", "梧州市"], "E": ["广西省", "北海市"], "F": ["广西省", "崇左市"], "G": ["广西省", "来宾市"], "H": ["广西省", "桂林市"], "J": ["广西省", "贺州市"], "K": ["广西省", "玉林市"], "M": ["广西省", "河池市"], "N": ["广西省", "钦州市"], "P": ["广西省", "防城港市"], "R": ["广西省", "贵港市"]}, "蒙": {"A": ["内蒙古自治区", "呼和浩特市"], "B": ["内蒙古自治区", "包头市"], "C": ["内蒙古自治区", "乌海市"], "D": ["内蒙古自治区", "赤峰市"], "E": ["内蒙古自治区", "呼伦贝尔市"], "F": ["内蒙古自治区", "兴安盟"], "G": ["内蒙古自治区", "通辽市"], "H": ["内蒙古自治区", "锡林郭勒盟"], "J": ["内蒙古自治区", "乌兰察布市"], "K": ["内蒙古自治区", "鄂尔多斯市"], "L": ["内蒙古自治区", "巴彦淖尔市"], "M": ["内蒙古自治区", "阿拉善盟"]}, "闽": {"A": ["福建省", "福州市"], "B": ["福建省", "莆田市"], "C": ["福建省", "泉州市"], "D": ["福建省", "厦门市"], "E": ["福建省", "漳州市"], "F": ["福建省", "龙岩市"], "G": ["福建省", "三明市"], "H": ["福建省", "南平市"], "J": ["福建省", "宁德市"], "K": ["福建省", "省直系统"]}, "川": {"A": ["四川省", "成都市"], "B": ["四川省", "绵阳市"], "C": ["四川省", "自贡市"], "D": ["四川省", "攀枝花市"], "E": ["四川省", "泸州市"], "F": ["四川省", "德阳市"], "H": ["四川省", "广元市"], "J": ["四川省", "遂宁市"], "K": ["四川省", "内江市"], "L": ["四川省", "乐山市"], "M": ["四川省", "资阳市"], "Q": ["四川省", "宜宾市"], "R": ["四川省", "南充市"], "S": ["四川省", "达州市"], "T": ["四川省", "雅安市"], "U": ["四川省", "阿坝藏族羌族自治州"], "V": ["四川省", "甘孜藏族自治州"], "W": ["四川省", "凉山彝族自治州"], "X": ["四川省", "广安市"], "Y": ["四川省", "巴中市"], "Z": ["四川省", "眉山市"]}, "琼": {"A": ["海南省", "海口市"], "B": ["海南省", "三亚市"], "C": ["海南省", "琼海市"], "D": ["海南省", "五指山市"], "E": ["海南省", "洋浦开发区"]}, "京": {"A": ["北京市"], "B": ["北京市"], "C": ["北京市"], "D": ["北京市"], "E": ["北京市"], "F": ["北京市"], "G": ["北京市"], "H": ["北京市"], "J": ["北京市"], "K": ["北京市"], "L": ["北京市"], "M": ["北京市"], "N": ["北京市"], "P": ["北京市"], "Q": ["北京市"]}, "云": {"A": ["云南省", "昆明市"], "C": ["云南省", "昭通市"], "D": ["云南省", "曲靖市"], "E": ["云南省", "楚雄彝族自治州"], "F": ["云南省", "玉溪市"], "G": ["云南省", "红河哈尼族彝族自治州"], "H": ["云南省", "文山壮族苗族自治州"], "J": ["云南省", "思茅区"], "K": ["云南省", "西双版纳傣族自治州"], "L": ["云南省", "大理白族自治州"], "M": ["云南省", "保山市"], "N": ["云南省", "德宏傣族景颇族自治州"], "P": ["云南省", "丽江市"], "Q": ["云南省", "怒江傈僳族自治州"], "R": ["云南省", "迪庆藏族自治州"], "S": ["云南省", "临沧市"]}, "湘": {"A": ["湖南省", "长沙市"], "B": ["湖南省", "株洲市"], "C": ["湖南省", "湘潭市"], "D": ["湖南省", "衡阳市"], "E": ["湖南省", "邵阳市"], "F": ["湖南省", "岳阳市"], "G": ["湖南省", "张家界市"], "H": ["湖南省", "益阳市"], "J": ["湖南省", "常德市"], "K": ["湖南省", "娄底市"], "L": ["湖南省", "郴州市"], "M": ["湖南省", "永州市"], "N": ["湖南省", "怀化市"], "U": ["湖南省", "湘西土家族苗族自治州"]}, "新": {"A": ["新疆维吾尔自治区", "乌鲁木齐市"], "B": ["新疆维吾尔自治区", "昌吉回族自治州"], "C": ["新疆维吾尔自治区", "石河子市"], "D": ["新疆维吾尔自治区", "奎屯市"], "E": ["新疆维吾尔自治区", "博尔塔拉蒙古自治州"], "F": ["新疆维吾尔自治区", "伊犁哈萨克自治州"], "G": ["新疆维吾尔自治区", "塔城地区"], "H": ["新疆维吾尔自治区", "阿勒泰地区"], "J": ["新疆维吾尔自治区", "克拉玛依市"], "K": ["新疆维吾尔自治区", "吐鲁番地区"], "L": ["新疆维吾尔自治区", "哈密地区"], "M": ["新疆维吾尔自治区", "巴音郭愣蒙古自治州"], "N": ["新疆维吾尔自治区", "阿克苏地区"], "P": ["新疆维吾尔自治区", "克孜勒苏柯尔克孜自治州"], "Q": ["新疆维吾尔自治区", "喀什地区"], "R": ["新疆维吾尔自治区", "和田地区"]}, "赣": {"A": ["江西省", "南昌市"], "B": ["江西省", "赣州市"], "C": ["江西省", "宜春市"], "D": ["江西省", "吉安市"], "E": ["江西省", "上饶市"], "F": ["江西省", "抚州市"], "G": ["江西省", "九江市"], "H": ["江西省", "景德镇市"], "J": ["江西省", "萍乡市"], "K": ["江西省", "新余市"], "L": ["江西省", "鹰潭市"], "M": ["江西省", "南昌市"]}, "甘": {"A": ["甘肃省", "兰州市"], "B": ["甘肃省", "嘉峪关市"], "C": ["甘肃省", "金昌市"], "D": ["甘肃省", "白银市"], "E": ["甘肃省", "天水市"], "F": ["甘肃省", "酒泉市"], "G": ["甘肃省", "张掖市"], "H": ["甘肃省", "武威市"], "J": ["甘肃省", "定西市"], "K": ["甘肃省", "陇南市"], "L": ["甘肃省", "平凉市"], "M": ["甘肃省", "庆阳市"], "N": ["甘肃省", "临夏回族自治州"], "P": ["甘肃省", "甘南藏族自治州"]}, "陕": {"A": ["陕西省", "西安市"], "B": ["陕西省", "铜川市"], "C": ["陕西省", "宝鸡市"], "D": ["陕西省", "咸阳市"], "E": ["陕西省", "渭南市"], "F": ["陕西省", "汉中市"], "G": ["陕西省", "安康市"], "H": ["陕西省", "商洛市"], "J": ["陕西省", "延安市"], "K": ["陕西省", "榆林市"], "V": ["陕西省", "杨凌区"]}, "贵": {"A": ["贵族省", "贵阳市"], "B": ["贵族省", "六盘水市"], "C": ["贵族省", "遵义市"], "D": ["贵族省", "铜仁地区"], "E": ["贵族省", "黔西南布依族苗族自治州"], "F": ["贵族省", "毕节地区"], "G": ["贵族省", "安顺市"], "H": ["贵族省", "黔东南苗族侗族自治州"], "J": ["贵族省", "黔南布依族苗族自治州"]}, "青": {"A": ["青海省", "西宁市"], "B": ["青海省", "海东地区"], "C": ["青海省", "海北藏族自治州"], "D": ["青海省", "黄南藏族自治州"], "E": ["青海省", "海南藏族自治州"], "F": ["青海省", "果洛藏族自治州"], "G": ["青海省", "玉树藏族自治州"], "H": ["青海省", "海西蒙古族藏族自治州"]}, "宁": {"A": ["宁夏回族自治区", "银川市"], "B": ["宁夏回族自治区", "石嘴山市"], "C": ["宁夏回族自治区", "银南市"], "D": ["宁夏回族自治区", "固原市"], "E": ["宁夏回族自治区", "中卫市"]}, "津": {"A": ["天津市"], "B": ["天津市"], "C": ["天津市"], "D": ["天津市"], "E": ["天津市"], "F": ["天津市"], "G": ["天津市"], "H": ["天津市"]}}')
# 车牌识别的部分参数保存在js中,便于根据图片分辨率做调整
# f = open('config.js')
j = json.loads('{"open":1, "blur":3, "morphologyr":4, "morphologyc":19, "col_num_limit":10, "row_num_limit":21 }')
# for c in j["config"]:
if j["open"]:
self.cfg = j.copy()
# break
def __del__(self):
pass
# 读取图片文件
def __imreadex(self, filename):
return cv2.imdecode(np.fromfile(filename, dtype=np.uint8), cv2.IMREAD_COLOR)
def __point_limit(self, point):
if point[0] < 0:
point[0] = 0
if point[1] < 0:
point[1] = 0
def accurate_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.8 if color != "green" else col_num * 0.5 # 绿色有渐变
for i in range(row_num):
count = 0
for j in range(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)
if limit1 < H <= limit2 and 34 < S and 46 < V:
count += 1
if count > col_num_limit:
if yl > i:
yl = i
if yh < i:
yh = i
for j in range(col_num):
count = 0
for i in range(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)
if limit1 < H <= limit2 and 34 < S and 46 < V:
count += 1
if count > row_num - row_num_limit:
if xl > j:
xl = j
if xr < j:
xr = j
return xl, xr, yh, yl
# 预处理
def pretreatment(self, car_pic):
if type(car_pic) == type(""):
img = self.__imreadex(car_pic)
else:
img = car_pic
pic_hight, pic_width = img.shape[:2]
if pic_width > self.MAX_WIDTH:
resize_rate = self.MAX_WIDTH / pic_width
img = cv2.resize(img, (self.MAX_WIDTH, int(pic_hight * resize_rate)),
interpolation=cv2.INTER_AREA) # 图片分辨率调整
# cv2.imshow('Image', img)
blur = self.cfg["blur"]
# 高斯去噪
if blur > 0:
img = cv2.GaussianBlur(img, (blur, blur), 0)
oldimg = img
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.imshow('GaussianBlur', img)
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); # 与上一次开运算结果融合
# cv2.imshow('img_opening', img_opening)
# 找到图像边缘
ret, img_thresh = cv2.threshold(img_opening, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # 二值化
img_edge = cv2.Canny(img_thresh, 100, 200)
# cv2.imshow('img_edge', img_edge)
# 使用开运算和闭运算让图像边缘成为一个整体
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) # 开运算
# cv2.imshow('img_edge2', img_edge2)
# cv2.imwrite('./edge2.png', img_edge2)
# 查找图像边缘整体形成的矩形区域,可能有很多,车牌就在其中一个矩形区域中
# image, contours, hierarchy = cv2.findContours(img_edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours, hierarchy = cv2.findContours(img_edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = [cnt for cnt in contours if cv2.contourArea(cnt) > self.Min_Area]
# print(contours[0])
# 逐个排除不是车牌的矩形区域
car_contours = []
for cnt in contours:
# 框选 生成最小外接矩形 返回值(中心(x,y), (宽,高), 旋转角度)
rect = cv2.minAreaRect(cnt)
# print('宽高:',rect[1])
area_width, area_height = rect[1]
# 选择宽大于高的区域
if area_width < area_height:
area_width, area_height = area_height, area_width
wh_ratio = area_width / area_height
# print('宽高比:',wh_ratio)
# 要求矩形区域长宽比在2到5.5之间,2到5.5是车牌的长宽比,其余的矩形排除
if wh_ratio > 2 and wh_ratio < 5.5:
car_contours.append(rect)
box = cv2.boxPoints(rect)
box = np.int0(box)
# 框出所有可能的矩形
# oldimg = cv2.drawContours(img, [box], 0, (0, 0, 255), 2)
# cv2.imshow("Test",oldimg )
# print(car_contours)
# 矩形区域可能是倾斜的矩形,需要矫正,以便使用颜色定位
card_imgs = []
for rect in car_contours:
if rect[2] > -1 and rect[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]
for point in box:
if left_point[0] > point[0]:
left_point = point
if low_point[1] > point[1]:
low_point = point
if heigth_point[1] < point[1]:
heigth_point = point
if right_point[0] < point[0]:
right_point = point
if left_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))
self.__point_limit(new_right_point)
self.__point_limit(heigth_point)
self.__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)
elif left_point[1] > right_point[1]: # 负角度
new_left_point = [left_point[0], heigth_point[1]]
pts2 = np.float32([new_left_point, heigth_point, 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))
self.__point_limit(right_point)
self.__point_limit(heigth_point)
self.__point_limit(new_left_point)
card_img = dst[int(right_point[1]):int(heigth_point[1]), int(new_left_point[0]):int(right_point[0])]
card_imgs.append(card_img)
# cv2.imshow("card", card_imgs[0])
# #____开始使用颜色定位,排除不是车牌的矩形,目前只识别蓝、绿、黄车牌
colors = []
for card_index, card_img in enumerate(card_imgs):
green = yellow = blue = black = white = 0
try:
# 有转换失败的可能,原因来自于上面矫正矩形出错
card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
except:
print('BGR转HSV失败')
card_imgs = colors = None
return card_imgs, colors
if card_img_hsv is None:
continue
row_num, col_num = card_img_hsv.shape[:2]
card_img_count = row_num * col_num
# 确定车牌颜色
for i in range(row_num):
for j in range(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)
if 11 < H <= 34 and S > 34: # 图片分辨率调整
yellow += 1
elif 35 < H <= 99 and S > 34: # 图片分辨率调整
green += 1
elif 99 < H <= 124 and S > 34: # 图片分辨率调整
blue += 1
if 0 < H < 180 and 0 < S < 255 and 0 < V < 46:
black += 1
elif 0 < H < 180 and 0 < S < 43 and 221 < V < 225:
white += 1
color = "no"
# print('黄:{:<6}绿:{:<6}蓝:{:<6}'.format(yellow,green,blue))
limit1 = limit2 = 0
if yellow * 2 >= card_img_count:
color = "yellow"
limit1 = 11
limit2 = 34 # 有的图片有色偏偏绿
elif green * 2 >= card_img_count:
color = "green"
limit1 = 35
limit2 = 99
elif blue * 2 >= card_img_count:
color = "blue"
limit1 = 100
limit2 = 124 # 有的图片有色偏偏紫
elif black + white >= card_img_count * 0.7:
color = "bw"
# print(color)
colors.append(color)
# print(blue, green, yellow, black, white, card_img_count)
if limit1 == 0:
continue
# 根据车牌颜色再定位,缩小边缘非车牌边界
xl, xr, yh, yl = self.accurate_place(card_img_hsv, limit1, limit2, color)
if yl == yh and xl == xr:
continue
need_accurate = False
if yl >= yh:
yl = 0
yh = row_num
need_accurate = True
if xl >= xr:
xl = 0
xr = col_num
need_accurate = True
card_imgs[card_index] = card_img[yl:yh, xl:xr] \
if color != "green" or yl < (yh - yl) // 4 else card_img[yl - (yh - yl) // 4:yh, xl:xr]
if need_accurate: # 可能x或y方向未缩小,需要再试一次
card_img = card_imgs[card_index]
card_img_hsv = cv2.cvtColor(card_img, cv2.COLOR_BGR2HSV)
xl, xr, yh, yl = self.accurate_place(card_img_hsv, limit1, limit2, color)
if yl == yh and xl == xr:
continue
if yl >= yh:
yl = 0
yh = row_num
if xl >= xr:
xl = 0
xr = col_num
card_imgs[card_index] = card_img[yl:yh, xl:xr] \
if color != "green" or yl < (yh - yl) // 4 else card_img[yl - (yh - yl) // 4:yh, xl:xr]
# cv2.imshow("result", card_imgs[0])
# cv2.imwrite('1.jpg', card_imgs[0])
# print('颜色识别结果:' + colors[0])
return card_imgs, colors
PlateRecognition_example = PlateRecognition()
class Ui_MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.RowLength = 0
self.Data = [['文件名称', '录入时间', '车牌号码', '车牌类型', '车牌信息']]
# self.setupUi(MainWindow())
self.cardtype = json.loads('{"blue": "蓝色牌照", "green": "绿色牌照", "yellow": "黄色牌照"}')
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1213, 670)
MainWindow.setFixedSize(1213, 670) # 设置窗体固定大小
MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setGeometry(QtCore.QRect(690, 40, 511, 460))
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 500, 489))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.label_0 = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.label_0.setGeometry(QtCore.QRect(10, 10, 111, 20))
font = QtGui.QFont()
font.setPointSize(11)
self.label_0.setFont(font)
self.label_0.setObjectName("label_0")
self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.label.setGeometry(QtCore.QRect(10, 40, 481, 420))
self.label.setObjectName("label")
self.label.setAlignment(Qt.AlignCenter)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.scrollArea_2 = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea_2.setGeometry(QtCore.QRect(10, 10, 671, 631))
self.scrollArea_2.setWidgetResizable(True)
self.scrollArea_2.setObjectName("scrollArea_2")
self.scrollAreaWidgetContents_1 = QtWidgets.QWidget()
self.scrollAreaWidgetContents_1.setGeometry(QtCore.QRect(0, 0, 669, 629))
self.scrollAreaWidgetContents_1.setObjectName("scrollAreaWidgetContents_1")
self.label_1 = QtWidgets.QLabel(self.scrollAreaWidgetContents_1)
self.label_1.setGeometry(QtCore.QRect(10, 10, 111, 20))
font = QtGui.QFont()
font.setPointSize(11)
self.label_1.setFont(font)
self.label_1.setObjectName("label_1")
self.tableWidget = QtWidgets.QTableWidget(self.scrollAreaWidgetContents_1)
self.tableWidget.setGeometry(QtCore.QRect(10, 40, 651, 581)) # 581))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(5)
self.tableWidget.setColumnWidth(0, 140) # 设置1列的宽度
self.tableWidget.setColumnWidth(1, 130) # 设置2列的宽度
self.tableWidget.setColumnWidth(2, 110) # 设置3列的宽度
self.tableWidget.setColumnWidth(3, 90) # 设置4列的宽度
self.tableWidget.setColumnWidth(4, 181) # 设置5列的宽度
self.tableWidget.setHorizontalHeaderLabels(["图片名称", "录入时间", "车牌号码", "车牌类型", "车牌信息"])
self.tableWidget.setRowCount(self.RowLength)
self.tableWidget.verticalHeader().setVisible(False) # 隐藏垂直表头)
b = '''
color:white;
background:#2B2B2B;
'''
# self.tableWidget.setStyleSheet(b)
# self.tableWidget.setAlternatingRowColors(True)
self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.tableWidget.raise_()
self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_1)
self.scrollArea_3 = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea_3.setGeometry(QtCore.QRect(690, 510, 341, 131))
self.scrollArea_3.setWidgetResizable(True)
self.scrollArea_3.setObjectName("scrollArea_3")
self.scrollAreaWidgetContents_3 = QtWidgets.QWidget()
self.scrollAreaWidgetContents_3.setGeometry(QtCore.QRect(0, 0, 339, 129))
self.scrollAreaWidgetContents_3.setObjectName("scrollAreaWidgetContents_3")
self.label_2 = QtWidgets.QLabel(self.scrollAreaWidgetContents_3)
self.label_2.setGeometry(QtCore.QRect(10, 10, 111, 20))
font = QtGui.QFont()
font.setPointSize(11)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.label_3 = QtWidgets.QLabel(self.scrollAreaWidgetContents_3)
self.label_3.setGeometry(QtCore.QRect(10, 40, 321, 81))
self.label_3.setObjectName("label_3")
self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3)
self.scrollArea_4 = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea_4.setGeometry(QtCore.QRect(1040, 510, 161, 131))
self.scrollArea_4.setWidgetResizable(True)
self.scrollArea_4.setObjectName("scrollArea_4")
self.scrollAreaWidgetContents_4 = QtWidgets.QWidget()
self.scrollAreaWidgetContents_4.setGeometry(QtCore.QRect(0, 0, 159, 129))
self.scrollAreaWidgetContents_4.setObjectName("scrollAreaWidgetContents_4")
self.pushButton_2 = QtWidgets.QPushButton(self.scrollAreaWidgetContents_4)
self.pushButton_2.setGeometry(QtCore.QRect(20, 50, 121, 31))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton = QtWidgets.QPushButton(self.scrollAreaWidgetContents_4)
self.pushButton.setGeometry(QtCore.QRect(20, 90, 121, 31))
self.pushButton.setObjectName("pushButton")
self.label_4 = QtWidgets.QLabel(self.scrollAreaWidgetContents_4)
self.label_4.setGeometry(QtCore.QRect(10, 10, 111, 20))
font = QtGui.QFont()
font.setPointSize(11)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.scrollArea_4.setWidget(self.scrollAreaWidgetContents_4)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton.clicked.connect(self.__openimage) # 设置点击事件
self.pushButton.setStyleSheet('''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#2B2B2B;}''')
self.pushButton_2.clicked.connect(self.__writeFiles) # 设置点击事件
self.pushButton_2.setStyleSheet('''QPushButton{background:#222225;border-radius:5px;}QPushButton:hover{background:#2B2B2B;}''')
self.retranslateUi(MainWindow)
self.close_widget = QtWidgets.QWidget(self.centralwidget)
self.close_widget.setGeometry(QtCore.QRect(1130, 0, 90, 50))
self.close_widget.setObjectName("close_widget")
self.close_layout = QGridLayout() # 创建左侧部件的网格布局层
self.close_widget.setLayout(self.close_layout) # 设置左侧部件布局为网格
self.left_close = QPushButton("") # 关闭按钮
self.left_close.clicked.connect(self.close)
self.left_visit = QPushButton("") # 空白按钮
self.left_visit.clicked.connect(MainWindow.big)
self.left_mini = QPushButton("") # 最小化按钮
self.left_mini.clicked.connect(MainWindow.mini)
self.close_layout.addWidget(self.left_mini, 0, 0, 1, 1)
self.close_layout.addWidget(self.left_close, 0, 2, 1, 1)
self.close_layout.addWidget(self.left_visit, 0, 1, 1, 1)
self.left_close.setFixedSize(15, 15) # 设置关闭按钮的大小
self.left_visit.setFixedSize(15, 15) # 设置按钮大小
self.left_mini.setFixedSize(15, 15) # 设置最小化按钮大小
self.left_close.setStyleSheet(
'''QPushButton{background:#F76677;border-radius:5px;}QPushButton:hover{background:red;}''')
self.left_visit.setStyleSheet(
'''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:yellow;}''')
self.left_mini.setStyleSheet(
'''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''')
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.ProjectPath = os.getcwd() # 获取当前工程文件位置
self.centralwidget.setStyleSheet('''
QWidget#centralwidget{
color:white;
background:#222225;
border-top:1px solid #222225;
border-bottom:1px solid #222225;
border-right:1px solid #222225;
border-left:1px solid #444444;
border-top-left-radius:10px;
border-top-right-radius:10px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
}
''')
sc = '''
QWidget{
color:white;
background:#2B2B2B;
border-top:1px solid #222225;
border-bottom:1px solid #222225;
border-right:1px solid #222225;
border-left:1px solid #444444;
border-top-left-radius:10px;
border-top-right-radius:10px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
}
'''
self.scrollAreaWidgetContents_1.setStyleSheet('''
QWidget{
color:black;
background:#2B2B2B;
border-top:1px solid #222225;
border-bottom:1px solid #222225;
border-right:1px solid #222225;
border-left:1px solid #444444;
border-top-left-radius:10px;
border-top-right-radius:10px;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
}
QListWidget{background-color:#2B2B2B;color:#222225}
/*垂直滚动条*/
QScrollBar:vertical{
width:12px;
border:1px solid #2B2B2B;
margin:0px,0px,0px,0px;
padding-top:0px;
padding-bottom:0px;
}
QScrollBar::handle:vertical{
width:3px;
background:#4B4B4B;
min-height:3;
}
QScrollBar::handle:vertical:hover{
background:#3F3F3F;
border:0px #3F3F3F;
}
QScrollBar::sub-line:vertical{
width:0px;
border-image:url(:/Res/scroll_left.png);
subcontrol-position:left;
}
QScrollBar::sub-line:vertical:hover{
height:0px;
background:#222225;
subcontrol-position:top;
}
QScrollBar::add-line:vertical{
height:0px;
border-image:url(:/Res/scroll_down.png);
subcontrol-position:bottom;
}
QScrollBar::add-line:vertical:hover{
height:0px;
background:#3F3F3F;
subcontrol-position:bottom;
}
QScrollBar::add-page:vertical{
background:#2B2B2B;
}
QScrollBar::sub-page:vertical{
background:#2B2B2B;
}
QScrollBar::up-arrow:vertical{
border-style:outset;
border-width:0px;
}
QScrollBar::down-arrow:vertical{
border-style:outset;
border-width:0px;
}
QScrollBar:horizontal{
height:12px;
border:1px #2B2B2B;
margin:0px,0px,0px,0px;
padding-left:0px;
padding-right:0px;
}
QScrollBar::handle:horizontal{
height:16px;
background:#4B4B4B;
min-width:20;
}
QScrollBar::handle:horizontal:hover{
background:#3F3F3F;
border:0px #3F3F3F;
}
QScrollBar::sub-line:horizontal{
width:0px;
border-image:url(:/Res/scroll_left.png);
subcontrol-position:left;
}
QScrollBar::sub-line:horizontal:hover{
width:0px;
background:#2B2B2B;
subcontrol-position:left;
}
QScrollBar::add-line:horizontal{
width:0px;
border-image:url(:/Res/scroll_right.png);
subcontrol-position:right;
}
QScrollBar::add-line:horizontal:hover{
width:0px;
background::#2B2B2B;
subcontrol-position:right;
}
QScrollBar::add-page:horizontal{
background:#2B2B2B;
}
QScrollBar::sub-page:horizontal{
background:#2B2B2B;
}
''')
self.scrollAreaWidgetContents.setStyleSheet(sc)
self.scrollAreaWidgetContents_3.setStyleSheet(sc)
self.scrollAreaWidgetContents_4.setStyleSheet(sc)
b = '''
color:white;
background:#2B2B2B;
'''
self.label_0.setStyleSheet(b)
self.label_1.setStyleSheet(b)
self.label_2.setStyleSheet(b)
self.label_3.setStyleSheet(b)
MainWindow.setWindowOpacity(0.95) # 设置窗口透明度
MainWindow.setAttribute(Qt.WA_TranslucentBackground)
MainWindow.setWindowFlag(Qt.FramelessWindowHint) # 隐藏边框
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "车牌识别系统"))
self.label_0.setText(_translate("MainWindow", "原始图片:"))
self.label.setText(_translate("MainWindow", ""))
self.label_1.setText(_translate("MainWindow", "识别结果:"))
self.label_2.setText(_translate("MainWindow", "车牌区域:"))
self.label_3.setText(_translate("MainWindow", ""))
self.pushButton.setText(_translate("MainWindow", "打开文件"))
self.pushButton_2.setText(_translate("MainWindow", "导出数据"))
self.label_4.setText(_translate("MainWindow", "事件:"))
self.scrollAreaWidgetContents_1.show()
# 识别
def __vlpr(self, path):
# image = cv2.imread(path)
result = {}
image = cv2.imdecode(np.fromfile(path, dtype=np.uint8), cv2.IMREAD_COLOR)
resu = catcher(image)
# [['京QF60F0', 0.99931663, 0, [137, 120, 319, 177]]]
print(resu)
# fontC = ImageFont.truetype("./platech.ttf", 14, 0)
fontC = ImageFont.truetype("simsun.ttc", 14, 0)
res, confi, box = resu[0][0], resu[0][1], resu[0][3]
# 获取地域省份信息
# license_result = response.json()['words_result']['number']
# result['From'] = ''.join(self.Prefecture[license_result[0]][license_result[1]])
image = drawRectBox(image, box, res, fontC)
# cv.imshow('Stream', image)
# c = cv.waitKey(0)
# PR = PlateRecognition()
# result = PR.get_license_plate(path) # lonlon
card_imgs, colors = PlateRecognition_example.pretreatment(path)
if len(colors) == 0:
result['InputTime'] = time.strftime("%Y-%m-%d %H:%M:%S")
result['Type'] = "蓝色牌照"
result['Picture'] = image
result['Number'] = res
result['From'] = '未知'
else:
result['InputTime'] = time.strftime("%Y-%m-%d %H:%M:%S")
result['Type'] = self.cardtype[colors[0]]
result['Picture'] = card_imgs[0]
result['Number'] = res
result['From'] = '未知'
return result
def __show(self, result, FileName):
# 显示表格
self.RowLength = self.RowLength + 1
if self.RowLength > 18:
self.tableWidget.setColumnWidth(5, 157)
self.tableWidget.setRowCount(self.RowLength)
self.tableWidget.setItem(self.RowLength - 1, 0, QTableWidgetItem(FileName))
self.tableWidget.setItem(self.RowLength - 1, 1, QTableWidgetItem(result['InputTime']))
self.tableWidget.setItem(self.RowLength - 1, 2, QTableWidgetItem(result['Number']))
self.tableWidget.setItem(self.RowLength - 1, 3, QTableWidgetItem(result['Type']))
if result['Type'] == '蓝色牌照':
self.tableWidget.item(self.RowLength - 1, 3).setBackground(QBrush(QColor(3, 128, 255)))
elif result['Type'] == '绿色牌照':
self.tableWidget.item(self.RowLength - 1, 3).setBackground(QBrush(QColor(98, 198, 148)))
elif result['Type'] == '黄色牌照':
self.tableWidget.item(self.RowLength - 1, 3).setBackground(QBrush(QColor(242, 202, 9)))
self.tableWidget.setItem(self.RowLength - 1, 4, QTableWidgetItem(result['From']))
self.tableWidget.item(self.RowLength - 1, 0).setBackground(QBrush(QColor(255, 255, 255)))
self.tableWidget.item(self.RowLength - 1, 1).setBackground(QBrush(QColor(255, 255, 255)))
self.tableWidget.item(self.RowLength - 1, 2).setBackground(QBrush(QColor(255, 255, 255)))
self.tableWidget.item(self.RowLength - 1, 4).setBackground(QBrush(QColor(255, 255, 255)))
# 显示识别到的车牌位置
size = (int(self.label_3.width()), int(self.label_3.height()))
shrink = cv2.resize(result['Picture'], size, interpolation=cv2.INTER_AREA)
shrink = cv2.cvtColor(shrink, cv2.COLOR_BGR2RGB)
self.QtImg = QtGui.QImage(shrink[:], shrink.shape[1], shrink.shape[0], shrink.shape[1] * 3,
QtGui.QImage.Format_RGB888)
self.label_3.setPixmap(QtGui.QPixmap.fromImage(self.QtImg))
def __writexls(self, DATA, path):
try:
wb = xlwt.Workbook();
ws = wb.add_sheet('Data');
# DATA.insert(0, ['文件名称','录入时间', '车牌号码', '车牌类型', '车牌信息'])
for i, Data in enumerate(DATA):
for j, data in enumerate(Data):
ws.write(i, j, data)
wb.save(path)
QMessageBox.information(None, "成功", "数据已保存!", QMessageBox.Yes)
except:
QMessageBox.information(None, "失败", "数据保存失败!可能因为保存的文件已经被打开", QMessageBox.Yes)
def __writecsv(self, DATA, path):
try:
f = open(path, 'w')
# DATA.insert(0, ['文件名称','录入时间', '车牌号码', '车牌类型', '车牌信息'])
for data in DATA:
f.write((',').join(data) + '\n')
f.close()
QMessageBox.information(None, "成功", "数据已保存!", QMessageBox.Yes)
except:
QMessageBox.information(None, "失败", "数据保存失败!可能因为保存的文件已经被打开", QMessageBox.Yes)
def __writeFiles(self):
path, filetype = QFileDialog.getSaveFileName(None, "另存为", self.ProjectPath,
"Excel 工作簿(*.xls);;CSV (逗号分隔)(*.csv)")
if path == "": # 未选择
return
if filetype == 'Excel 工作簿(*.xls)':
self.__writexls(self.Data, path)
elif filetype == 'CSV (逗号分隔)(*.csv)':
self.__writecsv(self.Data, path)
def __openimage(self):
path, filetype = QFileDialog.getOpenFileName(None, "选择文件", self.ProjectPath,
"JPEG Image (*.jpg);;PNG Image (*.png);;JFIF Image (*.jfif)") # ;;All Files (*)
if path == "": # 未选择文件
return
print('path',path)
filename = path.split('/')[-1]
# 尺寸适配
size = cv2.imdecode(np.fromfile(path, dtype=np.uint8), cv2.IMREAD_COLOR).shape
if size[0] / size[1] > 1.0907:
w = int(size[1] * self.label.height() / size[0])
h = self.label.height()
jpg = QtGui.QPixmap(path).scaled(w, h)
elif size[0] / size[1] < 1.0907:
w = self.label.width()
h = int((size[0] * self.label.width()) / size[1])
jpg = QtGui.QPixmap(path).scaled(w, h)
else:
jpg = QtGui.QPixmap(path).scaled(self.label.width(), self.label.height())
self.label.setPixmap(jpg)
result = self.__vlpr(path)
if result is not None:
self.Data.append(
[filename, result['InputTime'], result['Number'], result['Type'],
result['From']])
self.__show(result, filename)
else:
QMessageBox.warning(None, "Error", "无法识别此图像!", QMessageBox.Yes)
def close(self):
reply = QtWidgets.QMessageBox.question(self, '提示',
"是否要退出程序?\n提示:退出后将丢失所有识别数据",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
sys.exit()
else:
pass
# 重写MainWindow类
class MainWindow(QtWidgets.QMainWindow):
def closeEvent(self, event):
reply = QtWidgets.QMessageBox.question(self, '提示',
"是否要退出程序?\n提示:退出后将丢失所有识别数据",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
event.accept()
else:
event.ignore()
def mousePressEvent(self, event):
global big
big = False
self.setWindowState(Qt.WindowNoState)
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
def mouseMoveEvent(self, QMouseEvent):
global big
big = False
self.setWindowState(Qt.WindowNoState)
self.move(QMouseEvent.globalPos() - self.m_Position) # 更改窗口位置
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
global big
big = False
self.setWindowState(Qt.WindowNoState)
self.m_flag = False
def mousePressEvent(self, event):
global big
big = False
self.setWindowState(Qt.WindowNoState)
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
def mouseMoveEvent(self, QMouseEvent):
global big
big = False
self.setWindowState(Qt.WindowNoState)
self.move(QMouseEvent.globalPos() - self.m_Position) # 更改窗口位置
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
global big
big = False
self.setWindowState(Qt.WindowNoState)
self.m_flag = False
def big(self):
global big
print('最大化:{}'.format(big))
if not big:
self.setWindowState(Qt.WindowMaximized)
big = True
elif big:
self.setWindowState(Qt.WindowNoState)
big = False
def mini(self):
self.showMinimized()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = MainWindow() # QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())