python實現小區車牌識別計費程序

示例簡介

python利用百度文字識別功能,實現小區車輛進出識別,並顯示進出信息和收費信息;可查看停車信息,也可查看歷史數據;

開發環境:Windows7+python3.7+pycharm2018.2.4(開發工具);

目錄機構:

最終效果:由於涉及隱私,不上傳動態效果;左邊爲攝像頭的畫面(這裏是視頻播放頁面),右上角顯示車位情況和最近十條車輛信息,右下角顯示識別信息、收費信息或提示信息;

百度端創建應用

創建過程參考《微信小程序利用百度AI實現掃描身份證獲取信息功能》(把“圖像識別”換爲“文字識別”)。

實現過程

1. 文件“settings.py”用來設置該程序的基礎信息;

class Settings():
    def __init__(self):
        """ 初始化設置 """
        # 屏幕設置(寬、高、背景色、線顏色)
        self.screen_width = 1000
        self.screen_height = 484
        self.bg_color = (255, 255, 255)

        # 停車位
        self.total = 100

        # 識別顏色、車牌號、進來時間、出入場信息
        self.ocr_color = (212, 35, 122)
        self.carnumber = ''
        self.comeInTime = ''
        self.message = ''

2. 文件“timeutil.py”有兩個函數:

函數time_cmp主要用來比較出場時間跟卡有效期,判斷業主是否需要收費;

函數priceCalc用來計算停車時間,裏面存在兩種情況,一種是外來車,只需要比較出入場時間差;另一種是業主車,入場時,卡未到期,但出場已經到期,所以需要比較卡有效期和出場時間的差值;

Tips:由於讀取Excel的卡有效期字段,會多“.xxxx”這部分,所以需要經過split('.')處理。

import datetime
import math

# 計算兩個日期大小
def time_cmp(first_time, second_time):
    # 由於有效期獲取後會有小數數據
    firstTime = datetime.datetime.strptime(str(first_time).split('.')[0], "%Y-%m-%d %H:%M:%S")
    secondTime = datetime.datetime.strptime(str(second_time), "%Y-%m-%d %H:%M")
    number = 1 if firstTime > secondTime else 0
    return number

# 計算停車時間
def priceCalc(inDate, outDate):
    if '.' in str(inDate):
        inDate = str(inDate).split('.')[0]
        inDate = datetime.datetime.strptime(inDate, "%Y-%m-%d %H:%M:%S")
        print('特殊處理')
    else:
        inDate = datetime.datetime.strptime(inDate, "%Y-%m-%d %H:%M")
    outDate = datetime.datetime.strptime(str(outDate), "%Y-%m-%d %H:%M")
    rtn = outDate - inDate
    # 計算停車多少小時(往上取整)
    y = math.ceil(rtn.total_seconds() / 60 / 60)
    return y

3. 文件“button.py”用來繪製按鈕,這裏用來繪製“識別”按鈕;

import pygame.font
class Button():
	def __init__(self, screen, msg):
		"""初始化按鈕的屬性"""
		self.screen = screen
		self.screen_rect = screen.get_rect()
		# 設置按鈕的尺寸和其他屬性
		self.width, self.height = 100, 50
		self.button_color = (0, 120, 215)
		self.text_color = (255, 255, 255)
		self.font = pygame.font.SysFont('SimHei', 25)
		# 創建按鈕的rect對象,並使其居中
		self.rect = pygame.Rect(0, 0, self.width, self.height)
		# 創建按鈕的rect對象,並設置按鈕中心位置
		self.rect.centerx = 640 - self.width / 2 + 2
		self.rect.centery = 480 - self.height / 2 + 2
		# 按鈕的標籤只需創建一次
		self.prep_msg(msg)
	def prep_msg(self, msg):
		"""將msg渲染爲圖像,並使其在按鈕上居中"""
		self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
		self.msg_image_rect = self.msg_image.get_rect()
		self.msg_image_rect.center = self.rect.center
	def draw_button(self):
		# 繪製一個用顏色填充的按鈕,再繪製文本
		self.screen.fill(self.button_color, self.rect)
		self.screen.blit(self.msg_image, self.msg_image_rect)

4. 文件“textboard.py”用來繪製背景和文字;

import pygame.font
# 線顏色
line_color = (0, 0, 0)
# 顯示文字信息時使用的字體設置
text_color = (0, 0, 0)


