# canvas 对视频处理

# 1. 使用 canvas 动态截取视频

# 1. 截取画面

1
2
3
4
5
6
7
8
9
10
11
//可以使用drawImage截取视频当前播放的这一帧画面。
this.ctx.drawImage(video,0,0,width,height)
//与处理图片一样可以使用getImageData获取某一帧的画面的rgba数据
let data = this.ctx.getImageData(0,0,width,height)
//处理后使用putImageData将某画面绘制到canvas上。
this.ctx.putImageData(data,0,0)
最后绘制时注意,视频的大小以及画布的大小,如果视频大于画布的大小可以考虑使用scale缩小坐标系,不过这样会导致画面变糊,不建议这样解决。众所周知,canvas有两个宽高,一个是画布的宽高,这个获取dom后设置即可,另一个是展示的宽高,这个用style设置即可。先获取视频的大小,将画布的大小设置成视频的大小,由于展示的画布大小小于视频这时会自动对画布的内容缩小。
video.onloadeddata=()=>{
canvas.width = video.videoWidth
canvas.height = video.videoHeight
}//视频加载完成后触发的一个事件

# 2. canvas 处理视频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//绘制视频
function record(){
ctx.drawImage(video,0,0) //绘制视频
setTimeout(()=>{
record()
},16) //每隔16ms调用自己
}
既然都拿到视频画面了,可以对视频每一帧处理,比如将图片变为灰度图片。
function record(){
ctx.drawImage(video,0,0) //绘制视频
let imageData = ctx.getImageData(0,0,canvas.width,canvas.height)
for(let i=0;i<imageData.data.length;i+=4){
let r = imageData.data[i]
let g = imageData.data[i+1]
let b = imageData.data[i+2]
let avg = .299 * r + .587 * g + .114 * b
imageData.data[i] = avg
imageData.data[i+1] = avg
imageData.data[i+2] = avg
}
ctx.putImageData(imageData,0,0)
setTimeout(()=>{
record()
},16) //每隔16ms调用自己
}//不过这样处理之后,绘制的视频掉帧严重。

# 3. 合成视频

如果有一段绿幕视频,只要将这个画面用 drawImage 绘制,然后用 getImageData 获取画面的 rgba 数据,将所有纯绿色的像素点即 rb 为 0,g 为 255 的像素点的透明度改为 0 即完全透明,再将这个画面绘制到另一个视频即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<video src="./video/1.mp4" id="video" style="width: 600px; height: 400px;" controls></video>
<video src="./video/蓝幕.mp4" id="blue" style="width: 600px; height: 400px;" controls></video>
<button id="play">播放</button>
<canvas id="canvas" style="width: 600px; height: 400px;"></canvas>

let video = document.querySelector('#video')
let blue = document.querySelector('#blue')
let play = document.querySelector('#play')
let canvasblue = document.createElement('canvas')
let canvas = document.querySelector('#canvas')
let ctx = canvas.getContext('2d')
let ctxblue = canvasblue.getContext('2d')
//视频加载完成后,将画布的宽高设置成视频的宽高
blue.onloadeddata = ()=>{
canvasblue.width = blue.videoWidth
canvasblue.height = blue.videoHeight
}
video.onloadeddata = ()=>{
canvas.width = video.videoWidth
canvas.height = video.videoHeight
}
play.addEventListener('click',()=>{
blue.play()
video.play()
})
video.addEventListener('play',()=>{
setInterval(()=>{
ctxblue.drawImage(blue,0,0) //用画布绘制蓝幕视频
let data = ctxblue.getImageData(0,0,blue.videoWidth,blue.videoHeight)
for(let i=0;i<data.data.length;i+=4){
if(data.data[i+2]==255) data.data[i+3] = 0
//如果像素点蓝色为255则将其变为完全透明
}
ctxblue.putImageData(data,0,0) //将更改的数据绘制会原画布
ctx.drawImage(video,0,0) //绘制原视频
ctx.drawImage(canvasblue,0,0) //将绘制蓝幕的画布绘制到原视频。最后发现原视频掉帧严重。
},16) 每隔16ms绘制一次。
})

使用 canvas 处理视频 - Web API 接口参考 | MDN (mozilla.org)