求助解决OpenCV.js报错TypeError: cv.Mat is not a constructor
解决TypeError: cv.Mat is not a constructor 问题
我一眼就看出问题出在哪了——你的代码在OpenCV.js完全加载并初始化完成之前就尝试调用了cv对象的API,这就是为什么会抛出cv.Mat is not a constructor的错误。
问题根源分析
你的HTML里有两个关键问题:
index.js和opencv.js都加了async属性,且index.js放在了opencv.js前面。浏览器异步加载脚本时,大概率会先执行index.js,这时候OpenCV还没加载完成,cv对象要么不存在,要么未完成初始化,自然找不到Mat构造函数。- 你给
opencv.js绑定了onload="onOpenCvReady();"事件,但代码里根本没定义这个函数,等于白绑定了,完全起不到等待OpenCV加载的作用。
解决方案步骤
1. 调整脚本加载逻辑
移除index.js的async属性,把它放到opencv.js后面,确保OpenCV先加载;同时在index.js里定义onOpenCvReady函数,让所有依赖OpenCV的代码都在这个函数里执行。
2. 修复代码里的遗漏问题
你的原代码里还缺少streaming变量定义,这会导致后续逻辑报错,需要补充;另外要注意videoInput是canvas元素,而cv.VideoCapture通常用于处理HTMLVideoElement,如果是处理摄像头流需要额外调整。
修改后的完整代码
Index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello OpenCV.js</title> </head> <body> <h2>Hello OpenCV.js</h2> <p id="status">OpenCV.js is loading...</p> <div> <img src="dd.jpg" style="display:none;" id ="img"> <canvas id = "videoInput" height="500" width="500"></canvas> <canvas id = "canvasOutput" height="500" width="500"></canvas> <!-- 先加载OpenCV,再加载业务代码,并绑定加载完成事件 --> <script src="opencv.js" onload="onOpenCvReady();" type="text/javascript"></script> <script type="text/javascript" src="index.js"></script> </body> </html>
index.js
// 定义OpenCV加载完成后的回调函数 function onOpenCvReady() { document.getElementById('status').innerHTML = 'OpenCV.js is ready.'; let video = document.getElementById('videoInput'); let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4); let gray = new cv.Mat(); let cap = new cv.VideoCapture(video); let faces = new cv.RectVector(); let classifier = new cv.CascadeClassifier(); // 加载预训练分类器,确保文件路径正确 classifier.load('haarcascade_frontalface_default.xml'); const FPS = 30; // 补充缺失的streaming变量,控制视频处理循环 let streaming = true; function processVideo() { try { if (!streaming) { // 清理资源 src.delete(); dst.delete(); gray.delete(); faces.delete(); classifier.delete(); return; } let begin = Date.now(); // 读取帧并处理 cap.read(src); src.copyTo(dst); cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); // 检测人脸 classifier.detectMultiScale(gray, faces, 1.1, 3, 0); // 绘制人脸框 for (let i = 0; i < faces.size(); ++i) { let face = faces.get(i); let point1 = new cv.Point(face.x, face.y); let point2 = new cv.Point(face.x + face.width, face.y + face.height); cv.rectangle(dst, point1, point2, [255, 0, 0, 255]); } cv.imshow('canvasOutput', dst); // 调度下一帧处理 let delay = 1000/FPS - (Date.now() - begin); setTimeout(processVideo, delay); } catch (err) { console.error(err); // 替换原代码中未定义的utils.printError } }; // 启动处理循环 setTimeout(processVideo, 0); }
额外注意事项
- 确保
haarcascade_frontalface_default.xml文件路径正确,和HTML文件在同一目录或路径配置无误。 - 如果你是想处理摄像头视频流,需要将
videoInput改为HTMLVideoElement,再通过navigator.mediaDevices.getUserMedia获取媒体流并绑定到video元素上。
内容的提问来源于stack exchange,提问作者Mohammad Ummair
相关产品推荐
相关产品推荐

