2022.7.28 차량,번호판 오브젝트 디텍션 프로젝트 9일차

정성우·2022년 7월 28일
0

학습내용
flask를 이용해 웹으로 결과를 제공하는 코드에 주차요금 계산하는 코드를 추가

from flask import Flask, render_template, request, url_for
import sqlite3
import os
from pandas import NA
import torch
import torchvision.transforms as transforms
from PIL import Image, ImageFilter
from pathlib import Path
import sys
import cv2
import io
import string
import re
from time import time

from zmq import NULL
import ocr
app = Flask(__name__)
device = "cuda" if torch.cuda.is_available() else "cpu"

# 기본 템플릿
def template(content):
    return f'''
    <html>
    <head><link rel="stylesheet" href="{ url_for('static', filename='css/style.css') }"></head>
    <body>
        <div class="grid-container">
            <div class="header">
            	<h1><a href="/">Detection Web</a></h1>
            </div>
            <div class="left">
                <a href="/detection/"><h3>Detection</h3></a>
                <a href="/userList/"><h3>사용자 관리</h3></a>
            </div>
            {content}
        </div>
    </body>
    </html>
    '''

# OCR 
def solution(filename):
    ocr_result = ocr.azure_ocr(filename)
    
    if re.match("(\d{2,3}\D\d{4})", ocr_result) == None:
        name = '인식오류'
    else:
        conn = sqlite3.connect('users.sqlite3')
        cursor = conn.cursor()
        cursor.execute('SELECT * FROM users WHERE carNumber=?', (ocr_result, ))
        user = cursor.fetchone()
        conn.close()
        if user != None:
            name = user[1]
            #user[1]이 이름 user[2]가 차량번호
        else:
            name = "미등록"
    
    return name, ocr_result


@app.route('/detection/')
def detection(filename=None, name=None, carNumber=None):
    return template(render_template('./detection.html'))


# 사진 업로드 눌렀을 때
@app.route('/upload', methods = ['POST'])
def upload():
    # File load
    if "file" not in request.files:
        return redirect(request.url)

    file = request.files["file"]
    if not file:
        return 
    # Set image from file
    img_bytes = file.read()
    img = Image.open(io.BytesIO(img_bytes))
    
    # Set image upload path 
    img_src = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
    
    # Run model
    results = model(img, size=640)

    # Updates results.imgs with boxes and labels
    results.render()  
    
    for img in results.imgs:
        img_base64 = Image.fromarray(img)
        img_base64.save(img_src)
        
    # Crop image by boxes
    crops = results.crop(save=False)
    # conf = (crop[0]['conf'].item() * 100)
    
    # to save car numbers and names
    car_dict = {}

    
    # loop every cropped image
    for num, crop in enumerate(crops) :
        # if it's a plate over 50% probability
        if 'plate' in crop['label'] and crop['conf'].item() * 100 > 50 :
            image = crop['im']
            # Set cropped image and apply augmentation - grayscale, gaussianblur
            im = Image.fromarray(image)
            im = im.convert("L")
            im = im.filter(ImageFilter.GaussianBlur(radius =1))
    
    		# Set plate image save path to FILENAME_pl2.png
            plate_src = os.path.join(app.config['UPLOAD_FOLDER'], file.filename.split('.')[0] + '_pl' + str(num) + '.png')
            im.save(plate_src, 'png')
            #이미지를 upload 할 때 마다 실행
            price=0 #주차요금은 기본적으로 0원
            name, carNumber = solution(plate_src) #ocr로 차번호를 가져와서 db에 있는 이름을 가져온다
            print(name,carNumber)
            car_dict[carNumber] = (name,price) #dictonary 형태로 차번호:{이름,주차요금}
            if name!="미등록" and name!="인식오류":# 등록된 차량에 한해서 주차요금 계산
                conn = sqlite3.connect('users.sqlite3') #db에 접근
                cursor = conn.cursor()
                cursor.execute('UPDATE users SET timeout =? WHERE name =? and timein!=?', (time(),name,NULL) ) #입차시간이 있으면 출차시간에 등록

                cursor.execute('UPDATE users SET timein =? WHERE name =? and timein=?', (time(),name,NULL) ) # 입차시간이 없으면 입차시간에 등록

                cursor.execute('SELECT * FROM users WHERE name=?', (name, ))# db에 등록된 정보 가져옴
                results = cursor.fetchall()
                print(results)
                cursor.execute('UPDATE users SET (cal,timein,timeout) =(?,?,?) WHERE name =? and timein!=? and timeout!=?',
                    (results[0][4]-results[0][3],0,0,name,0,0)) #입차,출차시간이 있으면 출차시간-입차시간 계산해 주차시간에 입력하고 입차,출차시간 초기화
                cursor.execute('SELECT * FROM users WHERE name=?', (name, ))# db에 등록된 정보 가져옴
                fresults = cursor.fetchall()
                print(fresults)
                if fresults[0][5]!=0: #주차시간이 0이 아니면 초당100원 반올림
                    price=round(100*fresults[0][5])
                    car_dict[carNumber] = (name,price) #dictionary 형태로 주차요금 제공
                    cursor.execute('UPDATE users SET cal =? WHERE name =? ', (0,name)) #주차시간 초기화
                    cursor.execute('SELECT * FROM users WHERE name=?', (name, ))# db에 등록된 정보 가져옴
                    results = cursor.fetchall()
                    print(results)
                conn.commit() #db 수정 종료
                conn.close()

    # call detection.html with car_dict
    return template(render_template('detection.html', filename=img_src, results=car_dict))

