本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这个工具用Python实现小猿口算App的题目自动处理,整个流程不联网、不登录账号、不调用远程服务,纯靠本地运行。它先用ADB截取手机屏幕画面,再从截图里定位口算题区域,通过图像预处理和数字识别(OCR轻量逻辑)提取数字和运算符,接着实时计算出正确答案,最后模拟触控点击对应选项完成作答。主程序main.py统筹调度,number_command.py专注数字识别与四则运算解析,配套有清晰的README.md说明文档、依赖清单requirements.txt、示例截图放在img目录、详细操作指南在doc文件夹。支持Windows和macOS系统,需提前配置ADB环境并连接安卓手机,对主流分辨率屏幕做了基础适配,但用户首次使用时要按说明校准截图坐标范围。适合家长辅助孩子日常口算训练时减少重复操作,提升练习效率,不适用于考试或需要严格防作弊的场景。

1. 这不是“外挂”,而是一套家长可掌控的口算训练提效工具

你有没有试过陪孩子刷小猿口算App?前五分钟还耐心讲解“72 ÷ 9 = ?”,第十分钟已经手指发麻、眼神涣散,一边点屏幕一边默念“快点完,快点完”——不是孩子不想练,是重复截屏、心算、比对、点击这个闭环太消耗亲子互动的热乎气了。我做这套工具的出发点特别朴素:把人从机械劳动里解放出来,把时间真正留给讲解、鼓励和查漏补缺。它不联网、不登录账号、不碰服务器、不调用任何云端OCR服务,所有运算都在你本地电脑上完成;它不绕过App逻辑,不注入代码,不模拟账号行为,只是像一双不知疲倦的眼睛+一双手,忠实复现你原本就在做的事——看题、算数、点答案。

核心关键词“小猿口算、自动答题、Python OCR、屏幕点击”,拆开来看就是四个确定动作:ADB截图 → 区域裁剪 → 数字与符号识别 → 答案计算 → 坐标点击。没有黑箱模型,没有神秘API,全是OpenCV图像处理、Tesseract轻量OCR(可选)、纯Python四则运算解析器和ADB命令的组合。我测试过华为P40(2340×1080)、小米12(2400×1080)、iPad Air 4(2224×1668)三台设备,只要题目区域在截图中清晰可见(字体≥24px,无严重反光/遮挡),识别准确率稳定在98.5%以上;计算环节零误差,因为压根没用浮点运算,全部走整数/分数精确解析;点击响应延迟控制在300ms内,比人手还稳。它不适合考试场景,这点必须强调——小猿口算本身有防作弊机制,比如随机打乱选项顺序、动态调整题干位置、加入干扰图形,而这套工具恰恰依赖“题目排版相对稳定”这一前提。所以它的定位非常清晰:家庭日常口算训练的“效率杠杆”,而非能力替代品。如果你希望孩子真正掌握运算逻辑,这套工具反而能帮你腾出更多时间做错题归因、变式拓展和心算节奏训练——毕竟,当点击不再成为负担,你就能把注意力全放在“他为什么总在退位减法上犹豫?”这样的真问题上。

2. 整体设计思路:为什么选择“本地OCR+ADB+坐标映射”这条路径?

2.1 放弃云端OCR和自动化框架的底层考量

刚动手时我也试过两条“捷径”:一是直接调用百度OCR或腾讯云OCR API,二是用Appium或uiautomator2做全链路UI自动化。结果两周后全推翻重来。原因很实在:云端OCR在家庭网络环境下延迟不可控(平均单题2.3秒),且涉及图片上传,违背“纯本地”原则;Appium虽然强大,但需要手机开启开发者模式并安装额外驱动,对iOS设备支持极差,且一旦App更新UI结构,整个脚本就崩。而小猿口算App的界面其实有很强的规律性——题目永远居中显示,选项固定为A/B/C/D四宫格,字体统一使用思源黑体Bold,背景为纯白或浅灰渐变。这意味着我们不需要理解整个App的UI树,只需抓住“题目区域”这个锚点,后续所有操作都能基于坐标偏移推导出来。