def draw_bg(screen):
    # 背景文圖案
    bgfont = pygame.font.SysFont('SimHei', 15)
    # 繪製橫線
    pygame.draw.aaline(screen, line_color, (662, 30), (980, 30), 1)
    # 渲染爲圖片
    text_image = bgfont.render('識別信息:', True, text_color)
    # 獲取文字圖像位置
    text_rect = text_image.get_rect()
    # 設置文字圖像中心點
    text_rect.left = 660
    text_rect.top = 370
    # 繪製內容
    screen.blit(text_image, text_rect)


# 繪製文字(text-文字內容、xpos-x座標、ypos-y座標、fontSize-字體大小)
def draw_text(screen, text, xpos, ypos, fontsize, tc=text_color):
    # 使用系統字體
    xtfont = pygame.font.SysFont('SimHei', fontsize)
    text_image = xtfont.render(text, True, tc)
    # 獲取文字圖像位置
    text_rect = text_image.get_rect()
    # 設置文字圖像中心點
    text_rect.left = xpos
    text_rect.top = ypos
    # 繪製內容
    screen.blit(text_image, text_rect)

5. 文件“ocrutil.py”用來調用百度文字識別SDK,獲取圖片中的車牌信息;

Tips:文件“test.jpg”爲從攝像頭讀取的圖片,每次循環獲取一次,這裏爲了測試方便使用視頻;

from aip import AipOcr
import os

# 百度識別車牌
# 申請地址 https://login.bce.baidu.com/
filename = 'file/key.txt'  # 記錄申請的Key的文件位置
if os.path.exists(filename):  # 判斷文件是否存在
    with open(filename, "r") as file:  # 打開文件
        dictkey = eval(file.readlines()[0])  # 讀取全部內容轉換爲字典
        # 以下獲取的三個Key是進入百度AI開放平臺的控制檯的應用列表裏創建應用得來的
        APP_ID = dictkey['APP_ID']  # 獲取申請的APIID
        API_KEY = dictkey['API_KEY']  # 獲取申請的APIKEY
        SECRET_KEY = dictkey['SECRET_KEY']  # 獲取申請的SECRETKEY
else:
    print("請先在file目錄下創建key.txt,並且寫入申請的Key!格式如下:"
          "\n{'APP_ID':'申請的APIID', 'API_KEY':'申請的APIKEY', 'SECRET_KEY':'申請的SECRETKEY'}")
# 初始化AipOcr對象
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)


# 讀取文件
def get_file_content(filePath):
    with open(filePath, 'rb') as fp:
        return fp.read()


# 根據圖片返回車牌號
def getcn():
    # 讀取圖片
    image = get_file_content('images/test.jpg')
    # 調用車牌識別
    results = client.licensePlate(image)['words_result']['number']
    # 輸出車牌號
    return results

6. 文件“procedure_functions.py”存放跟程序相關的業務邏輯函數;

裏面比較複雜的就是點擊“識別”按鈕後的邏輯處理(event.type == pygame.MOUSEBUTTONDOWN):

1)當停車場未有停車時,只需要識別後,把車輛信息存入“停車場車輛表”並把相關信息顯示到界面右下角;

2)當停車場已有停車時,會出現兩種情況,一種是入場,一種是出場:

    入場需判斷是否停車場已滿,已滿則不給進入並顯示提示信息;未滿則把車輛信息存入“停車場車輛表”並把相關信息顯示到界面右下角;

    出場分業主有效、業主過期、外來車三種情況收費,並刪除車輛表相應的車輛信息,並把車輛信息和收費信息等存入“停車場歷史表”(可用於後面數據的彙總統計);

import sys
import pygame
import time
import pandas as pd
import ocrutil
import timeutil


