最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

原生Js Canvas去除視頻綠幕背景的方法實現(xiàn)

 更新時間:2023年09月07日 15:02:20   作者:Raccom  
本文主要介紹了原生Js Canvas去除視頻綠幕背景的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

注: 這里的去除視頻背景并不是對視頻文件進行操作去除背景

如果需要對視頻扣除背景并導(dǎo)出可以使用 ffmpeg 等庫,這里僅作播放用所以采用這種方法

由于uniapp中的canvas經(jīng)過封裝,且 uniapp 的 drawImage 無法繪制視頻幀畫面,因此uniapp中不適用

實現(xiàn)過程是將視頻使用canvas逐幀截下來對截取的圖片進行處理,然后在canvas中顯示處理好的圖片

最后通過定時器高速處理替換,形成視頻播放的效果,效果如下圖?

邊緣仍然會有些綠幕的像素,可以通過其他的處理進行優(yōu)化

原理

首先使用canvas的 drawImage 方法將video的當(dāng)前幀畫面繪制到canvas中

然后再通過 getImageData 方法獲取當(dāng)前canvas的所有像素的 rgba 值組成的數(shù)組

獲取到的值為 [r,g,b,a,r,g,b,a,...] ,每一組 rgba 的值就是一個像素,所以獲取到的數(shù)組長度是canvas的像素的數(shù)量 * 4

通過判斷每一組 rgb 的值是否為綠幕像素,然后設(shè)置其透明通道的 alpha 的值為0實現(xiàn)效果

代碼

因為canvas會受到跨域的影響導(dǎo)致畫布被污染,因此首先需要將測試視頻下載到本地

如果直接本地打開html的話同樣會因為本地路徑報跨域錯誤,需要將html,js,測試視頻放在文件夾中部署一個本地服務(wù)器

可以使用 http-server

npm i http-server -g
# 切換到存放html,js,測試視頻的文件夾 運行命令即可部署本地服務(wù)器
http-server

或者

vsCode的 Live server 插件均可

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
        video{
            width: 480px;
            height: 270px;
        }
    </style>
  </head>
  <body>
    <video id="video"  src="./63e1dd7ddd2b0.mp4"  loop autoplay muted></video>
    <canvas id="output-canvas" width="480" height="270" willReadFrequently="true"></canvas>
    <script type="text/javascript" src="processor2.js"></script>
  </body>
</html>
// processor2.js
let video, canvas, ctx, canvas_tmp, ctx_tmp;
function init () {
    video = document.getElementById('video');
    canvas = document.getElementById('output-canvas');
    ctx = canvas.getContext('2d');
	// 創(chuàng)建的canvas寬高最好與顯示圖片的canvas、video寬高一致
    canvas_tmp = document.createElement('canvas');
    canvas_tmp.setAttribute('width', 480);
    canvas_tmp.setAttribute('height', 270);
    ctx_tmp = canvas_tmp.getContext('2d');
    video.addEventListener('play', computeFrame);
}
function computeFrame () {
    if (video) {
        if (video.paused || video.ended) return;
    }
    // 如果視頻比例和canvas比例不正確可能會出現(xiàn)顯示形變, 調(diào)整除的值進行比例調(diào)整
    ctx_tmp.drawImage(video, 0, 0, video.clientWidth / 1, video.clientHeight / 1);
	// 獲取到繪制的canvas的所有像素rgba值組成的數(shù)組
    let frame = ctx_tmp.getImageData(0, 0, video.clientWidth, video.clientHeight);
	// 共有多少像素點
    const pointLens = frame.data.length / 4;
    for (let i = 0; i < pointLens; i++) {
        let r = frame.data[i * 4];
        let g = frame.data[i * 4 + 1];
        let b = frame.data[i * 4 + 2];
        // 判斷如果rgb值在這個范圍內(nèi)則是綠幕背景,設(shè)置alpha值為0 
        // 同理不同顏色的背景調(diào)整rgb的判斷范圍即可
        if (r < 100 && g > 120 && b < 200) {
            frame.data[i * 4 + 3] = 0;
        }
    }
    // 重新繪制到canvas中顯示
    ctx.putImageData(frame, 0, 0);
    // 遞歸調(diào)用
    setTimeout(computeFrame, 0);
}
document.addEventListener("DOMContentLoaded", () => {
    init();
});

使用本地服務(wù)器訪問html即可看到效果,可以看到邊緣仍有綠色像素閃爍

一般情況這種就可以了,使用算法進行處理的話效果會更好,但相應(yīng)的資源的消耗也會提升,造成幀率下降

下面展示通過一些算法進行羽化和顏色過渡

羽化

