在drawImage

时间:2019-06-18 01:06:00

标签: javascript ios cordova canvas html5-canvas

来自我的插件的链接: https://github.com/luisdemarchi/cordova-plugin-facedetection-lite

最终代码中的链接: https://github.com/luisdemarchi/example-cordova-facedetection/blob/master/www/index.html

问题: 我正在iOS应用程序(Cordova)中运行JavaScript,当我裁剪具有很多像素的Canvas并将其切成所需的大小时,可以跟上内存增长的速度,直到其限制和应用程序关闭为止。

我在做什么: 我正在创建我的第一个公共存储库,它将成为Cordova的面部检测组件。 C中有一个名为“ pico”的脚本,JavaScript中有一个翻译,我为插件使用了这些库,而在浏览器中,一切都很完美,但是在iOS(我从C库创建了一个库)中,我发生了内存泄漏在C中调用该方法后的几个步骤就会发生这种情况。问题显然出在示例代码中,而不是在库中。

IOS代码流:

  • 一个插件会打开本地iOS相机,并将帧转换为 HTML画布;
  • 我在设置20毫秒的超时时间内有函数循环:
  • 复制此Canvas的图像并创建另一个,高度和宽度的限制大小为90像素;
  • 将此图像发送到缩小为在检测到的面部坐标中返回的插件;
  • 同时,在第一个画布更新帧的同时,使用最新的协调面孔再次剪切此画布并穿上第三个画布;

enter image description here

我尝试过的事情:

  • 我通过requestAnimationFrame()删除了调整框架大小的操作
  • 在上下文中,我添加beginPath();
  • 将变量设置为null;
  • 调用“功能”删除
  • 如果等待1秒钟以调用切面方法,则可以防止内存泄漏;

代码

var updateFacePreview = function () {
    var loop = function () {
        if (faceBox.x > 0) {
            var facePreview = document.getElementById("facePreview");
            var facePreviewCtx = facePreview.getContext("2d", { alpha: false });
            facePreviewCtx.beginPath();
            facePreviewCtx.clearRect(0, 0, 400, 400);
            // console.log("x: " + parseInt(faceBox.x / scale) + " y: " + parseInt(faceBox.y / scale) + " size: " + parseInt(faceBox.size / scale));
            facePreviewCtx.drawImage(
                isIosApp ? cameraIosPreview : cameraPreview,
                parseInt(faceBox.x / scale),
                parseInt(faceBox.y / scale),
                parseInt(faceBox.size / scale),
                parseInt(faceBox.size / scale),
                0,
                0,
                400,
                400
            );
            delete facePreviewCtx;
            delete facePreview;
            delete cameraIosPreviewTemp;
            cameraIosPreviewTemp = null;
            facePreviewCtx = null;
            facePreview = null;
        }

        requestAnimationFrame(loop);
    }
    requestAnimationFrame(loop);
    // window.setTimeout(function () {
    //     updateFacePreview();
    // }, 100);
}

更新:

我发现,如果不更改图像的大小,则在剪切时不会发生内存泄漏。但是,如果放大或缩小1个像素,则会发生泄漏。

这是有效的代码段:

facePreviewCtx.drawImage(
    isIosApp ? cameraIosPreview : cameraPreview,
    10, 10, 300, 300,
    0, 0, 300, 300
);

发生内存泄漏的示例(仅在iOS的UIWebView中运行JS):

facePreviewCtx.drawImage(
    isIosApp ? cameraIosPreview : cameraPreview,
    10, 10, 300, 300,
    0, 0, 150, 150
);

1 个答案:

答案 0 :(得分:0)

有效的解决方案:

我正在创建一个临时的HTML Canvas,它会以原始大小捕获人脸而不缩小它,然后仅通过减小大小就为其他HTML Canvas制作了一个切口。

此解决方案不太理想,但是可以避免内存泄漏。以下源代码:

var updateFacePreview = function () {
    var loop = function () {
        if (faceBox.x > 0) {
            var faceSizeOriginal = document.createElement('canvas');
            faceSizeOriginal.width = parseInt(faceBox.size / scale);
            faceSizeOriginal.height = parseInt(faceBox.size / scale);
            var faceSizeOriginalCtx = faceSizeOriginal.getContext("2d", { alpha: false });
            faceSizeOriginalCtx.drawImage(
                isIosApp ? cameraIosPreview : cameraPreview,
                parseInt(faceBox.x / scale),
                parseInt(faceBox.y / scale),
                parseInt(faceBox.size / scale),
                parseInt(faceBox.size / scale),
                0,
                0,
                parseInt(faceBox.size / scale),
                parseInt(faceBox.size / scale),
            );

            facePreviewCtx.drawImage(
                faceSizeOriginal,
                0, 0, faceSizeOriginal.width, faceSizeOriginal.height,
                0, 0, 400, 400
            );

            cameraIosPreviewTemp = null;
            faceSizeOriginal = null;
            faceSizeOriginalCtx = null;
            facePreview = null;
            delete faceSizeOriginalCtx;
            delete faceSizeOriginal;
            delete facePreview;
            delete cameraIosPreviewTemp;
        }

        requestAnimationFrame(loop);
    }
    requestAnimationFrame(loop);
}