MCPcopy
hub / github.com/sonofmagic/weapp-tailwindcss / detect_sun_code_shape

Function detect_sun_code_shape

scripts/scan-wechat-qrcode.py:70–136  ·  view source on GitHub ↗

识别微信小程序太阳码的图形特征,不依赖文本解码。

(cv2, image)

Source from the content-addressed store, hash-verified

68
69
70def detect_sun_code_shape(cv2, image) -> tuple[bool, dict]:
71 """识别微信小程序太阳码的图形特征,不依赖文本解码。"""
72
73 height, width = image.shape[:2]
74 max_side = max(width, height)
75 scale = 560 / max_side if max_side > 560 else 1
76 if scale != 1:
77 image = cv2.resize(image, (round(width * scale), round(height * scale)), interpolation=cv2.INTER_AREA)
78
79 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
80 blurred = cv2.GaussianBlur(gray, (3, 3), 0)
81 _, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
82
83 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
84 image_area = binary.shape[0] * binary.shape[1]
85 center_x = binary.shape[1] / 2
86 center_y = binary.shape[0] / 2
87 small_components = 0
88 radial_components = 0
89 finder_rings = 0
90 dark_area = int(cv2.countNonZero(binary))
91
92 for contour in contours:
93 area = cv2.contourArea(contour)
94 if area < image_area * 0.00005 or area > image_area * 0.16:
95 continue
96
97 x, y, w, h = cv2.boundingRect(contour)
98 ratio = w / max(h, 1)
99 fill = area / max(w * h, 1)
100 component_center_x = x + w / 2
101 component_center_y = y + h / 2
102 distance_to_center = ((component_center_x - center_x) ** 2 + (component_center_y - center_y) ** 2) ** 0.5
103 radius_ratio = distance_to_center / max(min(binary.shape[:2]) / 2, 1)
104
105 if 0.45 <= ratio <= 2.25 and 0.08 <= fill <= 0.82:
106 small_components += 1
107
108 if radius_ratio >= 0.2 and 0.18 <= fill <= 0.72 and (ratio >= 1.65 or ratio <= 0.62):
109 radial_components += 1
110
111 perimeter = cv2.arcLength(contour, True)
112 if perimeter <= 0:
113 continue
114 circularity = 4 * 3.141592653589793 * area / (perimeter * perimeter)
115 if 0.72 <= ratio <= 1.28 and 0.24 <= fill <= 0.64 and circularity >= 0.42 and area >= image_area * 0.002:
116 finder_rings += 1
117
118 density = dark_area / image_area
119 aspect_ratio = width / height
120 aspect_score = clamp(1 - abs(aspect_ratio - 1) / 0.38, 0, 1)
121 density_score = 1 if 0.035 <= density <= 0.42 else 0
122 component_score = clamp(small_components / 80, 0, 1)
123 radial_score = clamp(radial_components / 28, 0, 1)
124 finder_score = clamp(finder_rings / 3, 0, 1)
125 score = aspect_score * 24 + density_score * 12 + component_score * 22 + radial_score * 24 + finder_score * 18
126
127 details = {

Callers 1

mainFunction · 0.85

Calls 2

clampFunction · 0.70
roundFunction · 0.50

Tested by

no test coverage detected