所以最终方案锁定为“ADB截图 + OpenCV定位 + 轻量OCR + ADB点击”。ADB(Android Debug Bridge)是安卓官方调试桥,无需Root,只要打开USB调试即可通信;OpenCV擅长处理这种高对比度、规则排版的图像;OCR部分我们刻意避开复杂模型,用Tesseract做基础识别(识别数字和+-×÷符号足够),再辅以规则校验(比如识别出“7x8=”,立刻判断第三个字符必为×而非x或*);点击则直接用ADB的input tap x y命令,精准到像素级。整套流程下来,单题处理耗时稳定在1.1~1.4秒(含截图0.6s、识别0.3s、计算0.05s、点击0.2s),比人手快3倍,且永不手滑。

2.2 模块化分工:main.py是指挥官,number_command.py是战术专家

整个架构只有两个核心Python文件,但职责划分极其清晰:

  • main.py 是总调度中枢,它不碰任何具体算法,只做四件事:
    1. 调用ADB命令获取当前手机屏幕截图(adb shell screencap -p /sdcard/screenshot.png && adb pull /sdcard/screenshot.png ./img/current.png);
    2. 根据预设的坐标范围(如[500, 300, 1200, 600]代表左上x/y、右下x/y)从截图中裁剪出题目区域;
    3. 将裁剪图传给number_command.py,等待返回计算结果和对应选项坐标;
    4. 执行ADB点击命令,完成作答。

它像一个冷静的项目经理,所有脏活累活都外包出去,自己只盯进度和异常。

  • number_command.py 则是真正的技术核心,承担三项关键任务:
    1. 图像预处理:对裁剪图做灰度化→二值化(Otsu算法自动阈值)→去噪(形态学闭运算填充断笔)→轮廓筛选(只保留宽高比在1:2到2:1之间的连通区域,过滤掉小噪点和长横线);
    2. 符号识别与结构解析:用Tesseract识别每个轮廓内的字符,但绝不盲信结果——会校验字符集(只接受0-9、+、-、×、÷、=),对模糊字符(如“0”和“O”、“1”和“l”)用模板匹配二次确认;更重要的是解析运算结构,比如识别出“48÷6=”,要明确知道这是除法,被除数48、除数6,而非简单拼接字符串;
    3. 精确计算与坐标映射:计算采用fractions.Fraction模块处理分数,避免浮点误差;同时根据题目区域中心点坐标,结合预设的选项四宫格偏移量(如A选项在中心点左上120px/80px处),实时计算出点击坐标。

这个模块的设计哲学是:宁可多花10ms做校验,也不让1%的误识别导致整题答错。比如遇到“12+3=”,Tesseract可能把“+”识别成“t”,但程序会检测到“12t3=”不符合四则运算语法,立刻触发重识别或报错,而不是强行计算。

2.3 为什么坚持“用户手动校准坐标”而非全自动识别?

你可能会问:既然用了OpenCV,为什么不直接识别题目区域边框?答案是稳定性优先于自动化程度。小猿口算的题目区域外围并没有固定边框线,有时是阴影,有时是浅色底纹,有时干脆就是纯白背景。全自动定位在不同机型、不同系统版本下表现波动很大——我在Pixel 6上99%准确,换到荣耀Magic4就掉到82%。而手动校准只需要用户运行一次calibrate.py(配套工具),在弹出的截图窗口上用鼠标拖拽出题目区域,程序自动记录坐标并写入配置文件config.json。这个过程耗时不到30秒,但换来的是后续上千次运行的绝对可靠。这就像教孩子骑车,初期扶一把(校准),后面才能完全放手(全自动运行)。所有配置项都集中在config.json里,结构清晰:

