用Python写了个“AI监工”盯着自己写代码,因过于硬核被围观!(附源码+原理)

摘要:作为一个自制力为负数的程序员,我终于对自己下手了。为了戒掉“写两行代码刷十分钟抖音”的毛病,我用 Python + OpenCV + YOLO + MediaPipe 撸了一个桌面端的AI视觉防摸鱼系统。它能识别我有没有在玩手机、有没有离开座位,甚至支持隔空手势控制。本文分享硬核开发过程、踩坑经验及核心源码。


😡 起因:我被算法“算计”了

不知道大家有没有同感:本来只想打开手机回个微信,结果手指不由自主地点开了短视频,一刷就是半小时。

作为一名开发者,我深知这就是多巴胺的“奖赏预测误差”机制。算法在攻破我的人性弱点。既然打不过算法,那就用魔法打败魔法!

我决定开发一款**“AI 视觉监工” (FocusGuard)**:

  1. 监控:摄像头实时盯着我,敢拿起手机?直接报警!
  2. 交互:不想碰鼠标?比个✌️就能暂停休息。
  3. 复盘:自动记录走神瞬间,生成“羞耻墙”截图。

这是最终做出来的样子(纯Python开发,已打包EXE):
*(此处建议插入软件运行截图,展示红框识别手机的效果)*
历史记录


🛠️ 技术栈选型

为了在我的渣机上也能流畅运行,我没有用笨重的 PyTorch 原生推理,而是走了轻量化路线:

  • GUI 框架CustomTkinter (比原声 Tkinter 美观 10 倍,支持高分屏)
  • 视觉捕捉OpenCV (CV2)
  • 物体检测YOLO11sONNX (CPU 推理也能跑满 30FPS)
  • 手势识别MediaPipe (谷歌的方案,稳准狠)
  • 打包工具PyInstaller + Inno Setup (为了把这堆环境塞进一个 exe 也是拼了)

💻 核心代码实现

1. 怎么判断我在玩手机?(YOLO + ONNX)

这是最核心的功能。我训练了一个 YOLO 模型专门识别 Cell Phone。为了性能,我使用了 OpenCV 的 DNN 模块加载 ONNX 模型,这样就不需要安装几 GB 的 PyTorch 环境了。

def detect_phone_onnx(self, frame):
    # 图像预处理:归一化 + 尺寸调整
    blob = cv2.dnn.blobFromImage(frame, 1/255.0, (640, 640), swapRB=True, crop=False)
    self.net.setInput(blob)
    outputs = self.net.forward()
    
    # 解析输出
    predictions = np.transpose(outputs[0])
    rows = predictions.shape[0]
    
    for i in range(rows):
        row = predictions[i]
        # 获取最大概率的类别
        classes_scores = row[4:]
        _, max_score, _, max_class_loc = cv2.minMaxLoc(classes_scores)
        
        # ID 67 是 COCO 数据集里的手机,置信度设为 0.45
        if max_score > 0.45 and max_class_loc[1] == 67:
            print(">>> 警告:监测到手机!")
            return True
    return False
  1. 手势控制 (MediaPipe 的妙用)
    为了不打断心流(Flow State),我设计了手势交互:
✌️ (剪刀手):申请休息 8 分钟(去喝水、上厕所)。

✋ (张开手掌):申请“手机豁免权” 10 分钟(必须回消息时用)。

这里利用了 MediaPipe Hands 的关键点坐标逻辑:

import mediapipe as mp

def _check_victory(self, hand_landmarks):
    """
    检测剪刀手 (Victory)
    逻辑:食指中指伸直,无名指小指弯曲
    """
    lm = hand_landmarks.landmark
    # 8:食指指尖, 6:食指根部 -> y坐标越小位置越高
    # 12:中指指尖, 10:中指根部
    index_is_open = lm[8].y < lm[6].y
    middle_is_open = lm[12].y < lm[10].y
    
    # 16:无名指, 20:小指 -> 必须是弯曲的
    ring_is_closed = lm[16].y > lm[14].y
    pinky_is_closed = lm[20].y > lm[18].y
    
    return index_is_open and middle_is_open and ring_is_closed and pinky_is_closed

🚀 遇到的坑与解决方案

  1. PyInstaller 打包后的“模块丢失”
    开发时好好的,打包成 .exe 后直接闪退,报错 ModuleNotFoundError: mediapipe.python.solutions。 这是因为 MediaPipe 动态加载了一些子模块,PyInstaller 分析不到。

解决方案: 在 .spec 文件中,必须使用 collect_all 暴力收集:

from PyInstaller.utils.hooks import collect_all

# 强行把 mediapipe 的所有家当都带上
mp_datas, mp_binaries, mp_hiddenimports = collect_all('mediapipe')

a = Analysis(
    ...
    datas=all_datas + mp_datas,
    binaries=all_binaries + mp_binaries,
    hiddenimports=all_hiddenimports + mp_hiddenimports,
    ...
)
  1. 误报问题
    刚开始,我喝水用的黑色马克杯经常被识别成手机。 优化:我加入了逻辑判断,不仅要识别到 Object,还必须结合 光流法 (Optical Flow) —— 只有当画面有动作且检测到手机时才报警。如果画面静止(比如手机放在桌上没动),则不报警,减少对注意力的打扰。

📦 成果发布:FocusGuard v1.0

经过两周的迭代(和无数次被自己的程序报警吓一跳),v1.0.0 版本终于上线了。

它能做什么?

1、全自动监工:你只需要打开它,最小化,然后开始工作。一旦你拿起手机,警报声就会响起。

2、不联网、更安全:所有计算都在本地,公司电脑也能放心用。

3、统计报表:结束工作后,它会生成一张“羞耻报表”,告诉你今天摸了多少次鱼,并附带走神瞬间的截图(保存在本地)。

适合人群:

1、写代码写着写着就开始刷手机的程序员。

2、正在肝论文的大学生/研究生。

3、需要长时间深度工作的自由职业者。
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