​Roader​ 2024-11-01 15:00 采纳率: 38.5%
浏览 35
已结题

opencv.js内存,CPU飙升

opencv.js调用摄像头CPU,内存飙升,造成浏览器卡顿严重
在定义video标签宽度和高度越高的时候,opencv.js中的map.read(src)的时候浏览器CPU直接飙升。

```html
  let gray2;
    let denoised2;
    let edges2;
    let fst2;
    let hierarchy2;
    let approx2;
    let dst1;
    let dst2;
    let kernel2;
    let fsk2;
    let sss;
    let frameCount = 0;
    let canvasElement1 = document.getElementById('videoCanvas');
    const FPS = 30;
    let begin;
    let delay;
    let videosrc;
    let videocap;

    function init() {
        sss = 1;
        var videoElement = document.getElementById('video');
        videocap = new cv.VideoCapture(videoElement);
        videosrc = new cv.Mat(videoElement.height, videoElement.width, cv.CV_8UC4);
        gray2 = new cv.Mat();
        denoised2 = new cv.Mat();
        edges2 = new cv.Mat();
        fst2 = new cv.Mat();
        hierarchy2 = new cv.Mat();
        approx2 = new cv.Mat();
        dst1 = new cv.Mat();
        dst2 = new cv.Mat();
        kernel2 = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(7, 7));
        fsk2 = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(5, 5));
    }


    function detectAndDraw() {

        if (sss !== 1) {
            init();
        }
        try {
            // 确保视频正在播放
            if (video.paused || video.ended) {
                videosrc.delete();
                videosrc = null;
                gray2.delete();
                denoised2.delete();
                edges2.delete();
                fst2.delete();
                hierarchy2.delete();
                approx2.delete();
                dst1.delete();
                dst2.delete();
                kernel2.delete();
                fsk2.delete();
                return;
            }
            videocap.read(videosrc);//造成cpu,内存高占用核心问题

            // 图像处理:转换为灰度图
            cv.cvtColor(videosrc, gray2, cv.COLOR_BGR2GRAY); // 重用 gray2 对象

            // 降噪处理
            cv.bilateralFilter(gray2, denoised2, 9, 75, 75); // 重用 denoised2 对象

            // 高斯滤波
            cv.GaussianBlur(denoised2, denoised2, new cv.Size(5, 5), 0, 0); // 使用降噪后的图像

            // 提取边缘
            cv.Canny(denoised2, edges2, 75, 150); // 重用 edges2 对象

            // 膨胀
            cv.dilate(edges2, edges2, kernel2); // 重用 kernel2 和 edges2 对象

            // 进行腐蚀操作
            cv.erode(edges2, fst2, fsk2); // 重用 fst2 和 fsk2 对象

            // 提取外轮廓
            let contours = new cv.MatVector();
            cv.findContours(edges2, contours, hierarchy2, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);

            let index = 0, maxArea = 0, aindex = 0;
            const area = videosrc.cols * videosrc.rows;

            for (let i = 0; i < contours.size(); ++i) {
                let tempArea = Math.abs(cv.contourArea(contours.get(i)));
                if (tempArea > maxArea) {
                    index = i;
                    maxArea = tempArea;
                }
                if (tempArea > area * 0.03) {
                    //console.log("底图面积:" + area + ";文件面积:" + tempArea);
                    aindex++;
                }
            }


            if (maxArea > 0 && aindex === 1) {
                const foundContour = contours.get(index);
                const arcL = cv.arcLength(foundContour, true);
                cv.approxPolyDP(foundContour, approx2, 0.02 * arcL, true); // 重用 approx2 对象

                if (approx2.total() === 4) {
                    let points = [];
                    const data32S = approx2.data32S;
                    for (let i = 0, len = data32S.length / 2; i < len; i++) {
                        points[i] = {x: data32S[i * 2], y: data32S[i * 2 + 1]};
                    }


                    let srcPoints = getSortedVertex(points).flatMap(p => [p.x, p.y]);

                    // 在源图像上绘制绿色边框
                    for (let i = 0; i < 4; i++) {
                        const startX = srcPoints[i * 2];
                        const startY = srcPoints[i * 2 + 1];
                        const endX = srcPoints[((i + 1) % 4) * 2];
                        const endY = srcPoints[((i + 1) % 4) * 2 + 1];

                        // 绘制线段,颜色为绿色,线宽为2
                        cv.line(videosrc, new cv.Point(startX, startY), new cv.Point(endX, endY), new cv.Scalar(0, 255, 0, 255), 7);
                    }

                }
            }

            // 释放本次使用的 Mat 对象
            contours.delete();
            contours = null;
        } catch (e) {
            console.error("发生错误:", e);

        } finally {

            cv.imshow(canvasElement1, videosrc);
            setTimeout(detectAndDraw, 1000 / FPS);

        }

    }

出问题的代码方法是detectAndDraw方法,尝试一行一行的注释代码发现, videocap.read(videosrc);这一行代码和
<video id="video" width="1500" height="1125" style="display: none"></video>
<canvas id="videoCanvas" width="1500" height="1125"></canvas>
这个宽度高度相关,宽度高度越大,浏览器内存和cpu越高,请问可以如何优化,或者哪里写的有问题吗?
目前这样写单个页面内存达到700M,,CP90%左右
  • 写回答

20条回答 默认 最新

  • Paggio 2024-11-03 09:17
    关注

    1.调整分辨率
    2.调整帧率,降低到30以下

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(19条)

报告相同问题?

问题事件

  • 系统已结题 11月11日
  • 已采纳回答 11月3日
  • 创建了问题 11月1日