运行OpenCV JS美颜代码数分钟后触发cv.multiply错误求助
OpenCV JS美颜功能运行1分钟后出现cv.multiply错误排查
我正尝试用OpenCV JS实现美颜功能,代码正常运行约1分钟后,控制台出现和cv.multiply相关的错误,想请教这是OpenCV本身的问题还是内存问题,以下是我的代码:
let video = document.getElementById("videoInput"); // video is the id of video tag let canvas = document.getElementById('canvasOutput'); let ctx = canvas.getContext("2d"); video.width = 640; video.height = 480; navigator.mediaDevices .getUserMedia({ video: true, audio: false }) .then(function(stream) { video.srcObject = stream; video.play(); const FPS = 30; function processVideo() { let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); let img = new cv.Mat(); let cap = new cv.VideoCapture(video); let blur = new cv.Mat(video.height, video.width, cv.CV_8UC4); let hpf1 = new cv.Mat(); let hpf = new cv.Mat(video.height, video.width, cv.CV_8UC4); let skinArea = new cv.Mat(video.height, video.width, cv.CV_8UC1); let begin = Date.now(); cap.read(src); img=src cv.GaussianBlur(img, blur, new cv.Size(15, 15), 0,0,cv.BORDER_DEFAULT) cv.GaussianBlur(img, hpf1, new cv.Size(3, 3), 0,0,cv.BORDER_DEFAULT) cv.subtract(img,hpf1,hpf1) let minRange = new cv.Mat(img.rows, img.cols, img.type(), [120, 80, 60, 0]); let maxRange = new cv.Mat(img.rows, img.cols, img.type(), [255, 190, 120, 255]); cv.inRange(img, minRange, maxRange, skinArea); maxRange.delete() minRange.delete() let mat_1 = new cv.Mat(); cv.imshow("canvasOutput1", skinArea); mat_1 = new cv.Mat(img.rows, img.cols, cv.CV_8UC1,new cv.Scalar(1,1,1)) let blur_hpf= new cv.Mat(); cv.add(blur,hpf1,blur_hpf) hpf1.delete() blur.delete() let blurred = new cv.Mat(),background = new cv.Mat(); let ones = new cv.Mat(img.rows, img.cols, cv.CV_8UC1, new cv.Scalar(1)); cv.min(skinArea, ones, skinArea) ones.delete() cv.subtract(mat_1, skinArea,blurred) cv.cvtColor(skinArea, skinArea, cv.COLOR_GRAY2BGRA); cv.cvtColor(blurred, blurred, cv.COLOR_GRAY2BGRA); cv.multiply(skinArea,blur_hpf,skinArea) let final_out = new cv.Mat() if(blurred == undefined){ background = img final_out = img } else if(blurred == undefined || img == undefined){ console.log("not image") } else{ cv.multiply(blurred,img,background) cv.add(skinArea,background,final_out) } background.delete() blurred.delete() skinArea.delete() let kernel = cv.matFromArray(3,3,cv.CV_32FC1, [0.110, 0.160, 0.07,0.145, 0.143, 0.12,0.150, 0.150, 0.09]); cv.filter2D(final_out, final_out, -1, kernel); cv.imshow("canvasOutput", final_out); src.delete() final_out.delete() let delay = 100/FPS - (Date.now() - begin); setTimeout(processVideo, 0); } // schedule first one. setTimeout(processVideo, 0);});
问题原因:内存泄漏
这不是OpenCV本身的问题,是代码里未正确释放Mat对象导致的内存泄漏。运行一段时间后内存耗尽,触发cv.multiply相关错误。
具体遗漏释放的对象:
hpf:初始化后全程未调用delete()- 第一个
mat_1:创建后被新的Mat覆盖,原引用丢失无法释放 blur_hpf:使用后未调用delete()kernel:创建后未调用delete()
修复方案:
给所有创建的Mat对象添加delete(),确保每个对象都被正确释放。修复后的代码如下:
let video = document.getElementById("videoInput"); // video is the id of video tag let canvas = document.getElementById('canvasOutput'); let ctx = canvas.getContext("2d"); video.width = 640; video.height = 480; navigator.mediaDevices .getUserMedia({ video: true, audio: false }) .then(function(stream) { video.srcObject = stream; video.play(); const FPS = 30; function processVideo() { let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); let img = new cv.Mat(); let cap = new cv.VideoCapture(video); let blur = new cv.Mat(video.height, video.width, cv.CV_8UC4); let hpf1 = new cv.Mat(); let hpf = new cv.Mat(video.height, video.width, cv.CV_8UC4); let skinArea = new cv.Mat(video.height, video.width, cv.CV_8UC1); let begin = Date.now(); cap.read(src); img=src; cv.GaussianBlur(img, blur, new cv.Size(15, 15), 0,0,cv.BORDER_DEFAULT); cv.GaussianBlur(img, hpf1, new cv.Size(3, 3), 0,0,cv.BORDER_DEFAULT); cv.subtract(img,hpf1,hpf1); let minRange = new cv.Mat(img.rows, img.cols, img.type(), [120, 80, 60, 0]); let maxRange = new cv.Mat(img.rows, img.cols, img.type(), [255, 190, 120, 255]); cv.inRange(img, minRange, maxRange, skinArea); maxRange.delete(); minRange.delete(); // 先释放第一个mat_1再覆盖 let mat_1 = new cv.Mat(); mat_1.delete(); mat_1 = new cv.Mat(img.rows, img.cols, cv.CV_8UC1,new cv.Scalar(1,1,1)); cv.imshow("canvasOutput1", skinArea); let blur_hpf= new cv.Mat(); cv.add(blur,hpf1,blur_hpf); hpf1.delete(); blur.delete(); let blurred = new cv.Mat(),background = new cv.Mat(); let ones = new cv.Mat(img.rows, img.cols, cv.CV_8UC1, new cv.Scalar(1)); cv.min(skinArea, ones, skinArea); ones.delete(); cv.subtract(mat_1, skinArea,blurred); mat_1.delete(); // 释放mat_1 cv.cvtColor(skinArea, skinArea, cv.COLOR_GRAY2BGRA); cv.cvtColor(blurred, blurred, cv.COLOR_GRAY2BGRA); cv.multiply(skinArea,blur_hpf,skinArea); blur_hpf.delete(); // 释放blur_hpf let final_out = new cv.Mat(); if(blurred == undefined){ background = img; final_out = img; } else if(blurred == undefined || img == undefined){ console.log("not image"); } else{ cv.multiply(blurred,img,background); cv.add(skinArea,background,final_out); } background.delete(); blurred.delete(); skinArea.delete(); let kernel = cv.matFromArray(3,3,cv.CV_32FC1, [0.110, 0.160, 0.07,0.145, 0.143, 0.12,0.150, 0.150, 0.09]); cv.filter2D(final_out, final_out, -1, kernel); kernel.delete(); // 释放kernel cv.imshow("canvasOutput", final_out); src.delete(); final_out.delete(); hpf.delete(); // 释放hpf let delay = 1000/FPS - (Date.now() - begin); // 修正延迟计算错误 setTimeout(processVideo, delay > 0 ? delay : 0); } // schedule first one. setTimeout(processVideo, 0);});
额外优化点:
- 修正了延迟计算错误:原代码
100/FPS改为1000/FPS,确保帧率稳定 - 避免Mat对象被覆盖前未释放,比如第一个
mat_1先delete再重新赋值
内容的提问来源于stack exchange,提问作者vaibhav jain
相关产品推荐
相关产品推荐

