버전 업그레이드
This commit is contained in:
@@ -1,25 +1,18 @@
|
||||
# 그룹 관리 — A/B 모델 그룹 수동 전환 (최대 4종 per group)
|
||||
# 검사 대상 관리 — DB 미연결 시 PatMax 슬롯 1~16 허용 (레거시 호환)
|
||||
from logic.products import MAX_PATMAX_SLOTS
|
||||
|
||||
|
||||
class GroupManager:
|
||||
MAX_PER_GROUP = 4
|
||||
|
||||
def __init__(self):
|
||||
self._group_a: list = []
|
||||
self._group_b: list = []
|
||||
self._active: str = "A"
|
||||
|
||||
def set_group_a(self, model_list: list):
|
||||
self._group_a = model_list[: self.MAX_PER_GROUP]
|
||||
|
||||
def set_group_b(self, model_list: list):
|
||||
self._group_b = model_list[: self.MAX_PER_GROUP]
|
||||
"""레거시 호환용. 그룹 A/B 전환·선택 제한은 비활성화."""
|
||||
|
||||
def get_active_group(self) -> list:
|
||||
return self._group_a if self._active == "A" else self._group_b
|
||||
return []
|
||||
|
||||
def get_active_name(self) -> str:
|
||||
return self._active
|
||||
return "ALL"
|
||||
|
||||
def get_allowed_ids(self) -> list:
|
||||
return list(range(1, MAX_PATMAX_SLOTS + 1))
|
||||
|
||||
def switch_group(self) -> str:
|
||||
"""A↔B 전환 후 활성 그룹 이름 반환"""
|
||||
self._active = "B" if self._active == "A" else "A"
|
||||
return self._active
|
||||
return "ALL"
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
# Cognex 카메라 셀 매핑 (GV 방식 fallback용으로 유지)
|
||||
PATTERN_RESULT_CELLS = {
|
||||
"A27": {"id": 1, "name": "LOW REF", "model": "LX3", "type": "RH"},
|
||||
"A77": {"id": 2, "name": "LOW REF", "model": "LX3", "type": "LH"},
|
||||
"A127": {"id": 3, "name": "LOW REF NAS", "model": "LX3", "type": "RH"},
|
||||
"A177": {"id": 4, "name": "LOW REF NAS", "model": "LX3", "type": "LH"},
|
||||
}
|
||||
from db.sql_client import SQLClient
|
||||
from logic.products import model_display_label
|
||||
|
||||
|
||||
class Inspector:
|
||||
|
||||
def __init__(self):
|
||||
self._pattern_cells: dict = {}
|
||||
|
||||
def set_pattern_cells(self, cells: dict):
|
||||
"""DB 기반 PatMax 셀 매핑 (refresh_wk_results 시 갱신)."""
|
||||
self._pattern_cells = cells or {}
|
||||
|
||||
# ── Python PatMax 매칭 (주 경로) ─────────────────────────────────── #
|
||||
|
||||
def match_image(self, image_bytes: bytes, matcher: "PatternMatcher") -> dict:
|
||||
@@ -47,9 +49,9 @@ class Inspector:
|
||||
# ── Cognex GV 셀 방식 (fallback) ────────────────────────────────── #
|
||||
|
||||
def read_patmax_results(self, insight) -> dict:
|
||||
"""A27/A77/A127/A177 셀 조회 → #ERR이면 실패, 그 외 점수 파싱."""
|
||||
"""PatMax 결과 셀 조회 → #ERR이면 실패, 그 외 점수 파싱."""
|
||||
results = {}
|
||||
for cell, model_info in PATTERN_RESULT_CELLS.items():
|
||||
for cell, model_info in self._pattern_cells.items():
|
||||
try:
|
||||
insight._send(f"GV{cell}")
|
||||
code = insight._read_line()
|
||||
@@ -85,8 +87,10 @@ class Inspector:
|
||||
|
||||
# ── 공통: 모델 판별 + 판정 ──────────────────────────────────────── #
|
||||
|
||||
def identify_model(self, results: dict, allowed_model_ids: list) -> dict:
|
||||
"""매칭된 패턴 중 점수가 가장 높은 것을 선택해 허용 모델 여부 판별."""
|
||||
def identify_model(self, results: dict,
|
||||
allowed_model_ids: "list | None" = None,
|
||||
allowed_article_ids: "set | None" = None) -> dict:
|
||||
"""매칭된 패턴 중 점수가 가장 높은 것을 선택해 허용 여부 판별."""
|
||||
matched_patterns = [
|
||||
(cell, info) for cell, info in results.items()
|
||||
if info["matched"]
|
||||
@@ -100,19 +104,26 @@ class Inspector:
|
||||
}
|
||||
|
||||
_best_cell, best_info = max(matched_patterns, key=lambda x: x[1]["score"])
|
||||
model = best_info["model"]
|
||||
in_allowed = model["id"] in allowed_model_ids
|
||||
model = best_info["model"]
|
||||
label = model_display_label(model)
|
||||
|
||||
if allowed_article_ids is not None:
|
||||
in_allowed = (
|
||||
SQLClient._norm_id(model.get("article_id")) in allowed_article_ids
|
||||
)
|
||||
else:
|
||||
in_allowed = model["id"] in (allowed_model_ids or [])
|
||||
|
||||
return {
|
||||
"matched": True,
|
||||
"in_allowed": in_allowed,
|
||||
"model": model,
|
||||
"score": best_info["score"],
|
||||
"matched": True,
|
||||
"in_allowed": in_allowed,
|
||||
"model": model,
|
||||
"score": best_info["score"],
|
||||
"cognex_pass": in_allowed,
|
||||
"status": (
|
||||
f"{model['name']} {model['model']} {model['type']} ({best_info['score']:.1f}점)"
|
||||
f"{label} ({best_info['score']:.1f}점)"
|
||||
if in_allowed
|
||||
else f"허용 외 모델: {model['name']} {model['model']} {model['type']}"
|
||||
else f"작업 대상 외: {label}"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
56
logic/products.py
Normal file
56
logic/products.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# Cognex PatMax GV 셀 주소 + DB 제품 기반 런타임 매핑
|
||||
|
||||
MAX_PATMAX_SLOTS = 16
|
||||
|
||||
# Cognex job: PatMax 블록마다 50행 간격, 첫 결과 셀 = A27
|
||||
_PATMAX_FIRST_ROW = 27
|
||||
_PATMAX_ROW_STEP = 50
|
||||
|
||||
|
||||
def patmax_cell_address(slot_index: int) -> str:
|
||||
"""0-based PatMax 슬롯 → GV 셀 주소 (A27, A77, …)."""
|
||||
row = _PATMAX_FIRST_ROW + slot_index * _PATMAX_ROW_STEP
|
||||
return f"A{row}"
|
||||
|
||||
|
||||
def build_patmax_cells(articles: list) -> dict:
|
||||
"""
|
||||
DB 제품 목록(관리자 MES 선택 순서)으로 PatMax 셀 → 제품 정보 매핑 생성.
|
||||
Cognex job 슬롯 순서와 mes.selected_article_ids 순서가 일치해야 함.
|
||||
"""
|
||||
cells = {}
|
||||
for i, article in enumerate(articles[:MAX_PATMAX_SLOTS]):
|
||||
cells[patmax_cell_address(i)] = article_to_model(article, slot_id=i + 1)
|
||||
return cells
|
||||
|
||||
|
||||
def article_to_model(article: dict, slot_id: int) -> dict:
|
||||
"""DB article 행 → PatMax/검사용 model dict."""
|
||||
return {
|
||||
"id": slot_id,
|
||||
"article_id": article["article_id"],
|
||||
"article": article.get("article", ""),
|
||||
"name": article.get("article", ""),
|
||||
"model": article.get("buyer_article_no", "") or "",
|
||||
"type": "",
|
||||
}
|
||||
|
||||
|
||||
def article_label(article: dict) -> str:
|
||||
"""DB article / model dict UI 표시용."""
|
||||
if article.get("article"):
|
||||
return article["article"]
|
||||
if article.get("name"):
|
||||
return article["name"]
|
||||
return str(article.get("article_id", ""))
|
||||
|
||||
|
||||
def model_display_label(model: dict) -> str:
|
||||
"""PatMax 인식 결과 model dict 표시용."""
|
||||
if model.get("article"):
|
||||
return model["article"]
|
||||
parts = [model.get("name", ""), model.get("model", "")]
|
||||
parts = [p for p in parts if p]
|
||||
if model.get("type"):
|
||||
parts.append(model["type"])
|
||||
return " / ".join(parts) if parts else str(model.get("article_id", ""))
|
||||
Reference in New Issue
Block a user