# 검사 판별 로직 — PatMax 결과 판독 + 모델 판별 + Pass/Fail 판정 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"}, } class Inspector: # ── Python PatMax 매칭 (주 경로) ─────────────────────────────────── # def match_image(self, image_bytes: bytes, matcher: "PatternMatcher") -> dict: """ FTP로 받은 이미지 바이트를 Python PatternMatcher로 매칭. 반환 형식은 read_patmax_results와 동일하여 identify_model에서 그대로 사용. """ if not image_bytes: return {} arr = np.frombuffer(image_bytes, dtype=np.uint8) img = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED) if img is None: return {} all_scores = matcher.match_all(img) results = {} for pid, score in all_scores.items(): info = matcher.get_product_info(pid) if info is None: continue results[f"PY_{pid}"] = { "matched": score >= matcher.score_threshold, "score": score, "model": info, "raw": f"python_match={score:.1f}", } return results # ── Cognex GV 셀 방식 (fallback) ────────────────────────────────── # def read_patmax_results(self, insight) -> dict: """A27/A77/A127/A177 셀 조회 → #ERR이면 실패, 그 외 점수 파싱.""" results = {} for cell, model_info in PATTERN_RESULT_CELLS.items(): try: insight._send(f"GV{cell}") code = insight._read_line() if code != "1": results[cell] = { "matched": False, "score": 0.0, "model": model_info, "raw": "" } continue value = insight._read_line() if "#ERR" in value or value.strip() == "": results[cell] = { "matched": False, "score": 0.0, "model": model_info, "raw": value } else: # "(736.1,742.0) -1.8 = 82.9" 형식에서 = 뒤 값 추출 try: score = float(value.split("=")[-1].strip()) except Exception: score = 0.0 results[cell] = { "matched": True, "score": score, "model": model_info, "raw": value } except Exception as e: print(f"[PatMax] {cell} 읽기 오류: {e}") results[cell] = { "matched": False, "score": 0.0, "model": model_info, "raw": "" } return results # ── 공통: 모델 판별 + 판정 ──────────────────────────────────────── # def identify_model(self, results: dict, allowed_model_ids: list) -> dict: """매칭된 패턴 중 점수가 가장 높은 것을 선택해 허용 모델 여부 판별.""" matched_patterns = [ (cell, info) for cell, info in results.items() if info["matched"] ] if not matched_patterns: return { "matched": False, "in_allowed": False, "model": None, "score": 0.0, "cognex_pass": False, "status": "인식 불가" } _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 return { "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}점)" if in_allowed else f"허용 외 모델: {model['name']} {model['model']} {model['type']}" ), } def judge(self, cognex_pass: bool, basler_pass: bool) -> str: return "PASS" if cognex_pass and basler_pass else "FAIL"