"""方法G:暗色图形的连通域 + alpha 轮廓形状匹配实验。""" from pathlib import Path import cv2 import numpy as np ROOT = Path(__file__).resolve().parent.parent CAP = ROOT / "captchas" OUT = ROOT / "try" / "out" / "G" OUT.mkdir(parents=True, exist_ok=True) def files_for(prefix): bigs = [p for p in CAP.glob(f"{prefix}*.jpeg") if "-mark" not in p.stem] if not bigs: return None, None big = bigs[0] return big, CAP / f"{big.stem}-mark.png" def detect_components(gray): """用局部暗目标检测提取候选组件。""" blur = cv2.GaussianBlur(gray, (0, 0), 15) dark = np.clip(blur.astype(np.int16) - gray.astype(np.int16), 0, 255).astype(np.uint8) mask = (dark > 12).astype(np.uint8) * 255 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8), iterations=2) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8)) return mask def process(prefix): big_path, mark_path = files_for(prefix) if big_path is None: return big = cv2.imread(str(big_path), cv2.IMREAD_COLOR) mark = cv2.imread(str(mark_path), cv2.IMREAD_UNCHANGED) if big is None or mark is None: return alpha = mark[..., 3] if mark.ndim == 3 and mark.shape[2] == 4 else np.full(mark.shape[:2], 255, np.uint8) m = (alpha > 128).astype(np.uint8) * 255 mc, _ = cv2.findContours(m, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) mc = max(mc, key=cv2.contourArea) ma = max(cv2.contourArea(mc), 1) gray = cv2.cvtColor(big, cv2.COLOR_BGR2GRAY) mask = detect_components(gray) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) vis = big.copy() found = [] for c in contours: area = cv2.contourArea(c) x, y, w, h = cv2.boundingRect(c) if area < ma * 0.08 or area > ma * 3 or min(w, h) < 20 or max(w, h) > 180: continue score = cv2.matchShapes(mc, c, cv2.CONTOURS_MATCH_I1, 0) found.append((score, area, x, y, w, h)) found.sort(key=lambda z: z[0]) for i, (_, _, x, y, w, h) in enumerate(found[:5]): color = (0, 0, 255) if i == 0 else (255, 0, 0) cv2.rectangle(vis, (x, y), (x + w, y + h), color, 2) cv2.putText(vis, f"{i+1}", (x, max(14, y - 3)), cv2.FONT_HERSHEY_SIMPLEX, .5, color, 2) cv2.imwrite(str(OUT / f"{prefix}-components.png"), vis) line = " ".join(f"#{i+1}:{s:.3f}@({x},{y},{w},{h})" for i,(s,_,x,y,w,h) in enumerate(found[:5])) print(prefix, line or "无候选") def main(): prefixes = sorted({p.name.split("~", 1)[0] for p in CAP.glob("*.jpeg") if "-mark" not in p.stem}) for prefix in prefixes: process(prefix) if __name__ == "__main__": main()