Web 端即時防擋臉彈幕(基於機器學習)
防擋臉彈幕,也就是大量彈幕飄過,但不會遮擋影片畫面中的人物,看起來像是從人物背後飄過去的。
機器學習已經火了好幾年了,但很多人都不知道瀏覽器中也能運行這些能力;
本文介紹在視頻彈幕方面的實踐優化過程,文末列舉了一些本方案可適用的場景,期望能開啟一些腦洞。
mediapipe Demo(https://google.github.io/mediapipe/)展示
主流防擋臉彈幕實現原理
點播
up 上傳影片
伺服器後台計算提取影片畫面中的人像區域,轉換成svg 儲存
客戶端播放影片的同時,從伺服器下載svg與彈幕合成,人像區域不顯示彈幕
直播
- 主播推流時,即時(主播設備)從畫面提取人像區域,轉換成svg
- 將svg 資料合併到視訊串流中(SEI),推流至伺服器
- 客戶端播放影片同時,從視訊串流(SEI)解析出svg
- 將svg 與彈幕合成,人像區域不顯示彈幕
本文實現方案
客戶端播放視頻同時,實時從畫面提取人像區域信息,將人像區域信息導出成圖片與彈幕合成,人像區域不顯示彈幕。
實作原理
- 採用機器學習開源程式庫從視訊畫面即時擷取人像輪廓,如Body Segmentation(https://github.com/tensorflow/tfjs-models/blob/ master/body-segmentation/README.md)
- 將人像輪廓轉導出為圖片,設定彈幕層的 mask-image(https://developer.mozilla.org/zh-CN/docs/ Web/CSS/mask-image)
比較傳統(直播SEI實時)方案
優點:
- 易於實現;只需要Video標籤一個參數,無需多端協同配合
- 無網路頻寬消耗
缺點:
- 理論效能極限劣於傳統方案;相當於效能資源換網絡資源
面臨的問題
眾所周知,JavaScript 的效能較差,因此不適合用於處理CPU 密集型任務。由官方demo變成工程實踐,最大的挑戰就是-效能。
這次實作最終將 CPU 佔用優化到 5% 左右(2020 M1 Macbook),達到生產可用狀態。
實踐調優過程
選擇機器學習模型
BodyPix (https://github.com/tensorflow/tfjs-models/blob/master/body-segmentation/ src/body_pix/README.md)
精確度太差,臉部狹窄,有很明顯的彈幕與人物臉部邊緣重疊現象
# BlazePose(https://github.com/tensorflow/tfjs-models/blob/master/pose-detection/src/blazepose_mediapipe/README.md)
#精確度優秀,且提供了肢體點位資訊,但效能較差
傳回資料結構範例
[{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)
精確度優秀(跟BlazePose 模型效果一致),CPU 佔用相對BlazePose 模型降低15% 左右,效能取勝,但返回資料中不提供肢體點位資訊
返回資料結構範例
{maskValueToLabel: (maskValue: number) => { return 'person' },mask: {toCanvasImageSource(): ...toImageData(): ...toTensor(): ...getUnderlyingType(): ...}}
初版實作
參考MediaPipe SelfieSegmentation 模型 官方實作(https://github.com/tensorflow/tfjs-models/blob /master/body-segmentation/README.md#bodysegmentationdrawmask),未做優化的情況下 CPU 佔用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)
降低提取頻率,平衡性能-體驗
#一般視頻30FPS,嘗試彈幕遮罩(後稱Mask)刷新頻率降為15FPS,體驗上還能接受
window.setTimeout(detect, 66) // 33 => 66
此時,CPU 佔用50% 左右
解決效能瓶頸
分析火焰圖可發現,效能瓶頸在 toBinaryMask 和 toDataURL
重寫toBinaryMask
分析原始碼,結合列印segmentation的訊息,發現segmentation.mask .toCanvasImageSource可取得原始ImageBitmap對象,即是模型擷取出來的資訊。嘗試自己編寫程式碼,將ImageBitmap轉換為遮罩(Mask),以取代使用開源程式庫所提供的預設實作。
實現原理
async function detect (): Promise<void> {const segmentation = await segmenter.segmentPeople(videoEl) context.clearRect(0, 0, canvas.width, canvas.height)// 1. 将`ImageBitmap`绘制到 Canvas 上context.drawImage(// 经验证 即使出现多人,也只有一个 segmentationawait segmentation[0].mask.toCanvasImageSource(),0, 0,canvas.width, canvas.height)// 2. 设置混合模式context.globalCompositeOperation = 'source-out'// 3. 反向填充黑色context.fillRect(0, 0, canvas.width, canvas.height)// 导出Mask图片,需要的是轮廓,图片质量设为最低handler(canvas.toDataURL('image/png', 0)) window.setTimeout(detect, 66)}
第2、3 步相當於給人像區域外的內容填充黑色(反向填充ImageBitmap),是為了配合css(mask-image), 不然只有當彈幕飄到人像區域才可見(與目標效果正好相反)。
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,提升页面加载性能。
- 分别打包一个 loader,一个主体
- 由业务方 import loader,首次启用时异步加载主体
这个两步前端工程已经非常成熟了,略过细节。
运行效果
总结
过程
- 选择高性能模型后,初始状态 CPU 70%
- 降低 Mask 刷新频率(15FPS),CPU 50%
- 重写开源库实现(toBinaryMask),CPU 33%
- 多线程优化,CPU 15%
- 降低分辨率,CPU 5%
- 判断画面是否有人,无人时 CPU 接近 0%
CPU 数值指主线程占用
注意事项
- 兼容性:Chrome 79及以上,不支持 Firefox、Safari。因为使用了OffscreenCanvas
- 不应创建多个或多次创建segmenter实例(bodySegmentation.createSegmenter),如需复用请保存实例引用,因为:
- 创建实例时低性能设备会有明显的卡顿现象
- 会内存泄露;如果无法避免,这是mediapipe 内存泄露 解决方法(https://github.com/google/mediapipe/issues/2819#issuecomment-1160335349)
经验
- 优化完成之后,提取并应用 Mask 关键计算量在 GPU (30%左右),而不是 CPU
- 性能优化需要业务场景分析,防挡弹幕场景可以使用低分辨率、低刷新率的 mask-image,能大幅减少计算量
- 该方案其他应用场景:
- 替换/模糊人物背景
- 人像马赛克
- 人像抠图
- 卡通头套,虚拟饰品,如猫耳朵、兔耳朵、带花、戴眼镜什么的(换一个模型,略改)
- 关注Web 神经网络 API (https://mp.weixin.qq.com/s/v7-xwYJqOfFDIAvwIVZVdg)进展,以后实现相关功能也许会更简单
本期作者
刘俊
嗶哩嗶哩資深開發工程師
以上是Web 端即時防擋臉彈幕(基於機器學習)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undress AI Tool
免費脫衣圖片

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

幣安官網唯一正確入口為域名結尾為.com的官方網站,且無任何多餘符號或子目錄;2. 驗證官網真實性需檢查SSL證書、通過官方社交媒體核對域名並警惕釣魚鏈接;3. 常見詐騙手段包括仿冒域名、虛假客服誘導及非官方渠道的APP下載陷阱;4. 安全訪問建議包括啟用雙重驗證、使用瀏覽器書籤保存官網地址並定期檢查設備授權情況,以確保賬戶安全完整。

確認官網地址為www.okx.com,手動輸入以防釣魚;2. 確保安卓系統5.0以上,預留100MB空間並開啟“允許未知來源”權限;3. 通過官網下載Android版v6.135.0的APK文件,建議校驗SHA256哈希值;4. 點擊APK文件安裝,手動允許“繼續安裝”或“信任此來源”;5. 授予存儲、網絡等必要權限;6. 安裝完成後在桌面打開歐易OKX圖標即可。

首先通過官方渠道下載幣安App,1、點擊文中提供的官方下載鏈接進行下載,遇瀏覽器安全提示時選擇“仍要下載”;2、下載完成後在通知欄或文件管理器中找到安裝包,點擊啟動安裝並允許系統授權;3、安裝成功後點擊桌面圖標打開應用,完成註冊登錄並開啟二次驗證以保障賬戶安全。整個過程需保持網絡穩定,且務必避免使用非官方渠道下載,確保資產安全。

1、Binance币安以庞大的交易量和丰富的交易对著称,提供多元交易模式与完善生态系统,并通过SAFU基金和多重安全技术保障用户资产安全且高度重视合规运营;2、OKX欧易提供广泛的数字资产交易服务和统一交易账户模式,积极布局Web3领域,并通过严格风控和用户教育提升交易安全与体验;3、gate.io芝麻开门以上币速度快和币种丰富见长,提供多样化交易工具与增值服务,采用多重安全验证机制并坚持资产储备透明化以增强用户信任;4、火币Huobi凭借深厚的行业积累提供一站式数字资产服务,拥有强大交易深度与

Binance:以高流动性、多币种支持、多样化交易模式及强大安全系统著称;2. OKX:提供多元交易产品、布局DeFi与NFT、具备高性能撮合引擎;3. Huobi:深耕亚洲市场、注重合规运营、提供专业服务;4. Coinbase:合规性强、界面友好、适合新手且为上市公司;5. Kraken:安全措施严格、支持多种法币、透明度高;6. Bybit:专注衍生品交易、低延迟、风控完善;7. KuCoin:币种丰富、支持新兴项目、持有KCS可享分红;8. Gate.io:上线新币频繁、具Copy Tr

歐交易所是一款全球領先的數字資產服務平台,為廣大用戶提供多樣化的數字產品交易與金融服務。其官方應用程序設計友好,操作便捷,致力於為用戶創造一個安全、穩定的交易環境。

智能合約是存儲在區塊鏈上的自動執行程序,其核心在於通過代碼實現“如果…那麼…”邏輯,以去中心化、不可篡改的方式執行協議。 1. 編寫代碼:使用Solidity等語言定義合約邏輯;2. 編譯:將代碼轉換為機器可讀的字節碼;3. 部署:通過交易將字節碼發佈到區塊鏈並生成唯一地址;4. 觸發執行:當預設條件滿足時,合約自動運行;5. 記錄結果:所有操作被永久記錄在鏈上,確保透明可查。它解決了傳統協議中的信任、效率、成本、透明度和執行風險問題,廣泛應用於DeFi、供應鏈、版權管理、投票、保險和遊戲等領域。

答案是:請通過官方渠道訪問和下載OKX。 1. 訪問全球官方網站www.okx.com,手動輸入網址確保安全;2. 在官網右上角點擊“下載”按鈕;3. 根據設備選擇iOS或Android版本;4. 按照官方指引完成安裝;務必驗證域名是否為okx.com,警惕虛假鏈接,始終使用官方渠道下載和更新應用,以保障賬戶與資產安全。