// 返回canvas中第num個像素點所在的坐標(biāo)  12 -> [1, 12]
function numToPoint (num, width) {
    let col = num % width;
    let row = Math.floor(num / width);
    row = col === 0 ? row : row + 1;
    col = col === 0 ? width : col;
    return [row, col];
}
// 返回canvas中所在坐標(biāo)的num(index + 1)值  [1, 12] -> 12
function pointToNum (point, width) {
    let [row, col] = point;
    return (row - 1) * width + col
}
// 獲取輸入的坐標(biāo)周圍1像素內(nèi)的所有像素的坐標(biāo)組成的數(shù)組 [1, 1] -> [[1, 2], [2, 1], [2, 2]]
function getAroundPoint (point, width, height, area) {
    let [row, col] = point;
    let allAround = [];
    if (row > height || col > width || row < 0 || col < 0) return allAround;
    for (let i = 0; i < area; i++) {
        let pRow = row - 1 + i;
        for (let j = 0; j < area; j++) {
            let pCol = col - 1 + j;
            if (i === area % 2 && j === area % 2) continue;
            allAround.push([pRow, pCol]);
        }
    }
    return allAround.filter(([iRow, iCol]) => {
        return (iRow > 0 && iCol > 0) && (iRow <= height && iCol <= width);
    })
}

通過上面的函數(shù)獲取到一個選定的不透明的像素周圍的像素后,判斷周圍的像素的alpha值

如果周圍的像素有存在透明的像素,則重新計算選定像素的alpha值

顏色過渡

計算修改alpha值連帶計算周圍像素中rgb的各項平均值給選定像素

最終處理結(jié)果如下

代碼

// 新增羽化和顏色過渡
// processor2.js
let video, canvas, ctx, canvas_tmp, ctx_tmp;
function init () {
    video = document.getElementById('video');
    canvas = document.getElementById('output-canvas');
    ctx = canvas.getContext('2d');
	// 創(chuàng)建的canvas寬高最好與顯示圖片的canvas、video寬高一致
    canvas_tmp = document.createElement('canvas');
    canvas_tmp.setAttribute('width', 480);
    canvas_tmp.setAttribute('height', 270);
    ctx_tmp = canvas_tmp.getContext('2d');
    video.addEventListener('play', computeFrame);
}
function numToPoint (num, width) {
    let col = num % width;
    let row = Math.floor(num / width);
    row = col === 0 ? row : row + 1;
    col = col === 0 ? width : col;
    return [row, col];
}
function pointToNum (point, width) {
    let [row, col] = point;
    return (row - 1) * width + col
}
function getAroundPoint (point, width, height, area) {
    let [row, col] = point;
    let allAround = [];
    if (row > height || col > width || row < 0 || col < 0) return allAround;
    for (let i = 0; i < area; i++) {
        let pRow = row - 1 + i;
        for (let j = 0; j < area; j++) {
            let pCol = col - 1 + j;
            if (i === area % 2 && j === area % 2) continue;
            allAround.push([pRow, pCol]);
        }
    }
    return allAround.filter(([iRow, iCol]) => {
        return (iRow > 0 && iCol > 0) && (iRow <= height && iCol <= width);
    })
}
function computeFrame () {
    if (video) {
        if (video.paused || video.ended) return;
    }
    ctx_tmp.drawImage(video, 0, 0, video.clientWidth, video.clientHeight);
    let frame = ctx_tmp.getImageData(0, 0, video.clientWidth, video.clientHeight);
    //----- emergence ----------
    const height = frame.height;
    const width = frame.width;
    const pointLens = frame.data.length / 4;
    for (let i = 0; i < pointLens; i++) {
        let r = frame.data[i * 4];
        let g = frame.data[i * 4 + 1];
        let b = frame.data[i * 4 + 2];
        if (r < 150 && g > 200 && b < 150) {
            frame.data[i * 4 + 3] = 0;
        }
    }
    const tempData = [...frame.data]
    for (let i = 0; i < pointLens; i++) {
        if (frame.data[i * 4 + 3] === 0) continue
        const currentPoint = numToPoint(i + 1, width);
        const arroundPoint = getAroundPoint(currentPoint, width, height, 3);
        let opNum = 0;
        let rSum = 0;
        let gSum = 0;
        let bSum = 0;
        arroundPoint.forEach((position) => {
            const index = pointToNum(position, width);
            rSum = rSum + tempData[(index - 1) * 4];
            gSum = gSum + tempData[(index - 1) * 4 + 1];
            bSum = bSum + tempData[(index - 1) * 4 + 2];
            if (tempData[(index - 1) * 4 + 3] !== 255) opNum++;
        })
        let alpha = (255 / arroundPoint.length) * (arroundPoint.length - opNum);
        if (alpha !== 255) {
            // debugger
            frame.data[i * 4] = parseInt(rSum / arroundPoint.length);
            frame.data[i * 4 + 1] = parseInt(gSum / arroundPoint.length);
            frame.data[i * 4 + 2] = parseInt(bSum / arroundPoint.length);
            frame.data[i * 4 + 3] = parseInt(alpha);
        }
    }
    //------------------------
    ctx.putImageData(frame, 0, 0);
    setTimeout(computeFrame, 0);
}
document.addEventListener("DOMContentLoaded", () => {
    init();
});

