opencv.js进行图像边缘化检测与描边内存溢出
以下为我的代码,主要使用了递归调用,也在调用完成后删除掉了初始化的mat对象之类的。但是依然内存溢出。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Object Detection</title>
</head>
<body>
<video id="video" width="1280" height="720" autoplay></video>
<canvas id="canvas" width="1280" height="720"></canvas>
<script async src="../archives/js/opencv.js" onload="onOpenCvReady();"></script>
<script>
let video = document.getElementById('video');
let canvasElement = document.getElementById('canvas');
let ctx = canvasElement.getContext('2d');
let gray;
let denoised;
let edges;
let fst;
let hierarchy;
let approx;
let dst;
let dst1;
let kernel;
let fsk;
let sss;
function onOpenCvReady() {
navigator.mediaDevices.getUserMedia({video: {width: 1280, height: 720}})
.then(stream => {
video.srcObject = stream;
video.play(); // 开始播放视频
})
.catch(err => {
console.error("Error accessing media devices.", err);
});
// 监听 'play' 事件,确保视频开始播放后再进行检测和绘制
video.addEventListener('play', detectAndDraw);
}
function detectAndDraw() {
// console.log("开始");
init();
// 确保视频正在播放
if (video.paused || video.ended) return;
// 绘制视频帧到 canvas 上
ctx.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
// 获取 canvas 上的图像数据并转换为 OpenCV 的 Mat 对象
let src = cv.matFromImageData(ctx.getImageData(0, 0, canvasElement.width, canvasElement.height));
// 图像处理:转换为灰度图
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY); // 重用 gray 对象
// 降噪处理
cv.bilateralFilter(gray, denoised, 9, 75, 75); // 重用 denoised 对象
// 高斯滤波
cv.GaussianBlur(denoised, denoised, new cv.Size(5, 5), 0, 0); // 使用降噪后的图像
// 提取边缘
cv.Canny(denoised, edges, 75, 150); // 重用 edges 对象
// 膨胀
cv.dilate(edges, edges, kernel); // 重用 kernel 和 edges 对象
// 进行腐蚀操作
cv.erode(edges, fst, fsk); // 重用 fst 和 fsk 对象
// 提取外轮廓
let contours = new cv.MatVector();
cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
let index = 0, maxArea = 0, aindex = 0;
const area = src.cols * src.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) {
const foundContour = contours.get(index);
const arcL = cv.arcLength(foundContour, true);
cv.approxPolyDP(foundContour, approx, 0.02 * arcL, true); // 重用 approx 对象
if (approx.total() === 4) {
let points = [];
const data32S = approx.data32S;
for (let i = 0, len = data32S.length / 2; i < len; i++) {
points[i] = {x: data32S[i * 2], y: data32S[i * 2 + 1]};
}
//console.log("检测到四边形点:", points);
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(src, new cv.Point(startX, startY), new cv.Point(endX, endY), new cv.Scalar(0, 255, 0, 255), 10);
}
cv.imshow(canvasElement, src);
gray.delete();
denoised.delete();
edges.delete();
fst.delete();
hierarchy.delete();
approx.delete();
dst.delete();
dst1.delete();
kernel.delete();
fsk.delete();
contours.delete();
}
}
requestAnimationFrame(detectAndDraw);
}
// 开始处理
video.addEventListener('play', () => {
detectAndDraw();
});
function getSortedVertex(points) {
// 计算中心点
const center = {
x: points.reduce((sum, p) => sum + p.x, 0) / points.length,
y: points.reduce((sum, p) => sum + p.y, 0) / points.length
};
// 计算每个点到中心点的角度
const angles = points.map(p => {
return {
point: p,
angle: Math.atan2(p.y - center.y, p.x - center.x) * 180 / Math.PI
};
});
// 按角度排序
const sortedPoints = angles.sort((a, b) => a.angle - b.angle).map(a => a.point);
return sortedPoints;
}
function init() {
//console.log("初始化");
sss = 1;
gray = new cv.Mat();
denoised = new cv.Mat();
edges = new cv.Mat();
fst = new cv.Mat();
hierarchy = new cv.Mat();
approx = new cv.Mat();
dst = new cv.Mat();
dst1 = new cv.Mat();
kernel = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(7, 7));
fsk = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(5, 5));
}
</script>
</body>
</html>
处理掉内存溢出的问题