bukuroo commited on
Commit
3969a3f
·
verified ·
1 Parent(s): 994af4d

Upload 6 files

Browse files
Files changed (6) hide show
  1. README.md +21 -8
  2. __init__.py +1 -0
  3. app.py +65 -0
  4. packages.txt +2 -0
  5. requirements.txt +3 -0
  6. space_inference.py +90 -0
README.md CHANGED
@@ -1,15 +1,28 @@
1
  ---
2
- title: Lipla
3
- emoji: 📚
4
- colorFrom: purple
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.22.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
  license: mit
12
- short_description: Japanese license plate recognition
 
 
 
13
  ---
14
 
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Lipla-jp
3
+ emoji: 🚘
4
+ colorFrom: indigo
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 6.20.0
8
+ python_version: 3.12
9
  app_file: app.py
10
  pinned: false
11
  license: mit
12
+ models:
13
+ - bukuroo/Lipla-jp
14
+ preload_from_hub:
15
+ - bukuroo/Lipla-jp ecpose_m_260809.onnx,ppocrv6_det.onnx,ppocrv6_rec.onnx,inference.yml c66f50ce0cc08e20318b00ad832c9b848b4d580b
16
  ---
17
 
18
+ # Lipla-jp Gradio demo
19
+
20
+ 画像をドロップすると、日本の自動車ナンバープレートを検出・認識します。
21
+
22
+ - `LPDetResult.det_image` と `LPDetResult.result_image` をギャラリー表示します。
23
+ - `LPDetResult` の画像以外のフィールドをJSONテキストで表示します。
24
+ - 複数のナンバープレートを検出した場合は、結果を検出順に表示します。
25
+
26
+ このディレクトリの内容をHugging Face Spaceリポジトリのルートへ配置して
27
+ 公開してください。Spaceのビルド時にモデルと日本語フォントが準備されます。
28
+
__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """Hugging Face Spaces向けデモアプリ。"""
app.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Lipla-jpのHugging Face Spaces向けGradioアプリ。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import gradio as gr
6
+
7
+ try:
8
+ from .space_inference import recognize_image
9
+ except ImportError: # Spaceでapp.pyを直接実行する場合
10
+ from space_inference import recognize_image
11
+
12
+
13
+ def build_demo() -> gr.Blocks:
14
+ """画像ドロップで推論を開始するGradio UIを構築する。"""
15
+ with gr.Blocks(title="Lipla-jp") as demo:
16
+ gr.Markdown(
17
+ "# Lipla-jp\n"
18
+ "日本の自動車ナンバープレートを検出・認識します。"
19
+ "画像をドロップすると自動的に処理を開始します。"
20
+ )
21
+
22
+ input_image = gr.Image(
23
+ label="入力画像",
24
+ type="numpy",
25
+ image_mode="RGB",
26
+ sources=["upload", "clipboard"],
27
+ )
28
+
29
+ with gr.Row():
30
+ det_gallery = gr.Gallery(
31
+ label="det_image",
32
+ columns=1,
33
+ object_fit="contain",
34
+ height="auto",
35
+ )
36
+ result_gallery = gr.Gallery(
37
+ label="result_image",
38
+ columns=1,
39
+ object_fit="contain",
40
+ height="auto",
41
+ )
42
+
43
+ result_json = gr.Textbox(
44
+ label="LPDetResult(画像以外)",
45
+ value="[]",
46
+ lines=20,
47
+ max_lines=30,
48
+ )
49
+
50
+ input_image.change(
51
+ fn=recognize_image,
52
+ inputs=input_image,
53
+ outputs=[det_gallery, result_gallery, result_json],
54
+ api_name="recognize",
55
+ )
56
+
57
+ return demo
58
+
59
+
60
+ demo = build_demo()
61
+ demo.queue(max_size=8)
62
+
63
+
64
+ if __name__ == "__main__":
65
+ demo.launch()
packages.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fonts-noto-cjk
2
+
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio==6.20.0
2
+ lipla-jp @ git+https://github.com/ikeboo/Lipla-jp.git@main
3
+
space_inference.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradio UIから独立したナンバープレート認識処理。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from collections.abc import Callable
7
+ from dataclasses import fields
8
+ from functools import cache
9
+ from typing import Any
10
+
11
+ import numpy as np
12
+
13
+ from lipla import LPDetResult, Recognizer
14
+
15
+ _IMAGE_FIELD_NAMES = frozenset(
16
+ {"plate_image", "original_image", "_det_image", "_result_image"}
17
+ )
18
+
19
+
20
+ @cache
21
+ def get_recognizer() -> Recognizer:
22
+ """モデルを最初の推論時に一度だけ初期化する。"""
23
+ return Recognizer(providers=["CPUExecutionProvider"])
24
+
25
+
26
+ def _json_compatible(value: Any) -> Any:
27
+ """NumPyの値をJSONで表現できるPython組み込み型へ変換する。"""
28
+ if isinstance(value, np.ndarray):
29
+ return value.tolist()
30
+ if isinstance(value, np.generic):
31
+ return value.item()
32
+ if isinstance(value, tuple):
33
+ return [_json_compatible(item) for item in value]
34
+ if isinstance(value, list):
35
+ return [_json_compatible(item) for item in value]
36
+ if isinstance(value, dict):
37
+ return {str(key): _json_compatible(item) for key, item in value.items()}
38
+ return value
39
+
40
+
41
+ def result_to_dict(result: LPDetResult) -> dict[str, Any]:
42
+ """LPDetResultから画像フィールドを除いたJSON用データを作る。"""
43
+ return {
44
+ field.name: _json_compatible(getattr(result, field.name))
45
+ for field in fields(result)
46
+ if field.name not in _IMAGE_FIELD_NAMES and not field.name.startswith("_")
47
+ }
48
+
49
+
50
+ def _bgr_to_rgb(image: np.ndarray) -> np.ndarray:
51
+ """OpenCVのBGR画像をGradio表示用RGB画像へ変換する。"""
52
+ return np.ascontiguousarray(image[..., ::-1])
53
+
54
+
55
+ def recognize_image(
56
+ image: np.ndarray | None,
57
+ *,
58
+ recognizer_factory: Callable[[], Recognizer] = get_recognizer,
59
+ ) -> tuple[
60
+ list[tuple[np.ndarray, str]],
61
+ list[tuple[np.ndarray, str]],
62
+ str,
63
+ ]:
64
+ """RGB画像を認識し、2種類の画像ギャラリーとJSON文字列を返す。"""
65
+ if image is None:
66
+ return [], [], "[]"
67
+ if not isinstance(image, np.ndarray):
68
+ raise TypeError("image must be a numpy.ndarray")
69
+ if image.ndim != 3 or image.shape[2] != 3:
70
+ raise ValueError("image must have shape (height, width, 3)")
71
+ if image.dtype != np.uint8:
72
+ raise TypeError("image must have dtype uint8")
73
+
74
+ bgr_image = _bgr_to_rgb(image)
75
+ results = recognizer_factory()(bgr_image)
76
+ det_images = [
77
+ (_bgr_to_rgb(result.det_image), f"LPDetResult[{index}]")
78
+ for index, result in enumerate(results)
79
+ ]
80
+ result_images = [
81
+ (_bgr_to_rgb(result.result_image), f"LPDetResult[{index}]")
82
+ for index, result in enumerate(results)
83
+ ]
84
+ result_json = json.dumps(
85
+ [result_to_dict(result) for result in results],
86
+ ensure_ascii=False,
87
+ indent=2,
88
+ allow_nan=False,
89
+ )
90
+ return det_images, result_images, result_json