OpenALPR による英語ナンバープレート認識(ソースコードと実行結果)

Python開発環境,ライブラリ類

ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。

Python 3.12 のインストール

インストール済みの場合は実行不要。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。

REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul

関連する外部ページ

Python の公式ページ: https://www.python.org/

AI エディタ Windsurf のインストール

Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。

管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。

winget install --scope machine Codeium.Windsurf -e --silent

関連する外部ページ

Windsurf の公式ページ: https://windsurf.com/

必要なライブラリのインストール

コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する


pip install opencv-python

OpenALPR による英語ナンバープレート認識

概要

このプログラムは、Webカメラから車両画像を取得し、OpenALPRライブラリを用いてナンバープレートの自動認識を行うシステムである。Windows環境でOpenALPR 2.3.0のバイナリを自動的にダウンロード・設定し、リアルタイムでナンバープレート認識処理を実行する。認識結果は画像上にオーバーレイ表示され、JSON形式でも出力される。

主要技術

OpenALPR (Automatic License Plate Recognition)

OpenALPRは、オープンソースの自動ナンバープレート認識ライブラリである[1]。機械学習とコンピュータビジョン技術を組み合わせ、画像からナンバープレートを検出・認識する。LBP (Local Binary Patterns) カスケード分類器による車両検出と、Tesseract OCRエンジンによる文字認識を統合している[2]。

技術的特徴

自動環境構築機能

プログラム実行時にOpenALPRバイナリの存在を確認し、未インストールの場合は自動的にダウンロード・展開を行う。LOCALAPPDATA環境変数を活用し、ユーザーごとの適切な場所に配置する。設定ファイル(openalpr.conf)とランタイムデータの自動探索を行う。

プロセス間通信による認識処理

OpenALPRの実行ファイル(alpr.exe)を子プロセスとして起動し、JSON形式で結果を取得する。環境変数(OPENALPR_CONFIG_FILE、OPENALPR_RUNTIME_DIR)を設定することで、動作環境を制御する。

実装の特色

一時ファイル管理

tempfileモジュールのTemporaryDirectoryを使用し、キャプチャ画像を一時的に保存する。コンテキストマネージャにより、処理終了後の自動削除を保証している。

認識結果の可視化

認識されたナンバープレート番号と信頼度スコアをヒョ持する。複数の候補がある場合は最も信頼度の高い結果を表示する。それと別に,JSON形式での詳細情報を出力する。

参考文献

[1] OpenALPR Technology, Inc. (2024). OpenALPR - Automatic License Plate Recognition library. GitHub Repository. https://github.com/openalpr/openalpr

[2] Smith, R. (2007). An Overview of the Tesseract OCR Engine. Proceedings of the Ninth International Conference on Document Analysis and Recognition (ICDAR 2007), 629-633. https://github.com/tesseract-ocr/tesseract

ソースコード


# OpenALPR による英語ナンバープレート認識
import os, sys, json, tempfile, zipfile, urllib.request, subprocess, time, shutil
try:
    import cv2
except Exception:
    subprocess.check_call([sys.executable, "-m", "pip", "install", "opencv-python"])
    import cv2

URL="https://github.com/openalpr/openalpr/releases/download/v2.3.0/openalpr-2.3.0-win-64bit.zip"
ROOT=os.path.join(os.environ.get("LOCALAPPDATA", tempfile.gettempdir()), "openalpr-2.3.0-win-64bit")
ALPR_EXE=None; CONFIG=None; RUNTIME=None

def ensure_openalpr():
    global ALPR_EXE, CONFIG, RUNTIME
    if not (os.path.isdir(ROOT) and any("alpr.exe" in f for _,_,f in os.walk(ROOT))):
        os.makedirs(ROOT, exist_ok=True)
        zpath=os.path.join(ROOT,"openalpr.zip")
        print("Downloading OpenALPR 2.3.0...")
        urllib.request.urlretrieve(URL, zpath)
        print("Extracting...")
        with zipfile.ZipFile(zpath) as zf: zf.extractall(ROOT)
        os.remove(zpath)
    # find alpr.exe
    found=None
    for d,_,f in os.walk(ROOT):
        if "alpr.exe" in f:
            found=os.path.join(d,"alpr.exe"); break
    if not found: raise RuntimeError("alpr.exe not found")
    ALPR_EXE=found
    base=os.path.dirname(found)
    # config file
    for c in [os.path.join(base,"openalpr.conf"),
              os.path.join(base,"etc","openalpr","openalpr.conf")]:
        if os.path.isfile(c): CONFIG=c; break
    if not CONFIG: raise RuntimeError("openalpr.conf not found")
    # runtime_data
    for r in [os.path.join(base,"runtime_data"),
              os.path.join(base,"..","share","openalpr","runtime_data")]:
        if os.path.isdir(r): RUNTIME=os.path.abspath(r); break
    if not RUNTIME: raise RuntimeError("runtime_data not found")

def capture_frame(path):
    cap=cv2.VideoCapture(0, cv2.CAP_DSHOW)
    if not cap.isOpened(): raise RuntimeError("Camera not available")
    time.sleep(0.3)
    ret,frame=cap.read(); cap.release()
    if not ret: raise RuntimeError("Failed to grab frame")
    cv2.imwrite(path, frame)
    return frame

def run_alpr(img, country="us", topn="10"):
    env=os.environ.copy()
    env["OPENALPR_CONFIG_FILE"]=CONFIG
    env["OPENALPR_RUNTIME_DIR"]=RUNTIME
    cmd=[ALPR_EXE, "-c", country, "--json", "-n", topn, img]
    r=subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, cwd=os.path.dirname(ALPR_EXE))
    if r.returncode!=0 and not r.stdout.strip():
        raise RuntimeError("ALPR error: "+r.stderr.strip())
    return json.loads(r.stdout or "{}")

def main():
    ensure_openalpr()
    with tempfile.TemporaryDirectory() as td:
        img=os.path.join(td,"frame.jpg")
        print("Capturing frame...")
        frame=capture_frame(img)
        print("Recognizing...")
        res=run_alpr(img)

        # 結果を表示
        if "results" in res and res["results"]:
            text=f"{res['results'][0].get('plate','')} ({res['results'][0].get('confidence',0):.1f}%)"
            cv2.putText(frame, text, (30,50), cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)
        cv2.imshow("Captured Frame", frame)
        print(json.dumps(res, indent=2, ensure_ascii=False))
        cv2.waitKey(0)
        cv2.destroyAllWindows()

if __name__=="__main__":
    try:
        main()
    except Exception as e:
        print("Error:", e)
        sys.exit(1)