# -*- coding: utf-8 -*- # 调试:宝龙导视牌 logo 裁切 · 掩膜参数迭代 # 目标:7 行连通域计数 = [11,11,10,11,11,11,11](r2 行牌子上只有 10 格) # 用法:python dev_test_scripts\debug\debug_mall_crop_mask.py import os import sys import cv2 import numpy as np sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools')) from tool_crop_mall_logos import imread_u, imwrite_u, detect_board_quad, warp_board # noqa: E402 SRC = r'D:\Temp文件\baolong-mall\照片.jpg' HERE = os.path.dirname(os.path.abspath(__file__)) img = imread_u(SRC) quad = detect_board_quad(img) warped = warp_board(img, quad) wh, ww = warped.shape[:2] gray = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY) hsv = cv2.cvtColor(warped, cv2.COLOR_BGR2HSV) S = hsv[:, :, 1].astype(np.float32) V = hsv[:, :, 2].astype(np.float32) # 局部纹理(box filter 标准差):过曝区颜色失效时靠纹理兜底 gf = gray.astype(np.float32) m1 = cv2.boxFilter(gf, -1, (9, 9)) m2 = cv2.boxFilter(gf * gf, -1, (9, 9)) STD = np.sqrt(np.maximum(m2 - m1 * m1, 0)) def build_mask(s_th, v_th, t_th, close_k, open_k): mask = (((S > s_th) | (V < v_th) | (STD > t_th)).astype(np.uint8)) * 255 mask[:60, :] = 0 mask[-60:, :] = 0 mask[:, :60] = 0 mask[:, -60:] = 0 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((close_k, close_k), np.uint8)) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((open_k, open_k), np.uint8)) return mask def row_counts(mask): n, labels, stats, cents = cv2.connectedComponentsWithStats(mask, 8) blocks = [] for i in range(1, n): x, y, bw, bh, area = stats[i] cx, cy = cents[i] if area < 8000 or bw < 100 or bh < 80 or bw > 0.35 * ww or bh > 0.25 * wh: continue if cy < 0.17 * wh or cx < 0.06 * ww: continue blocks.append((cy, cx, x, y, bw, bh, area)) blocks.sort() rows = [] for b in blocks: if rows and abs(b[0] - rows[-1][-1][0]) < 60: rows[-1].append(b) else: rows.append([b]) return [len(r) for r in rows], blocks, rows combos = [ (45, 140, 999, 9, 7), # 旧参数(仅颜色) (30, 170, 12, 21, 9), (25, 180, 10, 25, 11), (25, 180, 14, 25, 13), (20, 190, 12, 29, 13), (30, 170, 16, 21, 11), ] best = None for c in combos: mask = build_mask(*c) counts, blocks, rows = row_counts(mask) print(c, '->', counts) if counts == [11, 11, 10, 11, 11, 11, 11]: best = (c, mask, rows) break if best: c, mask, rows = best scale = 1600.0 / ww vis = cv2.resize(warped, (1600, int(wh * scale))).copy() for r in rows: for (cy, cx, x, y, bw, bh, area) in r: cv2.rectangle(vis, (int(x * scale), int(y * scale)), (int((x + bw) * scale), int((y + bh) * scale)), (0, 255, 0), 2) imwrite_u(os.path.join(HERE, 'blocks_preview.jpg'), vis) imwrite_u(os.path.join(HERE, 'mask_preview.jpg'), cv2.resize(mask, (1600, int(wh * scale)))) print('BEST', c) else: print('无完美组合,取最后一组出预览') mask = build_mask(*combos[-1]) counts, blocks, rows = row_counts(mask) scale = 1600.0 / ww vis = cv2.resize(warped, (1600, int(wh * scale))).copy() for r in rows: for (cy, cx, x, y, bw, bh, area) in r: cv2.rectangle(vis, (int(x * scale), int(y * scale)), (int((x + bw) * scale), int((y + bh) * scale)), (0, 255, 0), 2) imwrite_u(os.path.join(HERE, 'blocks_preview.jpg'), vis) imwrite_u(os.path.join(HERE, 'mask_preview.jpg'), cv2.resize(mask, (1600, int(wh * scale))))