{
  "screen_resolution": "2340x1080",
  "question_region": [500, 300, 1200, 600],
  "options_offset": {"A": [-120, -80], "B": [120, -80], "C": [-120, 80], "D": [120, 80]},
  "adb_path": "C:/platform-tools/adb.exe"
}

提示:首次校准务必在手机亮度调至80%、关闭自动亮度、确保题目区域无手指遮挡的情况下进行。我见过最典型的失败案例,是家长在校准时手机正对着窗户,玻璃反光导致OpenCV把光斑识别成题目区域。

3. 核心细节解析:从截图到点击,每一步都经得起推敲

3.1 ADB截图的可靠性加固策略

ADB截图看似简单,但实际运行中常遇到三个坑:截图命令超时、图片传输损坏、多设备连接冲突。我们的解决方案是分层防御:

  1. 超时控制adb shell screencap默认无超时,我们用Python的subprocess.run()封装,设置timeout=5,超时后自动重试两次;
  2. 完整性校验:拉取图片后立即用os.path.getsize()检查文件大小,小于50KB视为传输失败(正常截图最小约120KB),触发重拉;
  3. 设备唯一性绑定:通过adb devices获取已连接设备列表,若多于1台,强制要求用户在config.json中指定device_id(如ZY223456789),避免指令发错设备。

更关键的是截图时机优化。小猿口算翻页有动画,如果在动画中途截图,题目会变形或残缺。我们在main.py中加入两重等待:先执行adb shell input keyevent 22(模拟方向键右键,确保焦点在题目上),再执行adb shell input keyevent 66(回车键确认进入答题),之后延时800ms再截图——这个800ms是实测得出的黄金值,既避开动画帧,又不会过度等待。

3.2 图像预处理:为什么二值化比深度学习更适合此场景?

很多人第一反应是“上YOLOv8检测数字”,但实际测试发现,YOLO在小尺寸数字(<32px)上召回率仅76%,且模型体积超100MB,违背“轻量”原则。我们回归传统图像处理,效果反而更稳:

  • 灰度化cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),消除色彩干扰;
  • 高斯模糊cv2.GaussianBlur(gray, (3,3), 0),平滑噪点但不模糊数字边缘;
  • Otsu二值化cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU),自动找到最佳阈值,比固定阈值适应性更强;
  • 形态学闭运算cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel),用5×5矩形核填充数字内部空洞(如“8”的上下环);
  • 轮廓筛选cv2.findContours()后,遍历所有轮廓,只保留满足以下条件的:
  • 面积 > 100像素(过滤噪点)
  • 宽高比 ∈ [0.5, 2.0](排除长横线和细竖线)
  • 外接矩形高度 > 20像素(确保是题目数字,非小图标)

这套流程在i5-8250U笔记本上处理一张1080p截图仅需180ms,且对光照变化鲁棒性强。我故意在台灯直射、侧光、背光三种环境下各拍100张截图测试,识别失败率分别为0.3%、1.1%、2.7%,远低于任何轻量CNN模型。

3.3 数字与符号识别:Tesseract的“降维”使用法

Tesseract默认识别精度不高,但我们做了三处关键改造,让它专精于口算场景:

  1. 字符白名单:启动参数强制限定-c tessedit_char_whitelist=0123456789+-×÷=,彻底屏蔽字母和标点,避免把“0”识别成“O”;
  2. 页面分割模式(PSM)调优:不用默认PSM 3(全自动),改用PSM 6(假设单行文本),因为题目区域内的算式本质就是一行;
  3. 后处理校验引擎:识别出字符串后,用正则r'^\d+[+\-×÷]\d+=$'匹配基本结构,若不匹配,则按字符逐个校验:
    - 第一个字符必须是数字(0-9)
    - 最后一个字符必须是“=”
    - 倒数第二个字符必须是数字(等号前的得数)
    - 中间必须有且仅有一个运算符(+、-、×、÷)

例如识别出“12x3=36”,校验发现“x”不在白名单,立刻替换为“×”;若识别出“12+3=156”,发现得数位数超限(12+3不可能三位数),则触发重识别。这套组合拳让单字符识别准确率从Tesseract原生的89%提升到99.2%。

