V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
xiaowoli
V2EX  ›  分享创造

🚫为了防止狗上沙发,写了一个浏览器实时识别目标功能📷

  xiaowoli · 2024-03-15 16:32:36 +08:00 · 6626 次点击
这是一个创建于 377 天前的主题,其中的信息可能已经有所发展或是发生改变。

网页调用摄像头识别物体后做成行为

背景

家里有一条狗🐶,很喜欢乘人不备睡沙发🛋️,恰好最近刚搬家 + 狗迎来了掉毛期 不想让沙发上很多毛。所以希望能识别到狗,然后播放“gun 下去”的音频📣。

需求分析

  • 需要一个摄像头📷
    • 利用 chrome 浏览器可以调用手机摄像头,获取权限,然后利用 video 将摄像头的内容绘制到 video 上。
  • 通过摄像头实时识别画面中的狗🐶
    • 利用 tensorflow 和预训练的 COCO-SSD MobileNet V2 模型进行对象检测。
    • 将摄像头的视频流转化成视频帧图像传给模型进行识别
  • 录制一个音频
    • 识别到目标(狗)后播放音频📣
  • 需要部署在一个设备上
    • 找一个不用的旧手机📱,Android 系统
    • 安装 termux 来实现开启本地 http 服务🌐

技术要点

  1. 利用浏览器 API 调用手机摄像头,将视频流推给 video

    const stream = await navigator.mediaDevices.getUserMedia({
      // video: { facingMode: "environment" },  // 摄像头后置
      video: { facingMode: "user" },
    });
    
    const videoElement = document.getElementById("camera-stream");
    videoElement.srcObject = stream;
    
  2. 加载模型,实现识别

    let dogDetector;
    
    async function loadDogDetector() {
      // 加载预训练的 SSD MobileNet V2 模型
      const model = await cocoSsd.load();
      dogDetector = model; // 将加载好的模型赋值给 dogDetector 变量
    }
    
  3. 监听 video 的播放,将视频流转换成图像传入模型检测

    videoElement.addEventListener("play", async () => {
      requestAnimationFrame(processVideoFrame);
    });
    
    async function processVideoFrame() {
      if (!videoElement.paused && !videoElement.ended) {
        canvas.width = videoElement.videoWidth;
        canvas.height = videoElement.videoHeight;
        ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
    
        // 获取当前帧图像数据
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    
        // 对帧执行预测
        let predictionClasses = "";
        const predictions = await dogDetector.detect(imageData);
        // 处理预测结果,比如检查是否有狗被检测到
        for (const prediction of predictions) {
          predictionClasses += `${prediction.class}\n`; // 组装识别的物体名称
          if (prediction.class === "dog") {
            // 播放声音
            playDogBarkSound();
          }
        }
        nameContainer.innerText = predictionClasses.trim(); // 移除末尾的换行符
    
        requestAnimationFrame(processVideoFrame);
      }
    }
    
  4. 播放音频

    async function playDogBarkSound() {
      if (playing) return;
      playing = true;
      const audio = new Audio(dogBarkSound);
      audio.addEventListener("ended", () => {
        playing = false;
      });
      audio.volume = 0.5; // 调整音量大小
      await audio.play();
    }
    
  5. 手机开启本地 http 服务

    • 安装 termux
    • 安装 python3
    • 运行 python3 -m http.server 8000
  6. 将项目上传到 termux 的目录

    • 直接用 termux 打开文件
    • 访问 http://localhost:8000

项目代码(改为 html 文件后)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Mobile Dog Detector</title>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.17.0/dist/tf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd@2.2.3/dist/coco-ssd.min.js"></script>
    <style>
      #camera-stream {
        width: 200px;
        height: auto;
      }
      #name {
        height: 200px;
        overflow-y: auto;
        font-family: Arial, sans-serif;
      }
    </style>
  </head>
  <body>
    <video id="camera-stream" autoplay playsinline></video>
    <div id="name" style="height: 200px"></div>

    <script>
      let playing = false;
      let dogDetector;

      async function loadDogDetector() {
        // 加载预训练的 SSD MobileNet V2 模型
        const model = await cocoSsd.load();
        dogDetector = model; // 将加载好的模型赋值给 dogDetector 变量
        console.log("dogDetector", dogDetector);
        startCamera();
      }
      // 调用函数加载模型
      loadDogDetector();

      async function startCamera() {
        const stream = await navigator.mediaDevices.getUserMedia({
          // video: { facingMode: "environment" },  // 摄像头后置
          video: { facingMode: "user" },
        });
        const nameContainer = document.getElementById("name");
        const videoElement = document.getElementById("camera-stream");
        videoElement.srcObject = stream;

        const canvas = document.createElement("canvas");
        const ctx = canvas.getContext("2d");

        videoElement.addEventListener("play", async () => {
          requestAnimationFrame(processVideoFrame);
        });
        async function processVideoFrame() {
          if (!videoElement.paused && !videoElement.ended) {
            canvas.width = videoElement.videoWidth;
            canvas.height = videoElement.videoHeight;
            ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);

            const imageData = ctx.getImageData(
              0,
              0,
              canvas.width,
              canvas.height
            );

            let predictionClasses = "";
            const predictions = await dogDetector.detect(imageData);
            for (const prediction of predictions) {
              predictionClasses += `${prediction.class}\n`;
              if (prediction.class === "dog") {
                // 修改为检测到狗时播放声音
                playDogBarkSound();
              }
            }
            nameContainer.innerText = predictionClasses.trim();

            requestAnimationFrame(processVideoFrame);
          }
        }

        async function playDogBarkSound() {
          if (playing) return;
          playing = true;
          const audio = new Audio("./getout.mp3");
          audio.addEventListener("ended", () => {
            playing = false;
          });
          audio.volume = 0.5; // 调整音量大小
          await audio.play();
        }
      }
    </script>
  </body>
