ФронтендData и ИИJavaScriptHTML / CSS

Управляем сайтом жестами через веб-камеру: MediaPipe + JavaScript

Подключаем MediaPipe Gesture Recognizer в браузере, получаем кадры с веб-камеры, распознаём жесты и управляем слайдом с ограничением частоты.

Кодик

Автор

6 мин чтения

MediaPipe Gesture Recognizer можно освоить на одном небольшом проекте, если сразу видеть вход, действие и результат. MediaPipe Tasks Vision запускает модель распознавания жестов в браузере и возвращает категорию, уверенность и координаты руки для каждого кадра. Ниже вы соберёте работающий пример и проверите обычный и граничный сценарии.

Если привязать действие к каждому video frame, один жест переключит слайд десятки раз и интерфейс станет непредсказуемым. Поэтому отделим настройку, входные данные, основное действие и проверку. В этой статье вы соберёте демо с веб-камерой, где Thumb Up переходит к следующей карточке, Open Palm возвращает предыдущую, а cooldown защищает от повторов. Проверка: после разрешения камеры видео появляется, уверенный жест меняет карточку один раз, а отсутствие руки не вызывает действий.

1Соберите минимум

запросить video без audio после клика. Не расширяйте проект до первого успешного запуска.

2Увидьте данные

runningMode VIDEO готов к кадрам. Проверяйте значение, а не отсутствие ошибки.

3Измените правило

После успеха добавьте нейтральный жест подтверждения и отдельную кнопку остановки камеры. Так копирование станет практикой.

Как устроен учебный проект MediaPipe Gesture Recognizer

getUserMedia создаёт видеопоток, requestAnimationFrame передаёт новые кадры распознавателю, а отдельная функция превращает устойчивый жест в действие интерфейса. Держите ввод, логику и отображение раздельно: тогда каждый этап можно проверить отдельно.

ЭтапДействиеПроверяемый результат
Камеразапросить video без audio после кликаэлемент video показывает локальный поток
Модельзагрузить FilesetResolver и GestureRecognizerrunningMode VIDEO готов к кадрам
Цикланализировать только новый video.currentTimeрезультат содержит категорию и score
Действиеприменить порог и cooldownодин жест меняет слайд ровно один раз

Контрольные точки: камера, модель, цикл и действие. Следующий шаг начинается после совпадения с ожидаемым результатом.

Путь данных в проекте MediaPipe Gesture Recognizer
От входных данных до видимого результата. Сначала проверяется вход, затем действие и только потом интерфейс.

Зафиксируйте первый успех Сначала выведите имя жеста и score текстом. Не подключайте управление интерфейсом, пока классификация не стала понятной и устойчивой. Сохраните команду запуска и ожидаемый вывод.

Собираем рабочий пример шаг за шагом

Пример сверялся с актуальной документацией официальной документации MediaPipe Gesture Recognizer for Web на 19 октября 2026 года. Создайте Vite-проект, установите @mediapipe/tasks-vision и запускайте через localhost или HTTPS, иначе камера может быть недоступна. Проверьте текущую папку через pwd или Get-Location. Вставьте пример целиком, выполните один раз, затем разбирайте по частям.

import { FilesetResolver, GestureRecognizer } from '@mediapipe/tasks-vision'

const video = document.querySelector('video')
const label = document.querySelector('#gesture')
let recognizer
let lastVideoTime = -1
let lastActionAt = 0

async function start() {
  const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false })
  video.srcObject = stream
  await video.play()

  const vision = await FilesetResolver.forVisionTasks('/wasm')
  recognizer = await GestureRecognizer.createFromOptions(vision, {
    baseOptions: { modelAssetPath: '/gesture_recognizer.task' },
    runningMode: 'VIDEO',
    numHands: 1,
  })
  requestAnimationFrame(loop)
}

function loop() {
  if (video.currentTime !== lastVideoTime) {
    const result = recognizer.recognizeForVideo(video, performance.now())
    const best = result.gestures[0]?.[0]
    label.textContent = best ? best.categoryName + ' ' + best.score.toFixed(2) : 'Нет руки'
    if (best && best.score > 0.7 && performance.now() - lastActionAt > 900) {
      if (best.categoryName === 'Thumb_Up') nextSlide()
      if (best.categoryName === 'Open_Palm') previousSlide()
      lastActionAt = performance.now()
    }
    lastVideoTime = video.currentTime
  }
  requestAnimationFrame(loop)
}
Что должно произойти после запуска
  • После клика браузер запрашивает камеру и показывает локальный видеопоток.
  • Распознанный жест и score видны текстом, а действие срабатывает только выше порога 0.7.
  • Повторный запуск даёт тот же предсказуемый результат.
  • Пустой ввод получает понятное сообщение вместо падения.

Модель отвечает за классификацию кадра, а порог, cooldown и смысл жеста задаёт приложение. Найдите в примере вход, проверку и место формирования результата.

Хрупкий и проверяемый вариант MediaPipe Gesture Recognizer
Что отличает устойчивый проект от случайного запуска. Явные границы делают ошибку локальной и понятной.

Что происходит внутри и почему это работает