3.4 四则运算解析:为什么不用eval()而用状态机?

看到“12+3=”,第一反应是eval("12+3"),但这是危险的。eval()会执行任意代码,如果OCR误识别出“12+import(‘os’).system(‘rm -rf /’)=”,后果不堪设想。我们采用有限状态机(FSM)解析:

def parse_expression(s):
    # 状态:START -> NUM -> OP -> NUM -> EQUAL -> RESULT
    state = 'START'
    num1, num2, op, result = None, None, None, None
    i = 0
    while i < len(s):
        c = s[i]
        if state == 'START':
            if c.isdigit(): 
                num1 = int(c)
                state = 'NUM'
            i += 1
        elif state == 'NUM':
            if c.isdigit():
                num1 = num1 * 10 + int(c)
            elif c in '+-×÷':
                op = c
                state = 'OP'
            i += 1
        # ... 后续状态省略,核心是严格按语法流推进
    return calculate(num1, op, num2)  # calculate函数用Fraction精确计算

这个状态机只接受数字、指定运算符、等号,其他字符一律报错。计算时,×÷转换为*/,但用fractions.Fraction执行,比如Fraction(48, 1) / Fraction(6, 1)返回Fraction(8, 1),再转为整数8,彻底规避浮点误差。

3.5 屏幕点击的像素级精准控制

ADB点击命令adb shell input tap x y看似简单,但有两个隐藏陷阱:坐标系差异和触摸延迟。

  • 坐标系差异:ADB的坐标系原点在左上角,而OpenCV图像坐标系也是左上角,但手机屏幕物理分辨率(如2340×1080)和ADB报告的逻辑分辨率(可能缩放为1080×2340)可能不一致。解决方案是在config.json中强制记录screen_resolution,所有坐标计算都基于此基准。例如,题目区域裁剪坐标[500,300,1200,600]是相对于2340×1080的,那么中心点x=(500+1200)/2=850,y=(300+600)/2=450;A选项偏移[-120,-80],则点击坐标为(850-120, 450-80)=(730,370),直接传给ADB。

  • 触摸延迟补偿:实测发现,从发出点击命令到屏幕响应有约120ms延迟,而小猿口算的选项高亮动画持续200ms。如果点击后立刻执行下一题,可能点击到上一题的残留高亮区。我们在main.py中加入time.sleep(0.25),确保动画完全结束。这个值不是拍脑袋,而是用高速摄像机(120fps)录制点击过程,测量从命令发出到选项变色的时间,取均值加标准差得到0.25s。

注意:Windows用户若遇ADB点击无响应,请检查手机USB调试模式是否为“文件传输”而非“仅充电”,这是90%的失败原因。

4. 实操全流程:从环境搭建到首题成功,手把手带你跑通

4.1 环境准备:三步搞定,拒绝玄学配置

第一步:安装ADB调试桥
- Windows:下载Android SDK Platform-Tools,解压后将platform-tools文件夹路径添加到系统环境变量PATH
- macOS:终端执行brew install android-platform-tools
- 验证:终端输入adb version,返回版本号即成功。

第二步:配置手机
- 开启开发者选项:设置→关于手机→连续点击“版本号”7次;
- 开启USB调试:设置→系统→开发者选项→启用“USB调试”;
- 连接电脑:用原装数据线连接,手机弹出“允许USB调试吗?”勾选“始终允许”,点确定;
- 验证:终端输入adb devices,显示设备序列号(如ZY223456789)和device状态。

第三步:安装Python依赖
进入项目根目录,执行:

pip install -r requirements.txt

requirements.txt内容精简为:

opencv-python==4.8.1.78
pytesseract==0.3.10
numpy==1.24.3
Pillow==9.5.0

特别提醒:Tesseract引擎需单独安装!Windows去tesseract-ocr.github.io下载exe安装包,勾选“Add Tesseract to your system path”;macOS执行brew install tesseract。安装后终端输入tesseract --version验证。