</html>

实现效果

效果很好👍,用旧手机开启摄像头后,检测到狗就播放声音了。

但是,家里夫人直接做了一个围栏晚上给狗圈起来了🚫

实现总结

该方案通过以下步骤实现了一个基于网页的实时物体检测系统,专门用于识别画面中的狗并播放特定音频以驱赶它离开沙发。具体实现过程包括以下几个核心部分:

  • 调用摄像头:

使用浏览器提供的 navigator.mediaDevices.getUserMedia API 获取用户授权后调用手机摄像头,并将视频流设置给 video 元素展示。

  • 加载物体检测模型:

使用 TensorFlow.js 和预训练的 COCO-SSD MobileNet V2 模型进行对象检测,加载模型后赋值给 dogDetector 变量。 处理视频流与图像识别:

监听 video 元素的播放事件,通过 requestAnimationFrame 循环逐帧处理视频。 将当前视频帧绘制到 canvas 上,然后从 canvas 中提取图像数据传入模型进行预测。 在模型返回的预测结果中,如果检测到“dog”,则触发播放音频函数。

  • 播放音频反馈:

定义一个异步函数 playDogBarkSound 来播放指定的音频文件,确保音频只在前一次播放结束后才开始新的播放。

  • 部署环境准备:

使用旧 Android 手机安装 Termux ,创建本地 HTTP 服务器运行项目代码。 上传项目文件至 Termux 目录下并通过访问 localhost:8000 启动应用。

通过以上技术整合,最终实现了在旧手机上部署一个能够实时检测画面中狗的网页应用,并在检测到狗时播放指定音频。

41 条回复    2024-03-19 13:19:38 +08:00
xieqiqiang00
    1
xieqiqiang00  
   2024-03-15 16:36:34 +08:00 via Android
这个需求用 techable machine 上传几张图也可以实现🌚
blackcellcode
    2
blackcellcode  
   2024-03-15 16:40:17 +08:00
结果笑了哈哈😄
hinataharuki
    3
hinataharuki  
   2024-03-15 16:41:37 +08:00   ❤️ 10
女:什么花里胡哨的
woody3rd
    4
woody3rd  
   2024-03-15 16:42:04 +08:00
真会玩啊
cat
    5
cat  
   2024-03-15 16:42:23 +08:00
[但是,家里夫人直接做了一个围栏晚上给狗圈起来了]
Seven711
    6
Seven711  
   2024-03-15 16:45:10 +08:00
哈哈哈哈,整的花里胡哨的
netnetuser
    7
netnetuser  
   2024-03-15 16:48:17 +08:00
想法挺好的。实际上,有些狗狗很聪明,就 OP 狗狗生活的环境,狗狗可以越狱的方式就有 2 个:
1.跳上窗边走出来;
2.直接跳过围栏。

我在 Youtube 上看狗狗视频,嚓...他们有着强烈的外逃行动力,围栏难不倒他们的。
zmQAQ
    8
zmQAQ  
   2024-03-15 16:53:08 +08:00
nb
zoezz
    9
zoezz  
   2024-03-15 16:54:30 +08:00
够硬核 v 站需要这种帖子
wesleywaters
    10
wesleywaters  
   2024-03-15 16:56:13 +08:00
结局很欢乐
Felldeadbird
    11
Felldeadbird  
   2024-03-15 17:28:03 +08:00
硬核终究败给现实。
rewluck
    12
rewluck  
   2024-03-15 17:33:18 +08:00
狗子挺好看,op 够硬核,夫人很现实
gbw1992
    13
gbw1992  
   2024-03-15 17:39:55 +08:00   ❤️ 1
狗狗对于这围栏的态度
就相当于
你老婆对于你开发这套东西的态度
不能说一点用没有吧
gamexg
    14
gamexg  
   2024-03-15 17:49:37 +08:00
