如何用两帧图像正确计算 Geometry Dash 障碍物速度?
你把同一张差分图中两个矩形的横坐标差当成了两帧之间的位移,所以速度算错了。moving_rects[0] 和 moving_rects[1] 是差分图中检测到的两个区域,并不分别代表第一帧和第二帧里的同一个尖刺。因此,abs(moving_rects[0][0] - moving_rects[1][0]) 不能直接用于计算速度。
按两帧位置计算速度
先分别检测两帧中的目标,并确认两个矩形对应同一个障碍物。然后计算它的位置变化,再除以两次采集的实际时间间隔。障碍物向左移动时,通常用 x1 - x2 得到正的速度值;如果只关心速度大小,可以取绝对值。
import time
import cv2
import numpy as np
# mss 截图通常包含 BGRA 通道
frame1 = np.array(sct.grab(screen_region))
t1 = time.perf_counter()
time.sleep(0.1)
frame2 = np.array(sct.grab(screen_region))
t2 = time.perf_counter()
dt = t2 - t1
# 示例:分别处理两帧。阈值和筛选条件需按实际游戏画面调整。
def find_rects(frame):
gray = cv2.cvtColor(frame, cv2.COLOR_BGRA2GRAY)
_, binary = cv2.threshold(gray, 30, 255, cv2.THRESH_BINARY_INV)
contours, _ = cv2.findContours(
binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
rects = []
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
if w >= 30 and h >= 30 and w <= 200:
rects.append((x, y, w, h))
return rects
rects1 = find_rects(frame1)
rects2 = find_rects(frame2)
# 先按画面特征匹配两帧中的同一个尖刺,得到 r1 和 r2。
# 例如可结合 y、w、h 与相邻目标的距离进行筛选;不要直接取列表中的前两项。
r1 = ... # 第一帧中目标尖刺的 (x, y, w, h)
r2 = ... # 第二帧中同一尖刺的 (x, y, w, h)
x1 = r1[0] + r1[2] / 2
x2 = r2[0] + r2[2] / 2
speed = abs(x2 - x1) / dt
print(speed)
... 需要根据实际检测结果填写,或替换为匹配逻辑。OpenCV 不保证轮廓的返回顺序,因此不能假设 rects1[0] 和 rects2[0] 是同一个目标。可以先按横坐标排序,再结合矩形的纵坐标、宽高和相邻目标关系进行匹配。如果画面中有多个移动区域,也要先筛出尖刺,再计算位置变化。
为什么差分矩形不能直接表示速度
cv2.absdiff(frame1, frame2) 标出的是两帧之间发生变化的像素。物体向左移动后,差分结果可能同时留下原位置和新位置的区域,也可能因背景、边缘或其他画面变化形成多个轮廓。差分轮廓的坐标不是两帧各自检测到的目标坐标,因此它们之间的距离不一定等于目标位移,方向也可能与目标移动方向无关。
grab_elapsed 包含截图调用和 sleep 的耗时,应使用实际测得的时间间隔。测量短时间间隔时,可以用 time.perf_counter()。还要检查 mss 截图的通道数:数组为 BGRA 时使用 cv2.COLOR_BGRA2GRAY;已是 BGR 时才使用 cv2.COLOR_BGR2GRAY。
距离和跳跃延迟也要对应正确的目标
play_rects[0] 和 play_rects[1] 不一定分别是玩家和尖刺。应根据位置和尺寸识别玩家及其前方的尖刺,再计算两者的水平间距。直接用两个矩形左边缘的差值可能会算错距离,通常应计算玩家右边缘到尖刺左边缘的间距。
确认速度、距离和计时都正确后,可以用 distance / speed 估算障碍物到达玩家位置的时间,再扣除检测和处理耗时。这个估算假设障碍物在这段时间内近似匀速;实际触发时机还会受跳跃动作和游戏碰撞判定影响,需要根据画面观察调整。你当前代码中的 processing_time 从采集第三帧之前开始计时,因此包含采集和处理时间。计算剩余等待时间时,要确保距离对应的时刻与这段耗时的起点一致。
备注:内容仅供参考。