recognizeForVideo получает кадр и timestamp. Результат может быть пустым, содержать несколько рук и несколько категорий. Optional chaining защищает код от отсутствующих результатов. Логику держите отдельно от вывода: функция получает аргумент и возвращает значение, а интерфейс показывает его. Синхронное распознавание в основном потоке может блокировать интерфейс. Для тяжёлого сценария перенесите вычисления в Web Worker, как рекомендует документация.

ЧастьЗа что отвечаетЧто проверить
MediaStreamдоставляет кадры камеры в videoпоток запускается только после разрешения
Recognizerвозвращает жесты, score и landmarksrunningMode совпадает с методом VIDEO
Контроллерприменяет порог, cooldown и действиеодин устойчивый жест не повторяется каждый кадр

Score не является гарантией правильности. Освещение, фон, положение ладони и модель камеры меняют качество. Пользователь должен видеть распознанную команду и иметь обычные кнопки. Не делайте жест единственным способом выполнить важное действие. Не прячьте поток в одном обработчике: сохраните вход, проверьте его, вызовите операцию и только затем обновите интерфейс.

Проверьте границу Закройте ладонь или выйдите из кадра. Результат должен стать «Нет руки», а предыдущая команда не должна повторяться. Меняйте одно условие за прогон, чтобы видеть причину.

Проверяем проект и добавляем свою функцию

Добавьте состояние armed: действие разрешается только после жеста Closed_Fist, а затем ждёт Thumb_Up. Это уменьшит случайные команды. До правки запишите ожидаемое поведение одним предложением. После граничного теста повторите обычный сценарий.

Проверка своими руками
  1. Сохраните ожидаемый результат: после разрешения камеры видео появляется, уверенный жест меняет карточку один раз, а отсутствие руки не вызывает действий.
  2. Измените правило: добавьте нейтральный жест подтверждения и отдельную кнопку остановки камеры. Сначала предскажите итог.
  3. Передайте граничное значение и убедитесь, что приложение не падает.
  4. Верните корректные данные и объясните роли трёх основных частей.
Готово, если выполняются все пункты
  • элемент video показывает локальный поток
  • runningMode VIDEO готов к кадрам
  • результат содержит категорию и score
  • один жест меняет слайд ровно один раз

Надёжность интерфейса определяется не только моделью, но и правилами между последовательными кадрами. Полезная правка проходит от нового ввода до видимого результата.

Четыре контрольные точки MediaPipe Gesture Recognizer
Четыре проверки перед следующим шагом. Каждый следующий этап начинается после наблюдаемого результата.

Что запомнить и куда двигаться дальше

Останавливайте tracks при уходе со страницы, явно показывайте активную камеру и не отправляйте кадры на сервер без необходимости и согласия. Для закрепления откройте в распознавании текста с фото, в локальном ИИ в браузере и в AI-расширении Chrome.

Как изучить тему в Кодике

Сначала закрепите async/await, mediaDevices и requestAnimationFrame, затем подключайте модель. Сначала восстановите главную функцию и проверьте её на трёх значениях.

ШагЧто разобратьМини-проверка
1. ОсноваDOM, async/await, модули и видеопотокОбъясните вход и выход функции.
2. ИнструментFilesetResolver, runningMode VIDEO и recognizeForVideoПовторите команду по памяти.
3. ПроектПорог, cooldown и две команды интерфейсаПроверьте два сценария.
4. РефакторингWorker, сглаживание и приватность камерыРазделите ввод, логику и вывод.

Протестируйте разные руки, освещение, отсутствие камеры и отказ разрешения до добавления новых жестов. Базовый синтаксис закрепите через курс JavaScript.

Действие каждый кадр

Один жест вызывает десятки команд. Добавьте cooldown или конечный автомат.

Нет проверки пустого результата

Когда рука исчезает, обращение к gestures[0][0] падает. Используйте optional chaining.

Неправильный runningMode

Метод VIDEO не соответствует конфигурации IMAGE. Создайте recognizer с VIDEO.

Камера без обычных кнопок

Пользователь без камеры или с ограничениями не может управлять. Оставьте доступный fallback.

Сверяйтесь с первичной документацией. Команды и ограничения примера проверены по официальной документации MediaPipe Gesture Recognizer for Web. Если версия инструмента изменилась, официальный источник важнее старого скриншота.

Что получится в итоге

Готовый результат проекта: Управляем сайтом жестами через веб-камеру: MediaPipe + JavaScript
Так выглядит законченный учебный проект: есть понятный вход, видимый результат, защита от неверных данных и место для следующего улучшения.

Короткие ответы
Зачем нужен cooldown?

Он не даёт одному жесту запускать действие на каждом видеокадре.

Что возвращает Gesture Recognizer кроме имени?

Уверенность категории, landmarks руки и дополнительные данные результата.

Что проверять первым, если MediaPipe Gesture Recognizer не запускается?

Версию среды, текущую папку, команду запуска и первую строку ошибки.

Как понять, что проект MediaPipe Gesture Recognizer работает?

Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай.

Можно ли начать с готового кода?

Да. Добейтесь результата, измените одно правило и восстановите ключевую функцию без копирования.

Сделайте один осознанный шаг дальше

Выберите одно улучшение и проведите его от ввода до результата.

Если не хватает основы, перейдите курс JavaScript, затем восстановите ключевую функцию без подсказки.