Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -11,10 +11,8 @@ AI-Hub 원본 데이터는 배포하지 않는다(라이선스). 발표/시연
|
|
| 11 |
GLUE_NO_SEG=1 seg 정밀 마스크 끄기(CPU Space 속도용; 박스만 표시)
|
| 12 |
"""
|
| 13 |
import os
|
| 14 |
-
import statistics
|
| 15 |
|
| 16 |
import gradio as gr
|
| 17 |
-
from PIL import Image
|
| 18 |
|
| 19 |
from load_models import load_all
|
| 20 |
from infer import infer_battery
|
|
@@ -32,54 +30,17 @@ def _paths(files):
|
|
| 32 |
return [p for p in out if p]
|
| 33 |
|
| 34 |
|
| 35 |
-
# 종횡비 자동 형태 판정: cell≈1:13(긴막대), module≈1:2.4(직사각).
|
| 36 |
-
# ⚠️ 같은 배터리도 자른 축에 따라 단면 종횡비가 다름(cell도 가로 단면은 정사각).
|
| 37 |
-
# → 슬라이스 '최대' 종횡비로 판정: cell은 어느 축에선 ~13:1이 나오고 module은 최대 ~2.4:1.
|
| 38 |
-
# 3~5 구간은 모호 → 수동 확인 권장. (단일·비대표 슬라이스만 올리면 빗나갈 수 있음)
|
| 39 |
-
FORM_RATIO_THR = 5.0
|
| 40 |
-
FORM_GRAY_LOW = 3.0
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
def detect_form(paths):
|
| 44 |
-
"""반환: (form, max_ratio, note)."""
|
| 45 |
-
ratios = []
|
| 46 |
-
for p in paths:
|
| 47 |
-
try:
|
| 48 |
-
w, h = Image.open(p).size
|
| 49 |
-
lo, hi = min(w, h), max(w, h)
|
| 50 |
-
if lo > 0:
|
| 51 |
-
ratios.append(hi / lo)
|
| 52 |
-
except Exception:
|
| 53 |
-
pass
|
| 54 |
-
if not ratios:
|
| 55 |
-
return "module", None, "이미지 크기를 못 읽어 module 로 가정"
|
| 56 |
-
r = max(ratios) # 가장 길쭉한 뷰 기준
|
| 57 |
-
if r > FORM_RATIO_THR:
|
| 58 |
-
return "cell", r, ""
|
| 59 |
-
note = " ⚠️ 형태 모호 — 수동 확인 권장" if r >= FORM_GRAY_LOW else ""
|
| 60 |
-
return "module", r, note
|
| 61 |
-
|
| 62 |
-
|
| 63 |
def screen(files, form, battery_id):
|
| 64 |
paths = _paths(files)
|
| 65 |
if not paths:
|
| 66 |
return "⚠️ CT 슬라이스 이미지를 업로드하세요", None, {}, ""
|
| 67 |
|
| 68 |
-
# 형태: '자동'이면 종횡비로 추정(이 데이터셋 휴리스틱), 아니면 사용자 선택값
|
| 69 |
-
ratio = None; note = ""
|
| 70 |
-
if form == "자동":
|
| 71 |
-
form_used, ratio, note = detect_form(paths)
|
| 72 |
-
else:
|
| 73 |
-
form_used = form
|
| 74 |
-
|
| 75 |
slices = [{"idx": i, "name": os.path.basename(p), "img_path": p}
|
| 76 |
for i, p in enumerate(paths)]
|
| 77 |
bid = (battery_id or "uploaded").strip()
|
| 78 |
-
result = infer_battery(MODELS, slices,
|
| 79 |
decision = decide(result)
|
| 80 |
report = make_report(result, decision)
|
| 81 |
-
report["형태 판정"] = (f"{form_used} (자동 · 최대 종횡비 {ratio:.1f}:1{note})" if ratio is not None
|
| 82 |
-
else f"{form_used} (수동 선택)")
|
| 83 |
guide = recommend(result, decision)
|
| 84 |
|
| 85 |
if decision["zone"].startswith("🟢"):
|
|
@@ -102,13 +63,8 @@ with gr.Blocks(title="배터리 CT 결함 스크리닝") as demo:
|
|
| 102 |
with gr.Column():
|
| 103 |
files = gr.File(file_count="multiple", file_types=["image"],
|
| 104 |
label="CT 슬라이스 업로드 (한 배터리)")
|
| 105 |
-
form = gr.Radio(["
|
| 106 |
-
label="배터리 형태")
|
| 107 |
-
gr.Markdown(
|
| 108 |
-
"<sub>자동 = 종횡비로 추정(이 AI-Hub pouch 데이터 기준 휴리스틱). "
|
| 109 |
-
"다른 형태/장비면 빗나갈 수 있으니 **수동 선택으로 override** 하세요. "
|
| 110 |
-
"범용 해법은 형태 분류기 학습 또는 스캔 메타데이터.</sub>"
|
| 111 |
-
)
|
| 112 |
bid = gr.Textbox(label="배터리 ID (선택)", placeholder="예: module_402")
|
| 113 |
btn = gr.Button("검사", variant="primary")
|
| 114 |
with gr.Column():
|
|
|
|
| 11 |
GLUE_NO_SEG=1 seg 정밀 마스크 끄기(CPU Space 속도용; 박스만 표시)
|
| 12 |
"""
|
| 13 |
import os
|
|
|
|
| 14 |
|
| 15 |
import gradio as gr
|
|
|
|
| 16 |
|
| 17 |
from load_models import load_all
|
| 18 |
from infer import infer_battery
|
|
|
|
| 30 |
return [p for p in out if p]
|
| 31 |
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
def screen(files, form, battery_id):
|
| 34 |
paths = _paths(files)
|
| 35 |
if not paths:
|
| 36 |
return "⚠️ CT 슬라이스 이미지를 업로드하세요", None, {}, ""
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
slices = [{"idx": i, "name": os.path.basename(p), "img_path": p}
|
| 39 |
for i, p in enumerate(paths)]
|
| 40 |
bid = (battery_id or "uploaded").strip()
|
| 41 |
+
result = infer_battery(MODELS, slices, form, bid) # 형태는 사용자가 선택
|
| 42 |
decision = decide(result)
|
| 43 |
report = make_report(result, decision)
|
|
|
|
|
|
|
| 44 |
guide = recommend(result, decision)
|
| 45 |
|
| 46 |
if decision["zone"].startswith("🟢"):
|
|
|
|
| 63 |
with gr.Column():
|
| 64 |
files = gr.File(file_count="multiple", file_types=["image"],
|
| 65 |
label="CT 슬라이스 업로드 (한 배터리)")
|
| 66 |
+
form = gr.Radio(["module", "cell"], value="module",
|
| 67 |
+
label="배터리 형태 (직접 선택)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
bid = gr.Textbox(label="배터리 ID (선택)", placeholder="예: module_402")
|
| 69 |
btn = gr.Button("검사", variant="primary")
|
| 70 |
with gr.Column():
|