Serangan anti-muka, iaitu, sebilangan besar sekatan terapung, tetapi tidak menyekat orang dalam skrin video Ia kelihatan seperti terapung dari belakang orang itu.
Pembelajaran mesin telah popular selama beberapa tahun, tetapi ramai orang tidak tahu bahawa keupayaan ini juga boleh dijalankan dalam penyemak imbas
Artikel ini memperkenalkan proses pengoptimuman praktikal dalam rentetan video, disenaraikan; pada akhir artikel Beberapa senario di mana penyelesaian ini terpakai diterangkan, dengan harapan dapat membuka beberapa idea.
Demo mediapipe (https://google.github.io/mediapipe/) menunjukkan
Muat naik video
Pengiraan latar belakang pelayan mengekstrak kawasan potret dalam skrin video dan menukarnya kepada storan svg
Semasa pelanggan memainkan video, ia memuat turun svg daripada pelayan Digabungkan dengan benteng, benteng tidak dipaparkan dalam kawasan potret
Semasa pelanggan memainkan video, maklumat kawasan potret diekstrak daripada skrin dalam masa nyata, dan maklumat kawasan potret dieksport ke dalam gambar dan peluru Sintesis skrin, rentetan tidak akan dipaparkan dalam kawasan potret.
Berbanding dengan penyelesaian tradisional (SEI secara langsung masa nyata)
Kelebihan:
Kelemahan:
JavaScript diketahui mempunyai prestasi yang lemah, menjadikannya tidak sesuai untuk CPU- tugasan intensif. Daripada demo rasmi kepada amalan kejuruteraan, cabaran terbesar ialah prestasi.
Amalan ini akhirnya mengoptimumkan penggunaan CPU kepada kira-kira 5% (2020 M1 Macbook), mencapai keadaan sedia pengeluaran.
BodyPix (https://github.com/tensorflow/tfjs-models/blob/master/body-segmentation / src/body_pix/README.md)
Ketepatan terlalu lemah, mukanya sempit, dan jelas terdapat pertindihan antara rentetan dan tepi muka watak
BlazePose (https://github.com/tensorflow/tfjs-models/blob/master/pose-detection/src/blazepose_mediapipe/README.md)
Ketepatan yang sangat baik dan menyediakan maklumat titik badan, Tetapi prestasinya kurang baik
Contoh struktur data pengembalian
[{score: 0.8,keypoints: [{x: 230, y: 220, score: 0.9, score: 0.99, name: "nose"},{x: 212, y: 190, score: 0.8, score: 0.91, name: "left_eye"},...],keypoints3D: [{x: 0.65, y: 0.11, z: 0.05, score: 0.99, name: "nose"},...],segmentation: {maskValueToLabel: (maskValue: number) => { return 'person' },mask: {toCanvasImageSource(): ...toImageData(): ...toTensor(): ...getUnderlyingType(): ...}}}]
MediaPipe SelfieSegmentation (https://github.com/tensorflow/tfjs-models/blob/ master /body-segmentation/src/selfie_segmentation_mediapipe/README.md)
Ketepatan yang sangat baik (kesan yang sama seperti model BlazePose), penggunaan CPU adalah kira-kira 15% lebih rendah daripada model BlazePose, prestasi lebih baik, tetapi anggota badan tidak disediakan dalam maklumat Point data yang dikembalikan
Contoh struktur data pulangan
{maskValueToLabel: (maskValue: number) => { return 'person' },mask: {toCanvasImageSource(): ...toImageData(): ...toTensor(): ...getUnderlyingType(): ...}}
Rujuk kepada pelaksanaan rasmi model MediaPipe SelfieSegmentation (https://github.com/tensorflow/ tfjs-models/blob /master/body-segmentation/README.md#bodysegmentationdrawmask), tanpa pengoptimuman, CPU mengambil kira-kira 70%
const canvas = document.createElement('canvas')canvas.width = videoEl.videoWidthcanvas.height = videoEl.videoHeightasync function detect (): Promise<void> {const segmentation = await segmenter.segmentPeople(videoEl)const foregroundColor = { r: 0, g: 0, b: 0, a: 0 }const backgroundColor = { r: 0, g: 0, b: 0, a: 255 } const mask = await toBinaryMask(segmentation, foregroundColor, backgroundColor) await drawMask(canvas, canvas, mask, 1, 9)// 导出Mask图片,需要的是轮廓,图片质量设为最低handler(canvas.toDataURL('image/png', 0)) window.setTimeout(detect, 33)} detect().catch(console.error)
Kurangkan kekerapan pengekstrakan dan mengimbangi pengalaman prestasi
Selesaikan kesesakan prestasi Menganalisis graf nyalaan, didapati bahawa kesesakan prestasi berada dalam toBinaryMask dan toDataURLMenulis Semula keBinaryMask🎜 >
Menganalisis kod sumber, digabungkan dengan pencetakan maklumat segmentasi, kami mendapati segmentation.mask .toCanvasImageSource boleh mendapatkan objek ImageBitmap asal, iaitu maklumat yang diekstrak oleh model. Cuba tulis kod anda sendiri untuk menukar ImageBitmap kepada Mask dan bukannya menggunakan pelaksanaan lalai yang disediakan oleh perpustakaan sumber terbuka. Prinsip Pelaksanaanwindow.setTimeout(detect, 66) // 33 => 66
globalCompositeOperation MDN(https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)
此时,CPU 占用 33% 左右
我原先认为toDataURL是由浏览器内部实现的,无法再进行优化,现在只有优化toDataURL这个耗时操作了。
虽没有替换实现,但可使用 OffscreenCanvas (https://developer.mozilla.org/zh-CN/docs/Web/API/OffscreenCanvas)+ Worker,将耗时任务转移到 Worker 中去, 避免占用主线程,就不会影响用户体验了。
并且ImageBitmap实现了Transferable接口,可被转移所有权,跨 Worker 传递也没有性能损耗(https://hughfenghen.github.io/fe-basic-course/js-concurrent.html#%E4%B8%A4%E4%B8%AA%E6%96%B9%E6%B3%95%E5%AF%B9%E6%AF%94)。
// 前文 detect 的反向填充 ImageBitmap 也可以转移到 Worker 中// 用 OffscreenCanvas 实现, 此处略过 const reader = new FileReaderSync()// OffscreenCanvas 不支持 toDataURL,使用 convertToBlob 代替offsecreenCvsEl.convertToBlob({type: 'image/png',quality: 0}).then((blob) => {const dataURL = reader.readAsDataURL(blob)self.postMessage({msgType: 'mask',val: dataURL})}).catch(console.error)
可以看到两个耗时的操作消失了
此时,CPU 占用 15% 左右
继续分析,上图重新计算样式(紫色部分)耗时约 3ms
Demo 足够简单很容易推测到是这行代码导致的,发现 imgStr 大概 100kb 左右(视频分辨率 1280x720)。
danmakuContainer.style.webkitMaskImage = `url(${imgStr})
通过canvas缩小图片尺寸(360P甚至更低),再进行推理。
优化后,导出的 imgStr 大概 12kb,重新计算样式耗时约 0.5ms。
此时,CPU 占用 5% 左右
虽然提取 Mask 整个过程的 CPU 占用已优化到可喜程度。
当在画面没人的时候,或没有弹幕时候,可以停止计算,实现 0 CPU 占用。
无弹幕判断比较简单(比如 10s 内收超过两条弹幕则启动计算),也不在该 SDK 实现范围,略过
第一步中为了高性能,选择的模型只有ImageBitmap,并没有提供肢体点位信息,所以只能使用getImageData返回的像素点值来判断画面是否有人。
画面无人时,CPU 占用接近 0%
依赖包的提交较大,构建出的 bundle 体积:684.75 KiB / gzip: 125.83 KiB
所以,可以进行异步加载SDK,提升页面加载性能。
这个两步前端工程已经非常成熟了,略过细节。
注意事项
本期作者
刘俊
Jurutera Pembangunan Kanan Bilibili
Atas ialah kandungan terperinci Perlindungan masa nyata terhadap rentetan penyekat muka di web (berdasarkan pembelajaran mesin). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!