You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:16:04