另外狗对于这种声音可能并不在意,至少我家的就是这样.
人在家不敢上沙发,但是家里没人有时候就会上沙发.
通过监控/扫地机器人喊话毫无效果,它根本不会理.
但是你回家的话,它听到声音就会自己下来.
wcao
    15
wcao  
   2024-03-15 17:56:30 +08:00
好好好,真会玩。
luzemin
    16
luzemin  
   2024-03-15 18:15:25 +08:00
赛博手工耿
qsgy123456
    17
qsgy123456  
   2024-03-15 19:54:44 +08:00
想在衣领别个摄像头。识别到熟人的时候提示你相关资料。 感觉销售可以用
zhilincom
    18
zhilincom  
   2024-03-15 20:46:54 +08:00
围栏??这直接可以跳过去的吧。
miaomiao888
    19
miaomiao888  
   2024-03-15 20:54:45 +08:00
别把狗子吓坏了,怎么主子的声音像鬼魂一样时刻环绕在耳边
NeroKamin
    20
NeroKamin  
   2024-03-15 21:07:28 +08:00
哈哈哈哈好有意思
aitianci
    21
aitianci  
   2024-03-15 21:25:58 +08:00
可以给狗加个放电脖圈,接近沙发一米内就电一下
wonderfulcxm
    22
wonderfulcxm  
   2024-03-15 21:45:44 +08:00 via iPhone
结局略显意外
Atma
    23
Atma  
   2024-03-15 22:20:11 +08:00 via Android
你是真的🐶,哈哈哈
dyv9
    24
dyv9  
   2024-03-15 22:52:46 +08:00 via Android
活在你家,做狗也不开心,既然都是不开心下辈子还是做人吧,至少想结婚或想嫖总有一个可以,做狗就没机会。
keepRun
    25
keepRun  
   2024-03-16 02:57:33 +08:00 via Android
angry41
    26
angry41  
   2024-03-16 11:14:08 +08:00
@qsgy123456 #17 我记得房产销售大厅的摄像头都带这个功能,还上过 315 ,大数据会识别你之前在哪家看过哪家房子,心里价位大概多少
hanguofu
    27
hanguofu  
   2024-03-16 11:54:34 +08:00
厉害~~ 请问 ”使用 TensorFlow.js 和预训练的 COCO-SSD MobileNet V2 模型进行对象检测“ 这个拿来就可以用了吗 ?具体怎样训练才能识别 狗 啊?
ohayoo
    28
ohayoo  
   2024-03-16 14:01:23 +08:00
程序员的欢乐世界
lxcForPHP
    29
lxcForPHP  
   2024-03-16 16:13:39 +08:00
@qsgy123456 今年老回家过年,遇到很多能喊出我名字来(小时候的邻居和家族的人),但是我却没有多少印象,愣在那里也不知道喊人家啥,场面尴尬的很。所以就萌生了一个想法,能不能自己维护一个资料库,然后能通过啥智能设备来自动查询相关资料
fenglangjuxu
    30
fenglangjuxu  
   2024-03-18 09:39:37 +08:00
高阶程序员 我等只能望洋兴叹
uyoungco
    31
uyoungco  
   2024-03-18 11:34:37 +08:00   ❤️ 1
@hanguofu 别人训练好的,你输入图形他会给你图像中的信息,比如 人、狗之类的
huangz003
    32
huangz003  
   2024-03-18 14:57:46 +08:00
圈起来,小狗怎么上厕所😂
xiaowoli
    33
xiaowoli  
OP
   2024-03-18 16:09:46 +08:00
@huangz003 只有晚上关起来 我家狗一天就出去尿一次 够了
xiaowoli
    34
xiaowoli  
OP
   2024-03-18 16:10:53 +08:00
@netnetuser 老哥,最新消息,我家狗看了你的回复已经学会越狱了。。。
xiaowoli
    35
xiaowoli  
OP
   2024-03-18 16:12:06 +08:00
@hanguofu 直接用我那个代码就已经可以识别了 现成的模型库
netnetuser
    36
netnetuser  
   2024-03-18 16:32:05 +08:00
@xiaowoli 我觉得可以记录下狗狗越狱整个过程(偷 拍),然后让大家一起欢乐。
LavaC
    37
LavaC  
   2024-03-19 09:26:40 +08:00
突然想起那个买了体重秤放床垫下的玩法
jiandandkl
    38
jiandandkl  
   2024-03-19 10:19:03 +08:00
太好玩了,想知道狗听到播放的 gun 下去会听话的 gun 下去吗?
janda
    39
janda  
   2024-03-19 10:33:27 +08:00
有意思
DavidA
    40
DavidA  
   2024-03-19 10:57:54 +08:00
幽默
lefer
    41
lefer  
   2024-03-19 13:19:38 +08:00
@xieqiqiang00 #1 太厉害了。竟然是谷歌的项目。
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3194 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 33ms · UTC 12:12 · PVG 20:12 · LAX 05:12 · JFK 08:12
Developed with CodeLauncher
♥ Do have faith in what you're doing.