# 事件
def check_events(settings, recognition_button, ownerInfo_table, carInfo_table, history_table, path):
    """ 響應按鍵和鼠標事件 """
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            button_clicked = recognition_button.rect.collidepoint(mouse_x, mouse_y)
            if button_clicked:
                try:
                    # 獲取車牌
                    carnumber = ocrutil.getcn()

                    # 轉換當前時間 2018-12-11 16:18
                    localtime = time.strftime('%Y-%m-%d %H:%M', time.localtime())
                    settings.carnumber = '車牌號碼:' + carnumber

                    # 判斷進入車輛是否業主車輛
                    # 獲取業主車輛信息(只顯示卡未過期)
                    ownerInfo_table = ownerInfo_table[ownerInfo_table['validityDate'] > localtime]
                    owner_carnumbers = ownerInfo_table[['carnumber', 'validityDate']].values
                    carnumbers = ownerInfo_table['carnumber'].values
                    # 獲取車輛表信息
                    carInfo_carnumbers = carInfo_table[['carnumber', 'inDate', 'isOwner', 'validityDate']].values
                    cars = carInfo_table['carnumber'].values
                    # 增加車輛信息
                    append_carInfo = {
                        'carnumber': carnumber
                    }
                    # 增加歷史信息
                    append_history = {
                        'carnumber': carnumber
                    }
                    carInfo_length = len(carInfo_carnumbers)
                    # 車輛表未有數據
                    if carInfo_length == 0:
                        print('未有車輛數據入場')
                        in_park(owner_carnumbers, carnumbers, carInfo_table, append_carInfo, carnumber, localtime, settings, path)
                    # 車輛表有數據
                    else:
                        if carnumber in cars:
                            # 出停車場
                            i = 0
                            for carInfo_carnumber in carInfo_carnumbers:
                                if carnumber == carInfo_carnumber[0]:
                                    if carInfo_carnumber[2] == 1:
                                        if timeutil.time_cmp(carInfo_carnumber[3], localtime):
                                            print('業主車,自動擡槓')
                                            msgMessage = '業主車,可出停車場'
                                            parkPrice = '業主卡'
                                        else:
                                            print('業主車,但卡已過期,收費擡槓')
                                            # 比較卡有效期時間
                                            price = timeutil.priceCalc(carInfo_carnumber[3], localtime)
                                            msgMessage = '停車費用:' + str(5 * int(price)) + '(提醒業主,卡已到期)'
                                            parkPrice =  5 * int(price)

                                    else:
                                        print('外來車,收費擡槓')
                                        # 比較入場時間
                                        price = timeutil.priceCalc(carInfo_carnumber[1], localtime)
                                        msgMessage = '停車費用:' + str(5 * price)
                                        parkPrice = 5 * int(price)

                                    print(i)
                                    carInfo_table = carInfo_table.drop([i])
                                    # 增加數據到歷史表
                                    append_history['inDate'] = carInfo_carnumber[1]
                                    append_history['outData'] = localtime
                                    append_history['price'] = parkPrice
                                    append_history['isOwner'] = carInfo_carnumber[2]
                                    append_history['validityDate'] = carInfo_carnumber[3]
                                    history_table = history_table.append(append_history, ignore_index=True)

                                    settings.comeInTime = '出場時間:' + localtime
                                    settings.message = msgMessage

                                    # 更新車輛表和歷史表
                                    pd.DataFrame(carInfo_table).to_excel(path + '停車場車輛表' + '.xlsx', sheet_name='data',
                                                                         index=False, header=True)
                                    pd.DataFrame(history_table).to_excel(path + '停車場歷史表' + '.xlsx', sheet_name='data',
                                                                         index=False, header=True)
                                    break
                                i += 1
                        else:
                            # 入停車場
                            print('有車輛表數據入場')
                            if carInfo_length < settings.total:
                                in_park(owner_carnumbers, carnumbers, carInfo_table, append_carInfo, carnumber, localtime, settings, path)
                            else:
                                print('停車場已滿')
                                settings.comeInTime = '進場時間:' + localtime
                                settings.message = '停車場已滿,無法進入'
                except Exception as e:
                    print("錯誤原因:", e)
                    continue
                pass


# 車輛入停車場
def in_park(owner_carnumbers, carnumbers, carInfo_table, append_carInfo, carnumber, localtime, settings, path):
    if carnumber in carnumbers:
        for owner_carnumber in owner_carnumbers:
            if carnumber == owner_carnumber[0]:
                print('業主車,自動擡槓')
                msgMessage = '提示信息:業主車,可入停車場'
                append_carInfo['isOwner'] = 1
                append_carInfo['validityDate'] = owner_carnumber[1]
                # 退出循環
                break
    else:
        print('外來車,識別擡槓')
        msgMessage = '提示信息:外來車,可入停車場'
        append_carInfo['isOwner'] = 0
    append_carInfo['inDate'] = localtime
    settings.comeInTime = '進場時間:' + localtime
    settings.message = msgMessage
    # 添加信息到車輛表
    carInfo_table = carInfo_table.append(append_carInfo, ignore_index=True)
    # 更新車輛表
    pd.DataFrame(carInfo_table).to_excel(path + '停車場車輛表' + '.xlsx', sheet_name='data',
                                         index=False, header=True)

