You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

视频捕获中颜色过渡检测故障:白线跨黄绿区域单次打印失效

问题描述

我正在做一个项目,需要追踪一条从黄色区域延伸到绿色区域的白线,当白线穿过颜色交界点时,希望只打印一次"Perfect"。我写了下面的代码,但没实现预期效果;试过用像素计数器检测帧间颜色变化,也没用。

import cv2
import numpy as np
import time

# 指定HSV格式下要检测的颜色上下限
lower = np.array([35, 100, 140])
upper = np.array([70, 255, 255]) # 这个范围用来检测黄色

# 捕获摄像头画面
cap = cv2.VideoCapture(0)

prev_count = 0
curr_count = 0
frame_count = 0
perfect_printed = False
last_perfect_time = 0

while True:
    success, video = cap.read() # 读取摄像头画面

    img = cv2.cvtColor(video, cv2.COLOR_BGR2HSV) # 将BGR图像转换为HSV格式

    mask = cv2.inRange(img, lower, upper) # 对图像做掩码,筛选目标颜色

    mask_contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 在掩码图像中查找轮廓

    # 查找所有轮廓的位置
    if len(mask_contours) != 0:
        for mask_contour in mask_contours:
            area = cv2.contourArea(mask_contour)
            if area > 5 and area < 30:
                x, y, w, h = cv2.boundingRect(mask_contour)
                cv2.rectangle(video, (x, y), (x + w, y + h), (0, 0, 255), 1) # 绘制矩形框
                curr_count += area

    cv2.imshow("mask image", mask) # 显示掩码图像

    cv2.imshow("window", video) # 显示摄像头画面

    # 检测两帧内像素计数是否减少超过10
    if frame_count == 1:
        if (prev_count - curr_count) > 9 and not perfect_printed and time.time() - last_perfect_time > 2:
            print("Perfect")
            cv2.imwrite('perfect_screenshot.jpg', video)
            perfect_printed = True
            last_perfect_time = time.time()
        prev_count = curr_count
        curr_count = 0
        frame_count = 0
    else:
        frame_count += 1

    # 如果已经打印过,重置标记
    if perfect_printed:
        perfect_printed = False

    # 按下Esc键关闭窗口
    if cv2.waitKey(1) == 27:
        break

cap.release()
cv2.destroyAllWindows()

场景截图说明

  • 图片1:画面左侧为黄色区域,右侧为绿色区域,一条白线从黄色区域向绿色区域延伸,尚未到达交界点
  • 图片2:白线已穿过黄、绿区域的交界点,部分进入绿色区域
问题分析与修复

你的代码核心问题在于**perfect_printed标记被立即重置**——每次循环末尾都会把它设为False,导致即使触发了打印条件,下一次循环也会让标记失效;同时帧计数的逻辑依赖黄色区域的面积变化,稳定性差,无法准确捕捉白线跨越交界的瞬间。

以下是修复后的代码,核心改进点:

  1. 移除错误的perfect_printed强制重置逻辑,改用冷却时间控制标记重置
  2. 直接追踪白线的位置,通过预设的交界线判断跨越动作,比面积变化更精准
  3. 增加白色线条的检测逻辑,直接锁定目标白线
import cv2
import numpy as np
import time

# 黄色HSV范围(可根据实际场景微调)
lower_yellow = np.array([20, 100, 100])
upper_yellow = np.array([30, 255, 255])
# 绿色HSV范围
lower_green = np.array([40, 40, 40])
upper_green = np.array([70, 255, 255])

cap = cv2.VideoCapture(0)
# 定义交界线位置(默认取画面垂直中线,可根据实际场景调整)
border_x = None
# 标记是否已打印过Perfect
has_printed = False
# 记录白线之前的位置状态(True=在黄色区域,False=在绿色区域)
prev_line_in_yellow = None
# 记录上次触发时间,用于冷却
last_trigger_time = 0

while True:
    success, frame = cap.read()
    if not success:
        break

    # 第一次读取画面时初始化交界线
    if border_x is None:
        border_x = frame.shape[1] // 2
        cv2.line(frame, (border_x, 0), (border_x, frame.shape[0]), (255, 0, 0), 2)

    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # 检测白色线条的HSV范围
    lower_white = np.array([0, 0, 200])
    upper_white = np.array([180, 25, 255])
    white_mask = cv2.inRange(hsv, lower_white, upper_white)

    # 提取白色线条的轮廓,取面积最大的作为目标白线
    contours, _ = cv2.findContours(white_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    current_line_in_yellow = None

    if contours:
        max_contour = max(contours, key=cv2.contourArea)
        x, y, w, h = cv2.boundingRect(max_contour)
        # 计算白线中心的x坐标,判断是否在黄色区域(交界线左侧)
        line_center_x = x + w // 2
        current_line_in_yellow = line_center_x < border_x

        # 绘制白线的包围框和中心标记
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
        cv2.circle(frame, (line_center_x, y+h//2), 3, (0, 0, 255), -1)

    # 判断是否完成跨越动作:之前在黄色区域,现在进入绿色区域,且未打印过
    if prev_line_in_yellow is not None and current_line_in_yellow is not None:
        if prev_line_in_yellow and not current_line_in_yellow and not has_printed:
            print("Perfect")
            cv2.imwrite('perfect_screenshot.jpg', frame)
            has_printed = True
            last_trigger_time = time.time()

        # 冷却2秒后重置标记,允许下次触发
        if has_printed and time.time() - last_trigger_time > 2:
            has_printed = False

    prev_line_in_yellow = current_line_in_yellow

    cv2.imshow("White Line Tracking", frame)
    cv2.imshow("White Mask", white_mask)

    # 按下Esc键退出
    if cv2.waitKey(1) == 27:
        break

cap.release()
cv2.destroyAllWindows()

关键修复说明

  • 直接追踪白线的中心位置,通过交界线判断跨越动作,避免了原代码依赖黄色区域面积变化的不稳定问题
  • 用冷却时间控制has_printed标记的重置,确保单次跨越只触发一次"Perfect"打印
  • 增加白色线条检测,直接锁定目标追踪对象,逻辑更清晰

内容的提问来源于stack exchange,提问作者Learning2code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:37:03