代码之家  ›  专栏  ›  技术社区  ›  msj121

HTML将WebGL画布另存为图像

  •  7
  • msj121  · 技术社区  · 7 年前

    我正在使用 https://github.com/auduno/clmtrackr

    https://github.com/auduno/clmtrackr/blob/dev/examples/facedeform.html

    问题是我显然尝试了“canvas.dataToURL()”。我可以将网络摄像头的视频作为图像;但是,覆盖图像始终是透明的。

    我试图用这种纹理在画布上画画,但也没用。。。。

    https://codepen.io/msj121/pen/RgXjYK

    我想将整个图像覆盖保存到png,我想是“dataToURL”。

    // when everything is ready, automatically start everything ?
    
                    var vid = document.getElementById('videoel');
                    var vid_width = vid.width;
                    var vid_height = vid.height;
                    var overlay = document.getElementById('overlay');
                    var overlayCC = overlay.getContext('2d');
                    var webgl_overlay = document.getElementById('webgl');
    
                    // canvas for copying videoframes to
                    var videocanvas = document.createElement('CANVAS');
                    videocanvas.width = vid_width;
                    videocanvas.height = vid_height;
    
                    /*********** Setup of video/webcam and checking for webGL support *********/
    
                    var videoReady = false;
                    var imagesReady = false;
    
                    function enablestart() {
                        if (videoReady && imagesReady) {
                            var startbutton = document.getElementById('startbutton');
                            startbutton.value = "start";
                            startbutton.disabled = null;
                        }
                    }
    
                    $(window).load(function() {
                        imagesReady = true;
                        enablestart();
                    });
    
                    var insertAltVideo = function(video) {
                        if (supports_video()) {
                            if (supports_webm_video()) {
                                video.src = "./media/cap13_edit2.webm";
                            } else if (supports_h264_baseline_video()) {
                                video.src = "./media/cap13_edit2.mp4";
                            } else {
                                return false;
                            }
                            fd.init(webgl_overlay);
                            return true;
                        } else return false;
                    }
    
                    // check whether browser supports webGL
                    var webGLContext;
                    var webGLTestCanvas = document.createElement('canvas');
                    if (window.WebGLRenderingContext) {
                        webGLContext = webGLTestCanvas.getContext('webgl') || webGLTestCanvas.getContext('experimental-webgl');
                        if (!webGLContext || !webGLContext.getExtension('OES_texture_float')) {
                            webGLContext = null;
                        }
                    }
                    if (webGLContext == null) {
                        alert("Your browser does not seem to support WebGL. Unfortunately this face mask example depends on WebGL, so you'll have to try it in another browser. :(");
                    }
    
                    function gumSuccess( stream ) {
                        // add camera stream if getUserMedia succeeded
                        if ("srcObject" in vid) {
                            vid.srcObject = stream;
                        } else {
                            vid.src = (window.URL && window.URL.createObjectURL(stream));
                        }
                        vid.onloadedmetadata = function() {
                            // resize overlay and video if proportions are different
                            var proportion = vid.videoWidth/vid.videoHeight;
                            vid_width = Math.round(vid_height * proportion);
                            vid.width = vid_width;
                            overlay.width = vid_width;
                            webgl_overlay.width = vid_width;
                            videocanvas.width = vid_width;
    
                            fd.init(webgl_overlay);
                            vid.play();
                        }
                    }
    
                    function gumFail() {
                        // fall back to video if getUserMedia failed
                        insertAltVideo(vid);
                        alert("There was some problem trying to fetch video from your webcam, using a fallback video instead.");
                    }
    
                    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
                    window.URL = window.URL || window.webkitURL || window.msURL || window.mozURL;
    
                    // check for camerasupport
                    if (navigator.mediaDevices) {
                        navigator.mediaDevices.getUserMedia({video : true}).then(gumSuccess).catch(gumFail);
                    } else if (navigator.getUserMedia) {
                        navigator.getUserMedia({video : true}, gumSuccess, gumFail);
                    } else {
                        insertAltVideo(vid);
                        alert("Your browser does not seem to support getUserMedia, using a fallback video instead.");
                    }
    
                    vid.addEventListener('canplay', function() {videoReady = true;enablestart();}, false);
    
                    /*********** Code for face substitution *********/
    
                    var animationRequest;
                    var positions;
    
                    var ctrack = new clm.tracker();
                    ctrack.init(pModel);
    
                    function startVideo() {
                        // start video
                        vid.play();
                        // start tracking
                        ctrack.start(vid);
                        // start drawing face grid
                        drawGridLoop();
                    }
    
                    var fd = new faceDeformer();
    
                    var mouth_vertices = [
                        [44,45,61,44],
                        [45,46,61,45],
                        [46,60,61,46],
                        [46,47,60,46],
                        [47,48,60,47],
                        [48,59,60,48],
                        [48,49,59,48],
                        [49,50,59,49],
                        [50,51,58,50],
                        [51,52,58,51],
                        [52,57,58,52],
                        [52,53,57,52],
                        [53,54,57,53],
                        [54,56,57,54],
                        [54,55,56,54],
                        [55,44,56,55],
                        [44,61,56,44],
                        [61,60,56,61],
                        [56,57,60,56],
                        [57,59,60,57],
                        [57,58,59,57],
                        [50,58,59,50],
                    ];
    
                    var extendVertices = [
                        [0,71,72,0],
                        [0,72,1,0],
                        [1,72,73,1],
                        [1,73,2,1],
                        [2,73,74,2],
                        [2,74,3,2],
                        [3,74,75,3],
                        [3,75,4,3],
                        [4,75,76,4],
                        [4,76,5,4],
                        [5,76,77,5],
                        [5,77,6,5],
                        [6,77,78,6],
                        [6,78,7,6],
                        [7,78,79,7],
                        [7,79,8,7],
                        [8,79,80,8],
                        [8,80,9,8],
                        [9,80,81,9],
                        [9,81,10,9],
                        [10,81,82,10],
                        [10,82,11,10],
                        [11,82,83,11],
                        [11,83,12,11],
                        [12,83,84,12],
                        [12,84,13,12],
                        [13,84,85,13],
                        [13,85,14,13],
                        [14,85,86,14],
                        [14,86,15,14],
                        [15,86,87,15],
                        [15,87,16,15],
                        [16,87,88,16],
                        [16,88,17,16],
                        [17,88,89,17],
                        [17,89,18,17],
                        [18,89,93,18],
                        [18,93,22,18],
                        [22,93,21,22],
                        [93,92,21,93],
                        [21,92,20,21],
                        [92,91,20,92],
                        [20,91,19,20],
                        [91,90,19,91],
                        [19,90,71,19],
                        [19,71,0,19]
                    ]
    
                    function drawGridLoop() {
                        // get position of face
                        positions = ctrack.getCurrentPosition();
    
                        overlayCC.clearRect(0, 0, vid_width, vid_height);
                        if (positions) {
                            // draw current grid
                            ctrack.draw(overlay);
                        }
                        // check whether mask has converged
                        var pn = ctrack.getConvergence();
                        if (pn < 0.4) {
                            drawMaskLoop();
                        } else {
                            requestAnimFrame(drawGridLoop);
                        }
                    }
    
                    function drawMaskLoop() {
                        videocanvas.getContext('2d').drawImage(vid,0,0,videocanvas.width,videocanvas.height);
    
                        var pos = ctrack.getCurrentPosition();
    
                        if (pos) {
                            // create additional points around face
                            var tempPos;
                            var addPos = [];
                            for (var i = 0;i < 23;i++) {
                                tempPos = [];
                                tempPos[0] = (pos[i][0] - pos[62][0])*1.3 + pos[62][0];
                                tempPos[1] = (pos[i][1] - pos[62][1])*1.3 + pos[62][1];
                                addPos.push(tempPos);
                            }
                            // merge with pos
                            var newPos = pos.concat(addPos);
    
                            var newVertices = pModel.path.vertices.concat(mouth_vertices);
                            // merge with newVertices
                            newVertices = newVertices.concat(extendVertices);
    
                            fd.load(videocanvas, newPos, pModel, newVertices);
    
                            var parameters = ctrack.getCurrentParameters();
                            for (var i = 6;i < parameters.length;i++) {
                                parameters[i] += ph['component '+(i-3)];
                            }
                            positions = ctrack.calculatePositions(parameters);
    
                            overlayCC.clearRect(0, 0, vid_width, vid_height);
                            if (positions) {
                                // add positions from extended boundary, unmodified
                                newPos = positions.concat(addPos);
                                // draw mask on top of face
                                fd.draw(newPos);
                            }
                        }
                        animationRequest = requestAnimFrame(drawMaskLoop);
                    }
    
                    /*********** Code for stats **********/
    
                    stats = new Stats();
                    stats.domElement.style.position = 'absolute';
                    stats.domElement.style.top = '0px';
                    document.getElementById('container').appendChild( stats.domElement );
    
                    document.addEventListener("clmtrackrIteration", function(event) {
                        stats.update();
                    }, false);
    
                    /********** parameter code *********/
    
                    var pnums = pModel.shapeModel.eigenValues.length-2;
                    var parameterHolder = function() {
                        for (var i = 0;i < pnums;i++) {
                            this['component '+(i+3)] = 0;
                        }
                        this.presets = 0;
                    };
    
                    var ph = new parameterHolder();
                    var gui = new dat.GUI();
    
                    var presets = {
                        "unwell" : [0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                        "inca" : [0, 0, -9, 0, -11, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0],
                        "cheery" : [0, 0, -9, 9, -11, 0, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0],
                        "dopey" : [0, 0, 0, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0],
                        "longface" : [0, 0, 0, 0, -15, 0, 0, -12, 0, 0, 0, 0, 0, 0, -7, 0, 0, 5],
                        "lucky" : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -6, 12, 0, 0],
                        "overcute" : [0, 0, 0, 0, 16, 0, -14, 0, 0, 0, 0, 0, -7, 0, 0, 0, 0, 0],
                        "aloof" : [0, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, -2, 0, 0, 10],
                        "evil" : [0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, -8],
                        "artificial" : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, -16, 0, 0, 0, 0, 0],
                        "none" : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                    };
    
                    var control = {};
                    var eig = 0;
                    for (var i = 0;i < pnums;i++) {
                        eig = Math.sqrt(pModel.shapeModel.eigenValues[i+2])*3
                        control['c'+(i+3)] = gui.add(ph, 'component '+(i+3), -5*eig, 5*eig).listen();
                    }
    
                    /********** defaults code **********/
    
                    function switchDeformedFace(e) {
                        //var split = ph.presets.split(",");
                        for (var i = 0;i < pnums;i++) {
                            ph['component '+(i+3)] = presets[e.target.value][i];
                        }
                    }
    
                    document.getElementById('deform').addEventListener('change', switchDeformedFace, false);
    
                    for (var i = 0;i < pnums;i++) {
                        ph['component '+(i+3)] = presets['unwell'][i];
                    }
    
    2 回复  |  直到 7 年前
        1
  •  11
  •   Eddie Velasquez    7 年前

    在stackoverflow上,webgl画布为空白的原因已经在这里回答了至少10次

    Saving canvas to image via canvas.toDataURL results in black rectangle

    Canvas toDataURL() returns blank image only in Firefox

    toDataURL() of webgl canvas returning transparent image

    Why does my canvas go blank after converting to image?

    我知道还有几个,但我懒得搜索所有的

    我没有将其标记为副本的唯一原因是,您希望从2张画布中获得1个png。

    如果你只想要一个png,那么你需要从一个画布上抓取。因此,将WebGL画布绘制到视频画布中,然后调用 toDataURL 在视频画布上。

    const vctx = videocanvas.getContext('2d');
    vctx.drawImage(webGLTestCanvas, 0, 0); 
    const capturedImage = videocanvas.toDataURL();
    
        2
  •  0
  •   Bryce    5 年前

    {preserveDrawingBuffer: true} 初始化画布时。在我的例子中,我正在从事一个项目,在该项目中,使用这种方法会产生不良的副作用,使画布无法在绘图帧之间正确地清除。

    在打电话之前,我立即在当前帧上重新绘制了所有内容,从而绕过了这个问题 toDataUrl() .