首先建议大家不要走到这一步,最好是开发那边可以提供一些方法,如构建项目时预埋入相应代码或者打包时可以把广告模块独立关闭。
继续往下看的大家相信都是逼不得已,需要上按钮识别关闭的功能了。
设计思路-四层过滤
- 第一层先使用控件过滤。如果关闭按钮是可识别的控件,一定要优先使用这个稳定办法。我这边IOS自动化框架使用的Airtest,在AirtestIDE中选中关闭按钮获取名字,使用poco来定位关闭。
python
if poco("xxx_close").exists():
poco("xxx_close").click()
-
第二层使用CV检测算法。这里核心思路是
- 实现一个可以判断当前界面是否有广告的方法 has_ad(),可以使用目前软件的一些特征比如核心按钮是否可见,核心检测用例是不是能跑通来判断
- 实现find_ad(),给出预测的坐标列表,然后循环点击这个列表,点击后调用has_ad()判断是否成功,这样可以多次试错
- find_ad()中可以并行使用多种算法检测,最后统一打分,排序,按打分高低返回列表。
- 按照经验选择高概率区域搜索,如果所有的候选都无法关闭广告,再降级再低概率区域搜索。
-
第三层可以自己训练一个volon11这种轻量级的本地模型,进行兜底识别
-
最最后一层,上面都不行,上一个千问之类的拥有多模态api调用能力的大模型,直接上传截图并且询问关闭按钮坐标,这个得花钱,看预算了。
这里详细说下CV的思路
一、整体定位
这是一个 基于 OpenCV 的 iOS 广告关闭按钮自动检测模块,运行在 Airtest 自动化框架之上,用于在 iOS 设备上自动识别并点击插屏广告的关闭按钮(X 形状、半透明圆形底座)。
核心挑战:广告关闭按钮样式多样按钮半透明、背景复杂,传统图像匹配难以覆盖。
二、核心逻辑流程
第1步:搜索区域确定(三级策略)
通过
| 优先级 | 条件 | 搜索区域 |
|---|---|---|
| 主搜索 | 找到"广告"等标志性按钮 | 观察关闭和标志按钮的相对位置,圈定主搜索区 |
| 降级搜索 | 无标志性按钮(primary 阶段) | 四角覆盖:右上角 + 右侧中部 + 左下角 + 右下角 |
| 扩展搜索 | 无标志性按钮(secondary 阶段) | 顶部中间 + 左侧上部 |
第2步:双路径并行检测
路径A --- "先圆后X"检测(观察广告形态,如果大部分是圆形边框+中间x,采用这种检测)
- 评估背景复杂度 → 选择检测参数(标准/增强模式)
- CLAHE 对比度增强 + 高斯模糊
HoughCircles检测圆形候选- 对每个圆形:亚像素精化 → X图案验证 → 亮度验证 → 连续性验证
- 综合评分,取 Top3 候选
路径B --- "多通道投票纯X"检测 (有些广告只有x按钮,直接检测交叉点,附加一些角度,线段到中心点长度相等,这种条件过滤,并且在四个颜色通道同时检测,投票选出最有可能的交点)
- R/G/B/Gray 四通道独立检测
- 每通道:边缘提取 → HoughLinesP → 角度过滤(45°/135°±15°) → 交叉点计算
- 多通道位置投票:中位数定位 + 加权平均精化
- 输出置信度
第3步:候选评分与融合
对每条路径的候选计算综合得分:
| 场景 | 评分公式 |
|---|---|
| 有标志性按钮 | combined = CV得分 × 0.30 + 上下文 × 0.30 + 标志性按钮对齐得分 × 0.40 |
| 无标志性按钮 | combined = CV得分 × 0.50 + 上下文 × 0.50 |
标志性按钮对齐得分 :根据观察关闭和标志按钮的相对位置,越符合这个相对位置的,打分越高(max(0, 1 - distance/80px))
第4步:兜底策略
如果 CV 检测全部失败,且存在标志性按钮,则直接推算关闭按钮位置作为备选。
三、关键算法详解
算法1:背景复杂度自适应(路径A )
搜索圆形按钮背景的一些参数
| 指标 | (复杂) | (简单) |
|---|---|---|
| 边缘密度 | > 0.08 | < 0.04 |
| HSV 饱和度标准差 | > 50 | < 30 |
自适应参数调整:
| 参数 | 标准模式 | 增强模式 |
|---|---|---|
| HoughCircles param2 | 18 | 25(更严格) |
| minRadius | 12 | 15(拒绝小假圆) |
| 高斯模糊核 | (5,5) | (7,7) |
| 圆周连续性验证 | 关闭 | 开启 |
| 最低得分阈值 | 0.25 | 0.30 |
算法2:亚像素圆心精化(路径A )
在 HoughCircles 检测到的圆周围提取边缘点,用代数最小二乘法重新拟合圆心:
圆方程: (x-a)² + (y-b)² = r²
展开为线性方程: Ax + By + C = -(x² + y²)
最小二乘求解 → 精化圆心 (a, b)
安全机制:精化偏移 > 半径50% 时回退到原始中心
算法3:多通道投票机制(路径B )
R通道 → 边缘 → 直线 → 交叉点中心 → 候选位置1
G通道 → 边缘 → 直线 → 交叉点中心 → 候选位置2
B通道 → 边缘 → 直线 → 交叉点中心 → 候选位置3
Gray通道 → 边缘 → 直线 → 交叉点中心 → 候选位置4
↓
中位数计算 → 距离过滤 → 加权平均
↓
最终位置 + 置信度
置信度计算 :confidence = min(1.0, 通道通过率 × 0.6 + 交叉点集中度 × 0.4)
算法4:上下文验证 (最后的打分算法)
在候选位置 80×80 窗口内验证三个指标:
| 指标 | 权重 | 真按钮特征 | 假阳性特征 |
|---|---|---|---|
| 圆形边缘存在性 | 0.45 | 覆盖率 > 0.15 | 覆盖率 < 0.05 |
| X亮度对比度 | 0.35 | ratio > 1.3(白X vs 灰底) | ratio ≈ 1.0 |
| 圆内背景均匀度 | 0.20 | std < 30 | std > 50 |
四、重要参数汇总
关闭按钮几何参数
- 理想圆形半径:30px(直径 60px)
- 可接受半径范围:15-45px
- 评分加成半径:22-38px(+0.5分)
边缘检测参数
- Canny 阈值:high(50,150) / mid(30,100) / low(20,60)
- CLAHE:clipLimit=5.0, tileGridSize=(8,8)
霍夫变换参数
- HoughCircles:dp=1, minDist=30, param1=50, maxRadius=45
- HoughLinesP:threshold=20, minLineLength=17, maxLineGap=5
角度过滤
- X形状角度:45° / 135° / -45° / -135°,容差 ±15°
搜索区域
- 主搜索区:X(0.90-1.00), Y(标志按钮相对位置±0.05)
- 降级区域:四角各 15% 屏幕范围
评分权重
- 圆形+X检测(正常背景):圆形×0.3 + X×0.4 + 亮度×0.3
- 圆形+X检测(复杂背景):圆形×0.2 + X×0.3 + 亮度×0.2 + 连续性×0.3
- 综合评分(有对齐):CV×0.30 + 上下文×0.30 + 对齐×0.40
- 综合评分(无对齐):CV×0.50 + 上下文×0.50
六、调用方法
python
candidates = find_ad(channel='auto', threshold='high', search_phase='primary')
if candidates:
for candidate in candidates:
touch(candidate['position'])
if not has_ad():
return
else:
log(f"[主搜索]CV检测点击未关闭广告,尝试下一个候选")
# 阶段2: 扩展搜索 主搜索全部失败后直接执行
candidates_ext = find_ad(channel='auto', threshold='high', search_phase='extended')
if candidates_ext:
for candidate_ext in candidates_ext:
touch(candidate_ext['position'])
if not has_ad():
return
else:
log(f"[扩展搜索]CV检测点击未关闭广告,尝试下一个候选")