fix: 修复批量下载漏检测稀疏行和底部半行
根因: 1. std 横向采样区 x=350-1050 不覆盖左列卡片(中心x=201), 导致只有左列有卡片的稀疏行 std 被拉低到27,低于阈值28被误判为间隙 2. 扫描范围 ROW_Y1=2300 太靠上,底部半行被边缘过滤 3. 每轮只处理前3行(full_rows[:3]),后续行即使检测到也被跳过 修复: - ROW_STD_X0 350→50, ROW_STD_W 700→980(覆盖全部3列) - ROW_STD_LOW 28→18(分组标签std=0不会误判) - ROW_Y1 2300→2380(扩大底部扫描范围) - 处理所有检测到的行,未打勾格子最多取前9个避免超并发
This commit is contained in:
+13
-15
@@ -53,10 +53,10 @@ BLUE_THRESHOLD = 500 # 窗口内强蓝像素数 >= 此值判为已打勾(打
|
|||||||
# 导致点击/打勾检测全部错位、把已下载卡片误判为未下载重复点击。改为每屏用亮度标准差
|
# 导致点击/打勾检测全部错位、把已下载卡片误判为未下载重复点击。改为每屏用亮度标准差
|
||||||
# (std) 垂直剖面实测出真实的卡片行中心 Y:卡片缩略图有纹理 std 高,卡片间隙/分组标签/
|
# (std) 垂直剖面实测出真实的卡片行中心 Y:卡片缩略图有纹理 std 高,卡片间隙/分组标签/
|
||||||
# 灰占位是纯色 std≈0,据此切出"纹理带",每个带的竖直中心就是一行卡片的点击中心。
|
# 灰占位是纯色 std≈0,据此切出"纹理带",每个带的竖直中心就是一行卡片的点击中心。
|
||||||
ROW_Y0, ROW_Y1 = 1000, 2300 # 列表纵向扫描范围(避开顶部状态栏/预览/标题栏、底部手势条)
|
ROW_Y0, ROW_Y1 = 1000, 2380 # 列表纵向扫描范围(避开顶部状态栏/预览/标题栏、底部手势条)
|
||||||
ROW_STD_X0, ROW_STD_W = 350, 700 # 横向 std 采样区(避开左右圆角/阴影)
|
ROW_STD_X0, ROW_STD_W = 50, 980 # 横向 std 采样区(避开左右圆角/阴影)
|
||||||
ROW_STD_COLS = 175 # 降采样列数(Pillow 一次折成每行 175 个样本算 std,避免逐行上百次采样)
|
ROW_STD_COLS = 200 # 降采样列数(Pillow 一次折成每行 175 个样本算 std,避免逐行上百次采样)
|
||||||
ROW_STD_LOW = 28 # std 阈值:>= 判为卡片纹理,< 判为间隙/标签/占位(实测卡片≥46、非卡片=0,余量足)
|
ROW_STD_LOW = 18 # std 阈值:>= 判为卡片纹理,< 判为间隙/标签/占位(实测卡片≥46、非卡片=0,余量足)
|
||||||
ROW_MIN_H = 90 # 纹理带最小高度(滤掉分组标签、半截卡片、噪声)
|
ROW_MIN_H = 90 # 纹理带最小高度(滤掉分组标签、半截卡片、噪声)
|
||||||
ROW_MAX_H = 260 # 纹理带最大高度(超过视为两行粘连,按行距二次切分)
|
ROW_MAX_H = 260 # 纹理带最大高度(超过视为两行粘连,按行距二次切分)
|
||||||
ROW_PITCH = 204 # 相邻卡片行的竖直间距(用于粘连带二次切分)
|
ROW_PITCH = 204 # 相邻卡片行的竖直间距(用于粘连带二次切分)
|
||||||
@@ -707,25 +707,23 @@ def tap_all_thumbnails(baseline, max_rounds=300, poll_interval=4, max_wait_per_r
|
|||||||
# 仍未打勾,被反复重点,实测会让"跳过已打勾"退化成 0、重复率回升。多出的行
|
# 仍未打勾,被反复重点,实测会让"跳过已打勾"退化成 0、重复率回升。多出的行
|
||||||
# 下一轮滚上来再处理(滚动量≈2 行,正好衔接),不会漏。full_rows 保留全部行,
|
# 下一轮滚上来再处理(滚动量≈2 行,正好衔接),不会漏。full_rows 保留全部行,
|
||||||
# 供到底判定和到底清扫复用(省一次滚动前的重复截图+检测)。
|
# 供到底判定和到底清扫复用(省一次滚动前的重复截图+检测)。
|
||||||
row_centers = full_rows[:3]
|
row_centers = full_rows # 处理所有检测到的行,下面按未打勾数截断到9个
|
||||||
checked = get_checked_cells_dynamic(grid_shot, row_centers)
|
checked = get_checked_cells_dynamic(grid_shot, row_centers)
|
||||||
|
|
||||||
# 跳过已经打勾(下载完成)的卡片。滚动留的 1~2 行重叠滚上来时必然已是打勾
|
# 跳过已经打勾(下载完成)的卡片。滚动留的 1~2 行重叠滚上来时必然已是打勾
|
||||||
# 状态(本轮末尾"等全部点击的卡片打勾再滚动"保证),所以重叠行天然被跳过,
|
# 状态(本轮末尾"等全部点击的卡片打勾再滚动"保证),所以重叠行天然被跳过,
|
||||||
# 不会被当成新卡片重复触发下载——现在行中心是动态对准的,这个跳过才可靠。
|
# 不会被当成新卡片重复触发下载——现在行中心是动态对准的,这个跳过才可靠。
|
||||||
badge_skipped = sum(1 for cy in row_centers for gx in THUMB_X if checked.get((gx, cy)))
|
badge_skipped = sum(1 for cy in row_centers for gx in THUMB_X if checked.get((gx, cy)))
|
||||||
tapped_cells = []
|
# 收集所有未打勾格子(从上到下),最多9个避免超并发
|
||||||
for cy in row_centers:
|
todo_cells = [(gx, cy) for cy in row_centers for gx in THUMB_X if not checked.get((gx, cy))]
|
||||||
for gx in THUMB_X:
|
tapped_cells = todo_cells[:9]
|
||||||
if checked.get((gx, cy)):
|
for (gx, cy) in tapped_cells:
|
||||||
continue
|
adb("shell", "input", "tap", str(gx), str(cy))
|
||||||
tapped_cells.append((gx, cy))
|
time.sleep(0.5)
|
||||||
|
if not dialog_dismissed and dismiss_dialog_if_any():
|
||||||
|
dialog_dismissed = True
|
||||||
adb("shell", "input", "tap", str(gx), str(cy))
|
adb("shell", "input", "tap", str(gx), str(cy))
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
if not dialog_dismissed and dismiss_dialog_if_any():
|
|
||||||
dialog_dismissed = True
|
|
||||||
adb("shell", "input", "tap", str(gx), str(cy))
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
print(f" 轮 {r+1}: 检出 {len(row_centers)} 行,跳过已打勾 {badge_skipped} 个,点击待下载 {len(tapped_cells)} 个")
|
print(f" 轮 {r+1}: 检出 {len(row_centers)} 行,跳过已打勾 {badge_skipped} 个,点击待下载 {len(tapped_cells)} 个")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user