V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  ç™»å½•
爱意满满的作品展示区。
xiaowoli
V2EX  â€º  分享创造

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

  xiaowoli · 89 天前 · 4174 次点击
这是一个创建于 89 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

背景

家里有一条狗🐶,很喜欢乘人不备睡沙发🛋️,恰好最近刚搬家 + 狗迎来了掉毛期 不想让沙发上很多毛。所以希望能识别到狗,然后播放“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/[email protected]/dist/tf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]/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  
   89 天前 via Android
这个需求用 techable machine 上传几张图也可以实现🌚
blackcellcode
    2
blackcellcode  
   89 天前
结果笑了哈哈😄
hinataharuki
    3
hinataharuki  
   89 天前   ❤️ 9
女:什么花里胡哨的
woody3rd
    4
woody3rd  
   89 天前
真会玩啊
cat
    5
cat  
   89 天前
[但是,家里夫人直接做了一个围栏晚上给狗圈起来了]
Seven711
    6
Seven711  
   89 天前
哈哈哈哈,整的花里胡哨的
netnetuser
    7
netnetuser  
   89 天前
想法挺好的。实际上,有些狗狗很聪明,就 OP 狗狗生活的环境,狗狗可以越狱的方式就有 2 个:
1.跳上窗边走出来;
2.直接跳过围栏。

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