到此這篇關(guān)于原生Js Canvas去除視頻綠幕背景的方法實現(xiàn)的文章就介紹到這了,更多相關(guān)Js Canvas去除視頻綠幕背景內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JS實現(xiàn)黑客帝國文字下落效果

    JS實現(xiàn)黑客帝國文字下落效果

    看過黑客帝國的朋友或許都對開頭的字幕效果很熟悉,自從影片播放以來,網(wǎng)頁設(shè)計者有不少都在模仿這種文字下落的效果,而且還有文字漸變效果,對我們學(xué)習(xí)研究JS還是挺有幫助的哦,下面跟著小編一起學(xué)習(xí)JS 黑客帝國文字下落效果吧
    2015-09-09
  • 高亮顯示web頁表格行的javascript代碼

    高亮顯示web頁表格行的javascript代碼

    本文從簡單的css高亮顯示表格的某一行說開去,探討了在不同瀏覽器下對于高亮功能的兼容性。闡述針對表格本身綁定javascript事件實現(xiàn)這一功能的方法。
    2010-11-11
  • BootStrap表單驗證實例代碼

    BootStrap表單驗證實例代碼

    這篇文章主要介紹了bootstrap表單驗證的實例代碼,代碼中包括引入的js文件,具體實現(xiàn)方法,大家參考本文
    2017-01-01
  • JS實現(xiàn)瀑布流效果

    JS實現(xiàn)瀑布流效果

    這篇文章主要為大家詳細介紹了JS實現(xiàn)瀑布流效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • JavaScript創(chuàng)建對象的幾種方式小結(jié)

    JavaScript創(chuàng)建對象的幾種方式小結(jié)

    這篇文章主要介紹了 JavaScript 中創(chuàng)建對象的多種方式,包括字面量方式、構(gòu)造函數(shù)方式、原型模式、() 方法、ES6 類,并分別說明了它們的特點和適用場景,強調(diào)在實際編程中要根據(jù)需求選擇合適的方式以提高代碼質(zhì)量和性能,需要的朋友可以參考下
    2024-12-12
  • 詳解webpack與SPA實踐之開發(fā)環(huán)境搭建

    詳解webpack與SPA實踐之開發(fā)環(huán)境搭建

    這篇文章主要介紹了詳解webpack與SPA實踐之開發(fā)環(huán)境搭建,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • javascript實現(xiàn)滾動條效果

    javascript實現(xiàn)滾動條效果

    這篇文章主要為大家詳細介紹了javascript實現(xiàn)滾動條效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • javascript 連連看代碼出爐

    javascript 連連看代碼出爐

    非常不錯的連連看實現(xiàn)代碼,大家可以運行下,看下效果。
    2009-06-06
  • require.js的用法詳解

    require.js的用法詳解

    本文給大家介紹require.js的用法,require.js的誕生是為了解決兩大問題,第一實現(xiàn)js文件的異步加載,避免網(wǎng)頁失去響應(yīng),第二管理模塊之間的依賴性,便于代碼的編寫和維護,對require.js用法感興趣的朋友可以參考下本篇文章
    2015-10-10
  • 在JavaScript中使用嚴(yán)格模式(Strict Mode)

    在JavaScript中使用嚴(yán)格模式(Strict Mode)

    這篇文章主要介紹了在JavaScript中使用嚴(yán)格模式(Strict Mode),除了正常運行模式,ECMAscript 5添加了第二種運行模式:"嚴(yán)格模式"(strict mode)。顧名思義,這種模式使得Javascript在更嚴(yán)格的條件下運行。,需要的朋友可以參考下
    2019-06-06

最新評論

文安县| 三河市| 惠水县| 和顺县| 林西县| 白银市| 永平县| 石门县| 上虞市| 小金县| 东平县| 富川| 丹巴县| 扬州市| 亚东县| 仙桃市| 丹凤县| 武城县| 永昌县| 克山县| 济南市| 乌什县| 安达市| 浮梁县| 平远县| 大厂| 洪洞县| 马鞍山市| 贡嘎县| 托克托县| 南陵县| 新兴县| 双柏县| 黑山县| 上栗县| 大连市| 东乡| 邯郸市| 昭苏县| 乐都县| 民丰县|