@app.route("/userList/")
def userList(innerContent=""):
    conn = sqlite3.connect('users.sqlite3')
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, carNumber TEXT NOT NULL, timein INTEGER , timeout INTEGER ,cal INTEGER) ")
    cursor.execute('SELECT * FROM users')
    users = cursor.fetchall()
    conn.close()
    uList = f'''
      <div class="middle">
      <table id="users">
        <thead><tr><th>이름</th><th>차량번호</th><th>삭제</th></tr></thead>
        <tbody>
    '''
    for user in users:
        uList += f'<tr><td>{user[1]}</td><td>{user[2]}</td><td><a href="/delete/{user[0]}/">삭제</a></td></tr>'
    uList += f'</tbody></table>'
    content = f'''
    {uList}
    </div>
    <div class="right">
        <a class="insert" href="/insert/">신규 사용자 등록</a><br>
        {innerContent}
    </div>
    '''
    return template(content)


@app.route("/insert/")
def insert():
    content = '''
    <form action="/insert_process/" method="POST">
      <p><input type="text" name="name" placeholder="이름"></p>
      <p><input type="text" name="carNumber" placeholder="차량번호"></p>
      <p><input type="submit" value="등록"></p>
    </form>
    '''
    return userList(content)


@app.route("/insert_process/", methods=['POST'])
def insert_process():
    name = request.form['name'].replace(' ', '')
    carNumber = request.form['carNumber'].replace(' ', '')
    conn = sqlite3.connect('users.sqlite3')
    cursor = conn.cursor()
    cursor.execute('INSERT INTO users (name, carNumber, timein, timeout,cal) VALUES (?,?,?,?,?)', (name, carNumber,0,0,0))
    conn.commit()
    conn.close()
    content = "등록 완료하였습니다."
    return userList(content)

@app.route('/delete/<int:num>/')
def delete(num):
    conn = sqlite3.connect('users.sqlite3')
    cursor = conn.cursor()
    cursor.execute('DELETE FROM users WHERE id=?', (num,))
    conn.commit()
    conn.close()
    content = "삭제 완료하였습니다."
    return userList(content)


@app.route("/")
def index():
    return template("환영합니다.")


# 실행
if __name__ == "__main__":
    # 파일 업로드 폴더 경로
    UPLOAD_FOLDER = './static/images'
    Path("./" + UPLOAD_FOLDER).mkdir(parents=True, exist_ok=True)
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    
    pt_file_path = "./models_train/best.pt"
    model = torch.hub.load('./yolov5', 'custom', path=pt_file_path, source='local')
    
    app.run(host='0.0.0.0', port=80, debug=True)

실행결과

다음과 같이 db에 등록된 차량에 한하여

처음 이미지를 업로드 했을때 입차로 인식

같은 이미지를 두번째 업로드 했을때 출차로 인식하여 주차요금이 나온다.

내부데이터는 다음과 같이 바뀌고 초기화를 통해서 같은 차량이 여러번 할수도 있고 여러 차량의 값을 갖고 있다가 계산할수도 있다.

학습한 내용 중 어려웠던 점 또는 해결못한 것들
값을 불러오고 저장하는 과정이 어려웠다.

해결방법 작성

학습 소감
flask를 이용해서 웹으로 이러한 결과를 보여줄 수 있는점이 재미있다.

0개의 댓글