7. 文件“main.py”爲程序的主函數,用來初始化程序,並同步更新程序的信息。

import pygame
import cv2
import os
import pandas as pd
# 引入自定義模塊
from settings import Settings
from button import Button
import textboard
import procedure_functions as pf

def run_procedure():
    # 獲取文件的路徑
    cdir = os.getcwd()
    # 文件夾路徑
    path = cdir + '/file/'
    # 讀取路徑
    if not os.path.exists(path + '停車場車輛表' + '.xlsx'):
        # 車牌號 進入時間 離開時間 價格 是否業主
        carnfile = pd.DataFrame(columns=['carnumber', 'inDate', 'outData', 'price', 'isOwner', 'validityDate'])
        # 生成xlsx文件
        carnfile.to_excel(path + '停車場車輛表' + '.xlsx', sheet_name='data')
        carnfile.to_excel(path + '停車場歷史表' + '.xlsx', sheet_name='data')

    settings = Settings()
    # 初始化並創建一個屏幕對象
    pygame.init()
    pygame.display.set_caption('智能小區車牌識別系統')
    ic_launcher = pygame.image.load('images/icon_launcher.png')
    pygame.display.set_icon(ic_launcher)
    screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))

    try:
        # cam = cv2.VideoCapture(0) # 開啓攝像頭
        cam = cv2.VideoCapture('file/test.mp4')
    except:
        print('請連接攝像頭')
    # 循環幀率設置
    clock = pygame.time.Clock()
    running = True
    # 開始主循環
    while running:
        screen.fill(settings.bg_color)
        # 從攝像頭讀取圖片
        sucess, img = cam.read()
        # 保存圖片,並退出。
        if sucess:
            cv2.imwrite('images/test.jpg', img)
        else:
            # 識別不到圖片或者設備停止,則退出系統
            running = False
        # 加載圖像
        image = pygame.image.load('images/test.jpg')
        # 設置圖片大小
        image = pygame.transform.scale(image, (640, 480))
        # 繪製視頻畫面
        screen.blit(image, (2, 2))

        # 創建識別按鈕
        recognition_button = Button(screen, '識別')
        recognition_button.draw_button()
        # 讀取文件內容
        ownerInfo_table = pd.read_excel(path + '住戶車輛表.xlsx', sheet_name='data')
        carInfo_table = pd.read_excel(path + '停車場車輛表.xlsx', sheet_name='data')
        history_table = pd.read_excel(path + '停車場歷史表.xlsx', sheet_name='data')
        inNumber = len(carInfo_table['carnumber'].values)
        # 繪製背景
        textboard.draw_bg(screen)
        # 繪製信息標題
        textboard.draw_text(screen, '共有車位:' + str(settings.total) + '  剩餘車位:' + str(settings.total - inNumber), 680, 0, 20)
        # 繪製信息表頭
        textboard.draw_text(screen, ' 車牌號          進入時間', 700, 40, 15)
        # 繪製停車場車輛前十條信息
        carInfos = carInfo_table.sort_values(by='inDate', ascending=False)
        i = 0
        for carInfo in carInfos.values:
            if i >= 10:
                break
            i += 1
            textboard.draw_text(screen, str(carInfo[1])+'     '+str(carInfo[2]), 700, 40 + i * 30, 15)
        # 繪製識別信息
        textboard.draw_text(screen, settings.carnumber, 660, 400, 15, settings.ocr_color)
        textboard.draw_text(screen, settings.comeInTime, 660, 422, 15, settings.ocr_color)
        textboard.draw_text(screen, settings.message, 660, 442, 15, settings.ocr_color)

        """ 響應鼠標事件 """
        pf.check_events(settings, recognition_button, ownerInfo_table, carInfo_table, history_table, path)
        pygame.display.flip()
        # 控制遊戲最大幀率爲 60
        clock.tick(60)
    # 關閉攝像頭
    cam.release()
run_procedure()

 

                                                                             掃描公衆號,瞭解更多實例分享

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章