'commit'
This commit is contained in:
@@ -151,11 +151,11 @@ def detect_price_click_point_cv(image_path):
|
||||
|
||||
return [center_x, center_y]
|
||||
|
||||
def detect_cards_cv(image_path, top_ratio=0.40, bottom_ratio=0.12):
|
||||
"""
|
||||
使用计算机图形学 (OpenCV) 检测列表中的场站卡片。
|
||||
"""
|
||||
from Apps.TeLaiDian.Config.Setting import MIN_CARD_HEIGHT
|
||||
def detect_cards_cv(image_path, top_ratio=0.40, bottom_ratio=0.12):
|
||||
"""
|
||||
使用计算机图形学 (OpenCV) 检测列表中的场站卡片。
|
||||
"""
|
||||
from Apps.TeLaiDian.Config.Setting import MIN_CARD_HEIGHT
|
||||
|
||||
img = read_image(image_path)
|
||||
if img is None:
|
||||
@@ -183,24 +183,38 @@ def detect_cards_cv(image_path, top_ratio=0.40, bottom_ratio=0.12):
|
||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
|
||||
cards = []
|
||||
# 降低最小宽度要求,有些卡片边缘可能没完全闭合
|
||||
min_card_width = int(w * 0.6)
|
||||
# 更严格的最小宽度要求:列表卡片通常接近整宽
|
||||
min_card_width = int(w * 0.8)
|
||||
|
||||
temp_boxes = []
|
||||
for cnt in contours:
|
||||
x, y, cw, ch = cv2.boundingRect(cnt)
|
||||
center_y = y + ch // 2
|
||||
|
||||
# 增加最小高度验证 MIN_CARD_HEIGHT
|
||||
if (cw > min_card_width and
|
||||
ch > MIN_CARD_HEIGHT * 0.8 and # 稍微放宽高度限制
|
||||
y > top_limit and
|
||||
y + ch < bottom_limit):
|
||||
|
||||
logger.info(f"✅ 找到候选卡片: y={y}, h={ch}, w={cw}")
|
||||
# 绿色营销券区域排除
|
||||
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
||||
roi = hsv[max(0,y):min(h,y+ch), max(0,x):min(w,x+cw)]
|
||||
green_mask = cv2.inRange(roi, np.array([35, 80, 80]), np.array([85, 255, 255]))
|
||||
green_ratio = float(cv2.countNonZero(green_mask)) / (roi.shape[0]*roi.shape[1]) if roi.size > 0 else 0.0
|
||||
|
||||
# 圆角矩形判断:面积占比与顶点数量
|
||||
rect_area = cw * ch
|
||||
cnt_area = cv2.contourArea(cnt)
|
||||
extent = cnt_area / rect_area if rect_area > 0 else 0
|
||||
approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
|
||||
|
||||
ok_width = cw >= min_card_width
|
||||
ok_height = ch > MIN_CARD_HEIGHT * 0.8
|
||||
ok_vertical = center_y >= int(h * 0.58) and y > top_limit and y + ch < bottom_limit
|
||||
ok_shape = (len(approx) >= 6 or extent > 0.85)
|
||||
ok_color = green_ratio < 0.25
|
||||
|
||||
if ok_width and ok_height and ok_vertical and ok_shape and ok_color:
|
||||
logger.info(f"✅ 找到候选卡片: y={y}, h={ch}, w={cw}, extent={extent:.2f}, verts={len(approx)}, green={green_ratio:.2f}")
|
||||
temp_boxes.append((x, y, cw, ch))
|
||||
else:
|
||||
if cw > min_card_width:
|
||||
logger.debug(f"❌ 排除候选(不符条件): y={y}, h={ch}, w={cw} (limit: {top_limit}-{bottom_limit}, min_h: {MIN_CARD_HEIGHT*0.8})")
|
||||
if ok_width:
|
||||
logger.debug(f"❌ 排除候选: y={y}, h={ch}, w={cw}, extent={extent:.2f}, verts={len(approx)}, green={green_ratio:.2f} (limit: {top_limit}-{bottom_limit})")
|
||||
|
||||
if not temp_boxes:
|
||||
logger.warning(f"⚠️ CV 未能在指定范围 ({top_limit}-{bottom_limit}) 内检测到任何场站卡片")
|
||||
@@ -226,46 +240,46 @@ def detect_cards_cv(image_path, top_ratio=0.40, bottom_ratio=0.12):
|
||||
min(w, x + cw - padding),
|
||||
min(bottom_limit, y + ch - padding)
|
||||
])
|
||||
|
||||
return cards
|
||||
|
||||
def detect_wide_rounded_card_cv(image_path, min_width_ratio=0.8, min_y_ratio=0.5):
|
||||
img = read_image(image_path)
|
||||
if img is None:
|
||||
return []
|
||||
h, w = img.shape[:2]
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
blur = cv2.GaussianBlur(gray, (7, 7), 0)
|
||||
edges = cv2.Canny(blur, 60, 180)
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
|
||||
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
|
||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
results = []
|
||||
for cnt in contours:
|
||||
x, y, cw, ch = cv2.boundingRect(cnt)
|
||||
center_y = y + ch // 2
|
||||
if cw < int(w * min_width_ratio):
|
||||
continue
|
||||
if center_y < int(h * min_y_ratio):
|
||||
continue
|
||||
rect_area = cw * ch
|
||||
cnt_area = cv2.contourArea(cnt)
|
||||
if rect_area <= 0:
|
||||
continue
|
||||
extent = cnt_area / rect_area
|
||||
approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
|
||||
if extent < 0.7:
|
||||
continue
|
||||
if len(approx) >= 6 or (len(approx) == 4 and extent > 0.85):
|
||||
results.append([x, y, x + cw, y + ch])
|
||||
results.sort(key=lambda b: b[1])
|
||||
return results
|
||||
|
||||
def draw_rectangles(image_path, bboxes=None, click_points=None):
|
||||
"""
|
||||
使用 OpenCV 在图片上绘制矩形框和点击点,生成 _vl.jpg 和 _flag.jpg
|
||||
- _vl.jpg: 仅包含矩形框,供视觉模型参考
|
||||
- _flag.jpg: 包含矩形框和点击点,供人工调试
|
||||
|
||||
return cards
|
||||
|
||||
def detect_wide_rounded_card_cv(image_path, min_width_ratio=0.8, min_y_ratio=0.5):
|
||||
img = read_image(image_path)
|
||||
if img is None:
|
||||
return []
|
||||
h, w = img.shape[:2]
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
blur = cv2.GaussianBlur(gray, (7, 7), 0)
|
||||
edges = cv2.Canny(blur, 60, 180)
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
|
||||
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
|
||||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||
results = []
|
||||
for cnt in contours:
|
||||
x, y, cw, ch = cv2.boundingRect(cnt)
|
||||
center_y = y + ch // 2
|
||||
if cw < int(w * min_width_ratio):
|
||||
continue
|
||||
if center_y < int(h * min_y_ratio):
|
||||
continue
|
||||
rect_area = cw * ch
|
||||
cnt_area = cv2.contourArea(cnt)
|
||||
if rect_area <= 0:
|
||||
continue
|
||||
extent = cnt_area / rect_area
|
||||
approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
|
||||
if extent < 0.7:
|
||||
continue
|
||||
if len(approx) >= 6 or (len(approx) == 4 and extent > 0.85):
|
||||
results.append([x, y, x + cw, y + ch])
|
||||
results.sort(key=lambda b: b[1])
|
||||
return results
|
||||
|
||||
def draw_rectangles(image_path, bboxes=None, click_points=None):
|
||||
"""
|
||||
使用 OpenCV 在图片上绘制矩形框和点击点,生成 _vl.jpg 和 _flag.jpg
|
||||
- _vl.jpg: 仅包含矩形框,供视觉模型参考
|
||||
- _flag.jpg: 包含矩形框和点击点,供人工调试
|
||||
"""
|
||||
try:
|
||||
DEBUG_BOX_COLOR = (0, 255, 0) # 绿色矩形
|
||||
|
||||
Reference in New Issue
Block a user