Обработка видео с помощью холста
Комбинируя возможности элемента video с холстом canvas, вы можете в реальном времени обрабатывать данные видео, чтобы добавить различные визуальные эффекты к отображаемому видео. Этот учебник демонстрирует, как выполнить хрома-кейинг (также известный как эффект «зеленый экран») с помощью кода JavaScript.
Содержание документа
HTML-документ, используемый для отображения этого контента, показан ниже.
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<title>Video test page</title>
<style>
body {
background: black;
color: #cccccc;
}
#c2 {
background-image: url(media/foo.png);
background-repeat: no-repeat;
}
div {
float: left;
border: 1px solid #444444;
padding: 10px;
margin: 10px;
background: #3b3b3b;
}
</style>
</head>
<body>
<div>
<video
id="video"
src="media/video.mp4"
controls
crossorigin="anonymous" />
</div>
<div>
<canvas id="c1" width="160" height="96"></canvas>
<canvas id="c2" width="160" height="96"></canvas>
</div>
<script src="processor.js"></script>
</body>
</html>
Основные моменты, которые следует запомнить:
- В этом документе создаются два элемента
canvasс идентификаторамиc1иc2. Холстc1используется для отображения текущей кадра исходного видео, аc2используется для отображения видео после применения эффекта хрома-кейинга;c2предварительно загружен неподвижным изображением, которое будет использоваться для замены зеленого фона в видео. - Код JavaScript импортируется из скрипта под названием
processor.js.
Код JavaScript
Код JavaScript в processor.js состоит из трех методов.
Инициализация игрока хрома-ключа
Метод doLoad() вызывается при первоначальной загрузке HTML-документа. Задача этого метода — подготовить переменные, необходимые для обработки кода хрома-кейинга, и настроить обработчик событий, чтобы мы могли обнаружить, когда пользователь начинает воспроизведение видео.
const processor = {};
processor.doLoad = function doLoad() {
const video = document.getElementById("video");
this.video = video;
this.c1 = document.getElementById("c1");
this.ctx1 = this.c1.getContext("2d");
this.c2 = document.getElementById("c2");
this.ctx2 = this.c2.getContext("2d");
video.addEventListener(
"play",
() => {
this.width = video.videoWidth / 2;
this.height = video.videoHeight / 2;
this.timerCallback();
},
false,
);
};
Этот код получает ссылки на элементы в HTML-документе, которые представляют особый интерес, а именно элемент video и два элемента canvas. Он также получает ссылки на контексты графики для каждого из двух холстов. Они будут использоваться, когда мы фактически будем выполнять эффект хрома-кейинга.
Затем вызывается addEventListener(), чтобы начать отслеживание элемента video, чтобы получать уведомления, когда пользователь нажимает кнопку воспроизведения на видео. В ответ на начало воспроизведения пользователем этот код получает ширину и высоту видео, делит каждую пополам (мы будем уменьшать размер видео при выполнении эффекта хрома-кейинга), затем вызывает метод timerCallback(), чтобы начать отслеживание видео и вычисление визуального эффекта.
Обратный вызов таймера
Обратный вызов таймера вызывается первоначально при запуске видео (когда происходит событие «воспроизведение»), а затем берет на себя ответственность за вызов периодически, чтобы запускать эффект ключения для каждого кадра.
processor.timerCallback = function timerCallback() {
if (this.video.paused || this.video.ended) {
return;
}
this.computeFrame();
setTimeout(() => {
this.timerCallback();
}, 0);
};
Первое, что делает обратный вызов, — это проверяет, воспроизводится ли видео; если нет, обратный вызов возвращается немедленно, ничего не делая.
Затем он вызывает метод computeFrame(), который выполняет эффект хрома-кейинга на текущем кадре видео.
Последнее, что делает обратный вызов, — это вызов setTimeout() для повторного планирования вызова как можно скорее. В реальном мире вы, вероятно, запланируете это на основе знаний о частоте кадров видео.
Обработка данных кадра видео
Метод computeFrame(), показанный ниже, отвечает за фактическое извлечение кадра данных и выполнение эффекта хрома-кейинга.
processor.computeFrame = function () {
this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
const frame = this.ctx1.getImageData(0, 0, this.width, this.height);
const data = frame.data;
for (let i = 0; i < data.length; i += 4) {
const red = data[i + 0];
const green = data[i + 1];
const blue = data[i + 2];
if (green > 100 && red > 100 && blue < 43) {
data[i + 3] = 0;
}
}
this.ctx2.putImageData(frame, 0, 0);
};
Когда эта процедура вызывается, элемент видео отображает последний кадр данных видео, который выглядит так:
Этот кадр видео копируется в контекст графики ctx1 первого холста, указав в качестве высоты и ширины значения, которые мы ранее сохранили, чтобы отобразить кадр в уменьшенном размере. Обратите внимание, что вы можете передать элемент видео в метод drawImage() контекста, чтобы нарисовать текущий кадр видео в контексте. Результат:
Вызов метода getImageData() на первом контексте извлекает копию исходных данных графики для текущего кадра видео. Это предоставляет сырые данные изображения в формате 32 бита, которые мы можем затем обрабатывать. Затем мы вычисляем количество пикселей в изображении, разделив общий размер данных изображения кадра на четыре.
Цикл for сканирует пиксели кадра, извлекая значения красного, зеленого и синего для каждого пикселя и сравнивая их с предопределенными числами, используемыми для обнаружения зеленого экрана, который будет заменен неподвижным фоновым изображением, импортированным из foo.png.
Каждый пиксель в данных изображения кадра, который определяется как часть зеленого экрана, имеет значение альфа заменено нулем, что указывает на то, что пиксель полностью прозрачен. В результате конечное изображение имеет всю область зеленого экрана на 100% прозрачным, так что при отрисовке в целевом контексте с помощью ctx2.putImageData результатом является наложение на статический фон.
Полученное изображение выглядит так:
Это повторяется по мере воспроизведения видео, так что каждый кадр обрабатывается и отображается с эффектом хрома-кейинга.
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas