如何在构建opencv.js时包含cv.imread()



我克隆了OpenCV Git存储库:git clone https://github.com/opencv/opencv.git并且没有改变任何事情。

然后,我一步一步地遵循OpenCV上的构建opencv.js文档https://docs.opencv.org/4.5.2/d4/da1/tutorial_js_setup.html并用命令成功构建了CCD_ 3和CCD_

python ./platforms/js/build_js.py build_js --build_test

然后我用一个实时服务器打开创建的test.html,看到所有测试都成功了:"581 assertions of 581 passed, 0 failed."

但是,当我在<script> </script>标签之间插入构建的opencv.js并使用它时,它仍然可以工作,除了cv.imread()。我收到错误消息:`

"未捕获的类型错误:cv.imread不是一个函数。`

这是代码块:

let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let matrix = cv.imread("canvas");

然后我使用了官方的opencv.js和imread((。然而,问题是opencv.js的大小是7.7mb,因为它包含了opencv的大部分功能,而我只需要一些核心和图像处理功能。

如何在构建中包含imread((?到目前为止,我找不到解决办法。我只找到了构建白名单:它在OpenCV存储库中,名称为OpenCV_js.config.py,包括以下内容。你知道如何将imread((包含在构建中吗?因为OpenCV JavaScript文档几乎在每个例子中都使用imread((,所以应该有一种简单的方法来包含它

# Classes and methods whitelist
core = {
'': [
'absdiff', 'add', 'addWeighted', 'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'cartToPolar',
'compare', 'convertScaleAbs', 'copyMakeBorder', 'countNonZero', 'determinant', 'dft', 'divide', 'eigen',
'exp', 'flip', 'getOptimalDFTSize','gemm', 'hconcat', 'inRange', 'invert', 'kmeans', 'log', 'magnitude',
'max', 'mean', 'meanStdDev', 'merge', 'min', 'minMaxLoc', 'mixChannels', 'multiply', 'norm', 'normalize',
'perspectiveTransform', 'polarToCart', 'pow', 'randn', 'randu', 'reduce', 'repeat', 'rotate', 'setIdentity', 'setRNGSeed',
'solve', 'solvePoly', 'split', 'sqrt', 'subtract', 'trace', 'transform', 'transpose', 'vconcat',
'setLogLevel', 'getLogLevel',
],
'Algorithm': [],
}
imgproc = {'': ['Canny', 'GaussianBlur', 'Laplacian', 'HoughLines', 'HoughLinesP', 'HoughCircles', 'Scharr','Sobel', 
'adaptiveThreshold','approxPolyDP','arcLength','bilateralFilter','blur','boundingRect','boxFilter',
'calcBackProject','calcHist','circle','compareHist','connectedComponents','connectedComponentsWithStats', 
'contourArea', 'convexHull', 'convexityDefects', 'cornerHarris','cornerMinEigenVal','createCLAHE', 
'createLineSegmentDetector','cvtColor','demosaicing','dilate', 'distanceTransform','distanceTransformWithLabels', 
'drawContours','ellipse','ellipse2Poly','equalizeHist','erode', 'filter2D', 'findContours','fitEllipse', 
'fitLine', 'floodFill','getAffineTransform', 'getPerspectiveTransform', 'getRotationMatrix2D', 'getStructuringElement', 
'goodFeaturesToTrack','grabCut','initUndistortRectifyMap', 'integral','integral2', 'isContourConvex', 'line', 
'matchShapes', 'matchTemplate','medianBlur', 'minAreaRect', 'minEnclosingCircle', 'moments', 'morphologyEx', 
'pointPolygonTest', 'putText','pyrDown','pyrUp','rectangle','remap', 'resize','sepFilter2D','threshold', 
'undistort','warpAffine','warpPerspective','warpPolar','watershed', 
'fillPoly', 'fillConvexPoly', 'polylines',
],
'CLAHE': ['apply', 'collectGarbage', 'getClipLimit', 'getTilesGridSize', 'setClipLimit', 'setTilesGridSize'],
'segmentation_IntelligentScissorsMB': [
'IntelligentScissorsMB',
'setWeights',
'setGradientMagnitudeMaxLimit',
'setEdgeFeatureZeroCrossingParameters',
'setEdgeFeatureCannyParameters',
'applyImage',
'applyImageFeatures',
'buildMap',
'getContour'
],
}
objdetect = {'': ['groupRectangles'],
'HOGDescriptor': ['load', 'HOGDescriptor', 'getDefaultPeopleDetector', 'getDaimlerPeopleDetector', 'setSVMDetector', 'detectMultiScale'],
'CascadeClassifier': ['load', 'detectMultiScale2', 'CascadeClassifier', 'detectMultiScale3', 'empty', 'detectMultiScale'],
'QRCodeDetector': ['QRCodeDetector', 'decode', 'decodeCurved', 'detect', 'detectAndDecode', 'detectMulti', 'setEpsX', 'setEpsY']}
video = {'': ['CamShift', 'calcOpticalFlowFarneback', 'calcOpticalFlowPyrLK', 'createBackgroundSubtractorMOG2', 
'findTransformECC', 'meanShift'],
'BackgroundSubtractorMOG2': ['BackgroundSubtractorMOG2', 'apply'],
'BackgroundSubtractor': ['apply', 'getBackgroundImage']}
dnn = {'dnn_Net': ['setInput', 'forward'],
'': ['readNetFromCaffe', 'readNetFromTensorflow', 'readNetFromTorch', 'readNetFromDarknet',
'readNetFromONNX', 'readNet', 'blobFromImage']}
features2d = {'Feature2D': ['detect', 'compute', 'detectAndCompute', 'descriptorSize', 'descriptorType', 'defaultNorm', 'empty', 'getDefaultName'],
'BRISK': ['create', 'getDefaultName'],
'ORB': ['create', 'setMaxFeatures', 'setScaleFactor', 'setNLevels', 'setEdgeThreshold', 'setFirstLevel', 'setWTA_K', 'setScoreType', 'setPatchSize', 'getFastThreshold', 'getDefaultName'],
'MSER': ['create', 'detectRegions', 'setDelta', 'getDelta', 'setMinArea', 'getMinArea', 'setMaxArea', 'getMaxArea', 'setPass2Only', 'getPass2Only', 'getDefaultName'],
'FastFeatureDetector': ['create', 'setThreshold', 'getThreshold', 'setNonmaxSuppression', 'getNonmaxSuppression', 'setType', 'getType', 'getDefaultName'],
'AgastFeatureDetector': ['create', 'setThreshold', 'getThreshold', 'setNonmaxSuppression', 'getNonmaxSuppression', 'setType', 'getType', 'getDefaultName'],
'GFTTDetector': ['create', 'setMaxFeatures', 'getMaxFeatures', 'setQualityLevel', 'getQualityLevel', 'setMinDistance', 'getMinDistance', 'setBlockSize', 'getBlockSize', 'setHarrisDetector', 'getHarrisDetector', 'setK', 'getK', 'getDefaultName'],
# 'SimpleBlobDetector': ['create'],
'KAZE': ['create', 'setExtended', 'getExtended', 'setUpright', 'getUpright', 'setThreshold', 'getThreshold', 'setNOctaves', 'getNOctaves', 'setNOctaveLayers', 'getNOctaveLayers', 'setDiffusivity', 'getDiffusivity', 'getDefaultName'],
'AKAZE': ['create', 'setDescriptorType', 'getDescriptorType', 'setDescriptorSize', 'getDescriptorSize', 'setDescriptorChannels', 'getDescriptorChannels', 'setThreshold', 'getThreshold', 'setNOctaves', 'getNOctaves', 'setNOctaveLayers', 'getNOctaveLayers', 'setDiffusivity', 'getDiffusivity', 'getDefaultName'],
'DescriptorMatcher': ['add', 'clear', 'empty', 'isMaskSupported', 'train', 'match', 'knnMatch', 'radiusMatch', 'clone', 'create'],
'BFMatcher': ['isMaskSupported', 'create'],
'': ['drawKeypoints', 'drawMatches', 'drawMatchesKnn']}
photo = {'': ['createAlignMTB', 'createCalibrateDebevec', 'createCalibrateRobertson', 
'createMergeDebevec', 'createMergeMertens', 'createMergeRobertson', 
'createTonemapDrago', 'createTonemapMantiuk', 'createTonemapReinhard', 'inpaint'],
'CalibrateCRF': ['process'],
'AlignMTB' : ['calculateShift', 'shiftMat', 'computeBitmaps', 'getMaxBits', 'setMaxBits', 
'getExcludeRange', 'setExcludeRange', 'getCut', 'setCut'],
'CalibrateDebevec' : ['getLambda', 'setLambda', 'getSamples', 'setSamples', 'getRandom', 'setRandom'],
'CalibrateRobertson' : ['getMaxIter', 'setMaxIter', 'getThreshold', 'setThreshold', 'getRadiance'],
'MergeExposures' : ['process'],
'MergeDebevec' : ['process'],
'MergeMertens' : ['process', 'getContrastWeight', 'setContrastWeight', 'getSaturationWeight', 
'setSaturationWeight', 'getExposureWeight', 'setExposureWeight'],
'MergeRobertson' : ['process'],
'Tonemap' : ['process' , 'getGamma', 'setGamma'],
'TonemapDrago' : ['getSaturation', 'setSaturation', 'getBias', 'setBias', 
'getSigmaColor', 'setSigmaColor', 'getSigmaSpace','setSigmaSpace'],
'TonemapMantiuk' : ['getScale', 'setScale', 'getSaturation', 'setSaturation'],
'TonemapReinhard' : ['getIntensity', 'setIntensity', 'getLightAdaptation', 'setLightAdaptation', 
'getColorAdaptation', 'setColorAdaptation']
}
aruco = {'': ['detectMarkers', 'drawDetectedMarkers', 'drawAxis', 'estimatePoseSingleMarkers', 'estimatePoseBoard', 'estimatePoseCharucoBoard', 'interpolateCornersCharuco', 'drawDetectedCornersCharuco'],
'aruco_Dictionary': ['get', 'drawMarker'],
'aruco_Board': ['create'],
'aruco_GridBoard': ['create', 'draw'],
'aruco_CharucoBoard': ['create', 'draw'],
'aruco_DetectorParameters': ['create']
}
calib3d = {'': ['findHomography', 'calibrateCameraExtended', 'drawFrameAxes', 'estimateAffine2D', 
'getDefaultNewCameraMatrix', 'initUndistortRectifyMap', 'Rodrigues', 
'solvePnP', 'solvePnPRansac', 'solvePnPRefineLM']}

white_list = makeWhiteList([core, imgproc, objdetect, video, dnn, features2d, photo, aruco, calib3d])

我也遇到了同样的问题。我使用emscripten从源代码编译opencv,它没有任何错误,但当我试图在浏览器中加载它时,它根本不起作用。使用旧版本的emscripten解决了问题。

git clone https://github.com/emscripten-core/emsdk.git
cd emsdk/
./emsdk install 1.39.15
./emsdk activate 1.39.15
source ./emsdk_env.sh
git clone https://github.com/opencv/opencv.git
emcmake python ./opencv/platforms/js/build_js.py build_wasm --build_wasm

我浏览了所有更新的版本,但1.39.15是对我有效的最新版本。通过这种方式,我将opencv.js文件减少到1.7MB。

cv.imread((不能从您的自构建opencv.js中使用的原因是因为它返回了cv.ready,这是一个Promise(请检查您的自建opencv.js,第34行(。然而,官方构建的opencv.js返回cv(https://docs.opencv.org/4.5.0/opencv.js(。因此,如果你按照旧文档使用简历和你自己的简历opencv.js,你会出错。

如中所述https://github.com/opencv/opencv/issues/21580有两种方法可以解决这个问题。

  1. 采用Promise用法,在加载opencv.js后立即尝试重置cv
<script src="js/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
async function onOpenCvReady() { window.cv = await window.cv }
  1. 或者您可以保留原始用法,但必须修改opencv.js

修改opencv.js行:34

return cv.ready

return cv

然后在调用CCD_ 18之后使用cv。https://docs.opencv.org/4.x/d0/d84/tutorial_js_usage.html

我刚刚也遇到了同样的问题。看起来opencv.js文档还没有针对emscripten模块API的新版本进行更新(或者这只是我与opencv文档不同的做法,而且它恰好有效(。

如embind文档中所示,您可以使用onRuntimeInitialized函数来检测WASM模块何时完成加载,然后通过Module对象访问其导出的函数。这就是我如何使用opencv.js,包括cv.imread:

<html>
<head>
</head>
<body>
<h1>Hello OpenCV.js</h1>
<div>
<div>
<canvas id="canvas"></canvas>
</div>
<div>
<input type="file" id="fileInput" name="file" />
</div>
</div>
<script>
var Module = {
onRuntimeInitialized: function() {
console.log(Module.imread)
const cv = Module;
let fileInput = document.getElementById('fileInput');
fileInput.onchange = (e) => {
const image = new Image();
image.src = URL.createObjectURL(e.target.files[0]);
image.onload = ()  => {
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
canvas.height = image.height;
canvas.width = image.width;
context.drawImage(image, 0, 0, image.width, image.height);
const imageData = context.getImageData(0, 0, image.width, image.height);
const cvImage = cv.imread("canvas");
const mean = cv.mean(cvImage)
console.log(`Mean: ${mean[0]}, ${mean[1]}, ${mean[2]}`)
}
};
}
};
</script>
<script src="opencv.js"></script>
</body>
</html>

重要信息:请确保不要编译OpenCVimcodecs模块,因为imread的浏览器版本将被C++版本覆盖。浏览器实现(在opencv/modules/js/src/helpers.js中定义(从浏览器加载图像,而C++版本从文件加载图像。

请记住,我刚开始学习WASM、emscripten和JavaScript,所以请原谅任何潜在的术语滥用。如果我做错了什么或做得不好,我也会非常乐意得到一些反馈。

最新更新