OpenCV.js中如何将智能剪刀生成的轮廓转为画布点数组?
将OpenCV.js智能剪刀的轮廓转换为画布点数组
我正在使用OpenCV.js,代码基于智能剪刀教程:
let src = cv.imread('canvasInput'); //cv.resize(src, src, new cv.Size(1024, 1024)); cv.imshow('canvasOutput', src); let tool = new cv.segmentation_IntelligentScissorsMB(); tool.setEdgeFeatureCannyParameters(32, 100); tool.setGradientMagnitudeMaxLimit(200); tool.applyImage(src); let hasMap = false; let canvas = document.getElementById('canvasOutput'); canvas.addEventListener('click', e => { let startX = e.offsetX, startY = e.offsetY; console.log(startX, startY); if (startX < src.cols && startY < src.rows) { console.time('buildMap'); tool.buildMap(new cv.Point(startX, startY)); console.timeEnd('buildMap'); hasMap = true; } }); canvas.addEventListener('mousemove', e => { let x = e.offsetX, y = e.offsetY; //console.log(x, y); let dst = src.clone(); if (hasMap && x >= 0 && x < src.cols && y >= 0 && y < src.rows) { let contour = new cv.Mat(); tool.getContour(new cv.Point(x, y), contour); let contours = new cv.MatVector(); contours.push_back(contour); let color = new cv.Scalar(0, 255, 0, 255); // RGBA cv.polylines(dst, contours, false, color, 1, cv.LINE_8); contours.delete(); contour.delete(); } cv.imshow('canvasOutput', dst); dst.delete(); }); canvas.addEventListener('dispose', e => { src.delete(); tool.delete(); });
我不想用cv.polylines(dst, contours, false, color, 1, cv.LINE_8);在画布上绘制轮廓折线,而是希望将轮廓转换为画布点(宽、高)的数组,格式为[[w0, h0], ... [wi, hi]]。调用tool.getContour(new cv.Point(x, y), contour);后,contour是一个2通道的32位整数型Mat,每一行对应一个点的x、y坐标。
转换方法
要提取点数组,直接访问Mat的data32S属性即可——这是一个存储所有点数据的32位整数数组,每两个元素对应一个点的x和y值。
替换原代码中cv.polylines相关的逻辑,改成以下代码:
// 转换contour为目标格式的数组 let contourPoints = []; for (let i = 0; i < contour.rows; i++) { // 每两个元素对应一个点的x、y const x = contour.data32S[i * 2]; const y = contour.data32S[i * 2 + 1]; contourPoints.push([x, y]); } // contourPoints就是[[w0,h0], ... [wi, hi]]格式的数组 console.log(contourPoints);
修改后的完整鼠标移动事件代码
把原事件中的绘制逻辑替换成转换代码后,示例如下(也可以自己用原生Canvas API绘制):
canvas.addEventListener('mousemove', e => { let x = e.offsetX, y = e.offsetY; let dst = src.clone(); if (hasMap && x >= 0 && x < src.cols && y >= 0 && y < src.rows) { let contour = new cv.Mat(); tool.getContour(new cv.Point(x, y), contour); // 转换为画布点数组 let contourPoints = []; for (let i = 0; i < contour.rows; i++) { const pointX = contour.data32S[i * 2]; const pointY = contour.data32S[i * 2 + 1]; contourPoints.push([pointX, pointY]); } // 示例:用原生Canvas API绘制轮廓(可选) const ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.moveTo(contourPoints[0][0], contourPoints[0][1]); for (let i = 1; i < contourPoints.length; i++) { ctx.lineTo(contourPoints[i][0], contourPoints[i][1]); } ctx.strokeStyle = '#00ff00'; ctx.lineWidth = 1; ctx.stroke(); contour.delete(); // 记得释放内存 } cv.imshow('canvasOutput', dst); dst.delete(); });
注意事项
- 务必在使用完
contour后调用contour.delete(),避免OpenCV.js内存泄漏。 - 如果图像做过缩放,需要根据缩放比例调整点坐标,保证和画布尺寸匹配。
内容的提问来源于stack exchange,提问作者Below the Radar
相关产品推荐
相关产品推荐

