블랙박스에서 자동차 번호를 추출해서 엑셀 csv로 변환해주는 테스트 웹사이트을 구축해보았습니다.

프로그램 코드
main.py
# main.py
import os
from flask import Flask, request, redirect, url_for, render_template, send_from_directory
from werkzeug.utils import secure_filename
import cv2
import easyocr
import pandas as pd
import datetime
import re
import logging
# 로깅 설정 추가 (맨 위쪽에 추가)
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
# 허용된 파일 확장자 설정
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv'}
# 업로드 폴더 설정
UPLOAD_FOLDER = 'uploads'
RESULT_FOLDER = 'results'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(RESULT_FOLDER, exist_ok=True)
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# 허용된 파일인지 확인하는 함수
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
# 한국 번호판 패턴 검증 함수 추가
def validate_korean_plate(text):
# 문자열에서 공백 제거
text = re.sub(r'\s+', '', text)
# 숫자 2-3개 + 한글 1개 + 숫자 4개 패턴
pattern1 = r'\d{2,3}[가-힣]\d{4}'
# 한글 2개 + 숫자 4개 패턴 (외교차량, 국제기구 등)
pattern2 = r'[가-힣]{2}\d{4}'
# 텍스트 내에서 패턴 찾기
matches = re.findall(pattern1, text) or re.findall(pattern2, text)
if matches:
return matches[0]
return None
# 비디오 처리 함수
def process_video(filepath):
# 한국어 인식을 위해 'ko' 추가
reader = easyocr.Reader(['ko', 'en'], gpu=True) # GPU 사용 설정
cap = cv2.VideoCapture(filepath)
detected_plates = []
frame_rate = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
logging.info(f"비디오 처리 시작: {filepath}")
logging.info(f"총 프레임 수: {total_frames}, 프레임레이트: {frame_rate}")
current_frame = 0
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 3프레임당 한 번씩만 처리 (기존 5프레임에서 3프레임으로 수정)
if current_frame % 3 != 0:
current_frame += 1
continue
# 프로그레스 로깅
if current_frame % 30 == 0:
progress = (current_frame / total_frames) * 100
logging.info(f"처리 진행률: {progress:.1f}%")
current_time = current_frame / frame_rate
# 이미지 전처리
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# OCR 처리
results = reader.readtext(blurred)
for (bbox, text, prob) in results:
# 확률 75% 이상으로 낮춤 (기존 85%에서 조정)
if prob > 0.75:
valid_plate = validate_korean_plate(text)
if valid_plate:
plate_info = {
"time": str(datetime.timedelta(seconds=current_time)),
"plate": valid_plate,
"confidence": round(prob * 100, 2)
}
detected_plates.append(plate_info)
logging.info(f"번호판 감지: {plate_info}")
current_frame += 1
cap.release()
logging.info(f"비디오 처리 완료. 감지된 번호판 수: {len(detected_plates)}")
return detected_plates
# 업로드 페이지 라우트
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
return '파일이 없어요!'
file = request.files['file']
if file.filename == '':
return '선택된 파일이 없어요!'
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
logging.info(f"파일 업로드 완료: {filename}")
# 비디오 처리
detected_plates = process_video(filepath)
if not detected_plates:
logging.warning("감지된 번호판이 없습니다!")
return "번호판을 감지하지 못했습니다. 다른 영상을 시도해보세요."
# 결과를 CSV로 저장
df = pd.DataFrame(detected_plates)
csv_filename = f"{filename.rsplit('.',1)[0]}_license_plates.csv"
csv_path = os.path.join(RESULT_FOLDER, csv_filename)
df.to_csv(csv_path, index=False, encoding='utf-8-sig')
logging.info(f"결과 저장 완료: {csv_filename}")
return redirect(url_for('download_file', filename=csv_filename))
return '''
<!doctype html>
<title>블랙박스 동영상 업로드</title>
<h1>블랙박스 동영상을 업로드하세요</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file accept="video/*">
<input type=submit value=업로드>
</form>
'''
# 결과 파일 다운로드 라우트
@app.route('/download/<filename>')
def download_file(filename):
return send_from_directory(RESULT_FOLDER, filename, as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)
프로그램 동작 설명
1. 필요한 라이브러리 임포트: Flask 웹 프레임워크, OpenCV, EasyOCR, Pandas 등을 불러옵니다.
2. 파일 업로드 설정:
허용된 비디오 파일 확장자를 설정하고, 업로드 및 결과 저장 폴더를 생성합니다.
3. Flask 애플리케이션 설정:
Flask 앱을 초기화하고, 업로드 폴더를 설정합니다.
4. 파일 확장자 검증 함수:
업로드된 파일의 확장자가 허용된 형식인지 확인하는 함수를 정의합니다.
5. 비디오 처리 함수 (process_video):
비디오 파일을 프레임 단위로 읽어들이고, EasyOCR을 사용하여 각 프레임에서 번호판을 인식합니다.
인식된 번호판과 해당 프레임의 타임스탬프를 리스트에 저장합니다.
6. 루트 라우트 (/):
GET 요청 시 업로드 폼을 보여주고, POST 요청 시 파일을 업로드합니다.
업로드된 파일이 유효하면 저장 후 process_video 함수를 호출하여 번호판을 인식하고, 결과를 CSV 파일로 저장합니다.
CSV 파일 다운로드 페이지로 리디렉션합니다.
7. 다운로드 라우트 (/download/<filename>):
처리된 CSV 파일을 사용자에게 다운로드할 수 있도록 제공합니다.

8. 애플리케이션 실행:
D:\study\python>python main.py

웹페이지 접속 ( http://127.0.0.1:5000/ )

영상 업로드 하면... 자동으로 분석해서 검색된 자동차 번호판을 csv로 변환해줍니다.
'개발 언어 > Python' 카테고리의 다른 글
파이썬 자료 구조 샘플 (7) | 2025.05.18 |
---|---|
실시간 객체 인식 시스템: 웹캠과 모바일 카메라를 활용한 AI 기술 구현하기 (3) | 2025.05.11 |
파이썬 프로토콜 연동, 샘플 프로젝트로 쉽게 시작하기 (0) | 2025.05.11 |
Sentry를 사용하여 Django 프로젝트에서 Python 예외 처리 (0) | 2025.05.09 |
RTSP 영상 모니터링을 위한 Python 입문 가이드 (1) | 2025.04.28 |