This commit is contained in:
HuangHai
2026-01-14 07:47:48 +08:00
parent 77f5e80857
commit b0d7afe420
7 changed files with 110 additions and 31 deletions

View File

@@ -93,56 +93,72 @@ def save_image(path, img):
logger.error(f"Error saving image {path}: {e}")
return False
def detect_cards_cv(image_path, top_ratio=0.15, bottom_ratio=0.1):
def detect_cards_cv(image_path, top_ratio=0.40, bottom_ratio=0.12):
"""
使用计算机图形学 (OpenCV) 检测列表中的场站卡片
使用计算机图形学 (OpenCV) 检测列表中的场站卡片。
"""
from Apps.TeLaiDian.Config.Setting import MIN_CARD_HEIGHT
img = read_image(image_path)
if img is None:
return []
h, w = img.shape[:2]
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 10, 50)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cards = []
min_card_width = int(w * 0.8)
min_card_height = 150
# 限制检测范围
top_limit = int(h * top_ratio)
bottom_limit = int(h * (1 - bottom_ratio))
valid_contours = []
# 使用自适应阈值
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
# 闭运算:连接断开的边缘
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (w // 2, 1))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# 寻找轮廓
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cards = []
min_card_width = int(w * 0.7)
temp_boxes = []
for cnt in contours:
x, y, cw, ch = cv2.boundingRect(cnt)
# 增加最小高度验证 MIN_CARD_HEIGHT
if (cw > min_card_width and
ch > min_card_height and
ch > MIN_CARD_HEIGHT and
y > top_limit and
y + ch < bottom_limit):
center_y = y + ch // 2
is_duplicate = False
for vx, vy, vcw, vch in valid_contours:
v_center_y = vy + vch // 2
if abs(center_y - v_center_y) < 50:
is_duplicate = True
break
temp_boxes.append((x, y, cw, ch))
if not is_duplicate:
valid_contours.append((x, y, cw, ch))
padding = 5
cards.append([
max(0, x + padding),
max(0, y + padding),
max(0, x + cw - padding),
max(0, y + ch - padding)
])
# 按 Y 轴排序
temp_boxes.sort(key=lambda b: b[1])
cards.sort(key=lambda c: c[1])
# 再次过滤和去重
for i, box in enumerate(temp_boxes):
x, y, cw, ch = box
# 检查是否与已有的框重叠
is_duplicate = False
for v in cards:
if abs(y - v[1]) < 100: # 增加去重间距
is_duplicate = True
break
if not is_duplicate:
padding = 2
cards.append([
max(0, x + padding),
max(top_limit, y + padding),
min(w, x + cw - padding),
min(bottom_limit, y + ch - padding)
])
return cards
def draw_rectangles(image_path, points, output_path=None):