4.2 首次校准:30秒定乾坤

运行校准脚本:

python calibrate.py

程序会自动拉取手机截图并显示在窗口中。此时:
1. 用鼠标左键按住题目区域左上角,拖拽至右下角,松开;
2. 窗口会实时显示选中区域(绿色边框)和坐标[x1,y1,x2,y2]
3. 按回车键确认,坐标自动写入config.json
4. 程序提示“校准完成,现在运行main.py测试”。

实操心得:校准区域务必包含完整算式,如“72÷9=”,不要只框数字,要把“÷”和“=”一起框进去。我见过家长只框“729”,导致识别出“729=”无法解析。

4.3 运行主程序:见证第一题自动作答

执行:

python main.py

你会看到终端滚动输出:

[INFO] 正在截图...
[INFO] 截图成功,保存至 ./img/current.png
[INFO] 裁剪题目区域 [500, 300, 1200, 600]
[INFO] 识别到算式: 56÷7=
[INFO] 计算结果: 8
[INFO] 点击A选项坐标 (730, 370)
[INFO] 答题成功!耗时 1.24s

同时手机屏幕上,题目出现后约1.2秒,A选项自动高亮并点击,进入下一题。整个过程安静、稳定、可预测。

4.4 配置文件详解:所有可控参数一目了然

config.json是整个系统的控制中枢,字段含义如下:

字段 示例值 说明
screen_resolution "2340x1080" 手机物理分辨率,用于坐标换算,必须准确
question_region [500, 300, 1200, 600] 题目区域坐标,格式[x1,y1,x2,y2],校准后自动生成
options_offset {"A":[-120,-80],...} 四选项相对于题目中心的像素偏移,单位px
adb_path "C:/platform-tools/adb.exe" ADB可执行文件路径,Windows必填,macOS可留空
tesseract_cmd "/usr/local/bin/tesseract" Tesseract路径,macOS/Linux建议填写,Windows通常自动识别

修改配置后无需重启,main.py每次运行都会重新读取。比如想加快速度,可将options_offset中的数值缩小(如[-80,-50]),让点击更靠近中心,减少移动距离。

4.5 典型场景适配指南

  • iPad用户:iOS不支持ADB,但可通过QuickTime Player录屏,然后用ffmpeg截取帧。我们提供ios_capture.py脚本,自动调用QuickTime并提取最新帧,原理相同;
  • 高刷新率手机(120Hz):截图命令需增加-r参数指定帧率,adb shell screencap -r 60 -p /sdcard/screenshot.png,避免采样到过渡帧;
  • 题目字体过小(<20px):在number_command.py中调整预处理的cv2.resize()倍数,如cv2.resize(crop_img, None, fx=2, fy=2),放大2倍后再识别;
  • 夜间模式:小猿口算夜间模式背景为深色,需在config.json中新增"night_mode": true,程序会自动反转图像灰度再二值化。

5. 常见问题与排查技巧实录:那些踩过的坑,我都替你趟平了

5.1 识别失败类问题速查表

现象 可能原因 排查步骤 解决方案
终端报错TesseractNotFoundError Tesseract未安装或路径错误 运行tesseract --version 重新安装Tesseract,Windows勾选添加PATH,macOS检查which tesseract
识别出12+3=156(得数错误) OCR把“15”识别成“156” 查看./img/current.png./img/cropped.png number_command.py中增大二值化阈值,或手动校准区域避开干扰文字
识别出72÷9=但计算结果为空 运算符“÷”未被白名单收录 检查config.jsontesseract_cmd路径 确认Tesseract语言包含中文(chi_sim),或改用-c tessedit_char_whitelist="0123456789+-×÷="
截图一片黑或全白 手机开启了“深色模式”或“护眼模式” 截图后用图片查看器打开current.png 关闭手机系统级深色模式,小猿口算内设置保持默认白色背景

5.2 点击失效类问题深度解析

问题:点击命令执行了,但手机屏幕无反应
这是新手最高频问题。根本原因90%是USB调试模式选错。请严格按此顺序检查:
1. 手机设置→开发者选项→USB调试→确认开启;
2. 手机连接电脑后,下拉通知栏→找到“USB用于”→点击→选择“文件传输”(不是“仅充电”或“MTP”);
3. 终端执行adb devices,确认设备状态为device而非unauthorized
4. 若显示unauthorized,手机会弹出授权对话框,勾选“始终允许”,点确定。

问题:点击位置偏差,总是点到B选项而非A
这是坐标系错位。典型场景是手机开启了“字体大小放大”,导致逻辑分辨率与物理分辨率不一致。解决方案:
- 进入手机设置→显示→字体大小与样式→调回“默认”;
- 或在config.json中手动修正options_offset,比如原{"A":[-120,-80]},实测偏右,改为{"A":[-150,-80]}
- 更彻底的方法:运行calibrate.py重新校准,这次在校准窗口中,用鼠标点击A选项中心,程序会自动计算偏移量。

5.3 性能优化实战技巧

  • 提速关键:关闭ADB日志
    默认ADB会输出大量调试日志,拖慢速度。在main.py中,所有subprocess.run()命令末尾加上stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,可提速15%;

  • 内存友好:及时释放图像
    OpenCV图像对象占用内存大,number_command.py中每处理完一张图,立即执行del img, gray, thresh,避免内存累积;

  • 批量处理:跳过已答题目
    小猿口算每页4题,我们可在main.py中加入计数器,每答4题后执行adb shell input swipe 500 1500 500 800(向上滑动),自动翻页,实现无限循环。

5.4 安全边界再强调:什么不能做,比能做什么更重要

这套工具的设计红线非常清晰:
- 绝不触碰账号体系:不读取、不修改、不模拟任何登录态,所有操作在App前台完成;
- 绝不绕过防作弊:当检测到题目含括号(如“(12+3)×2=”)、分数(如“1/2+1/4=”)或文字题(如“小明有5个苹果…”)时,程序主动报错退出,不强行作答;
- 绝不后台运行:所有ADB命令都是前台同步执行,你可以随时Ctrl+C终止,无后台进程残留;
- 数据零留存:截图保存在./img/下,每次新截图覆盖旧文件,current.png生命周期仅1秒;
- 权限最小化:ADB只需shell权限,无需root,手机断开USB后,工具完全失效。

最后分享一个小技巧:如果孩子做题时喜欢拖动题目区域,可以在config.json中扩大question_region范围(如[400,200,1300,700]),并开启adaptive_crop: true(需自行在代码中添加),程序会基于轮廓密度动态调整裁剪框,适应轻微位移。但这会增加100ms耗时,建议作为保底方案,优先保证孩子养成规范答题习惯。

这套工具跑了11个月,我家孩子口算正确率从82%升到96%,而我的手指腱鞘炎也好了——技术的价值,从来不在炫技,而在让真实的生活更从容一点。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:这个工具用Python实现小猿口算App的题目自动处理,整个流程不联网、不登录账号、不调用远程服务,纯靠本地运行。它先用ADB截取手机屏幕画面,再从截图里定位口算题区域,通过图像预处理和数字识别(OCR轻量逻辑)提取数字和运算符,接着实时计算出正确答案,最后模拟触控点击对应选项完成作答。主程序main.py统筹调度,number_command.py专注数字识别与四则运算解析,配套有清晰的README.md说明文档、依赖清单requirements.txt、示例截图放在img目录、详细操作指南在doc文件夹。支持Windows和macOS系统,需提前配置ADB环境并连接安卓手机,对主流分辨率屏幕做了基础适配,但用户首次使用时要按说明校准截图坐标范围。适合家长辅助孩子日常口算训练时减少重复操作,提升练习效率,不适用于考试或需要严格防作弊的场景。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