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

如何使用JS实现Canvas内目标图像定位并框选的计算机视觉功能

需求实现方案

该需求完全可行,以下是具体实现方案:

参考图像

  • 待定位的目标图:目标图
  • 待匹配的搜索图:搜索图

实现逻辑说明

定位逻辑(对应locate函数)

  1. 分别提取两个Canvas的像素数据,转为灰度矩阵降低计算复杂度
  2. 遍历搜索图所有可能的目标放置位置,计算当前位置子图与目标图的像素相似度,这里采用计算量较小的归一化互相关算法做相似度判断
  3. 取相似度最高的位置作为目标匹配结果,计算得到该区域的四个角坐标(左上、右上、右下、左下)返回

框选逻辑(对应rectangle函数)

  1. 接收Canvas上下文和四个角坐标参数
  2. 设置描边样式,按顺序连接四个坐标点完成矩形绘制

完整可运行代码

// 等待所有资源加载完成后执行
window.onload = function() {
  const canvas1 = document.querySelector("#imgone");
  const canvas2 = document.querySelector("#imgtwo");
  const ctx1 = canvas1.getContext("2d");
  const ctx2 = canvas2.getContext("2d");

  // 定位函数:返回目标在搜索图中的四个角坐标 [左上, 右上, 右下, 左下]
  function locate(context1, context2) {
    // 获取模板图尺寸和像素数据
    const templateWidth = context1.canvas.width;
    const templateHeight = context1.canvas.height;
    const templateData = context1.getImageData(0, 0, templateWidth, templateHeight).data;
    const templateGray = toGray(templateData, templateWidth, templateHeight);

    // 获取搜索图尺寸和像素数据
    const searchWidth = context2.canvas.width;
    const searchHeight = context2.canvas.height;
    const searchData = context2.getImageData(0, 0, searchWidth, searchHeight).data;
    const searchGray = toGray(searchData, searchWidth, searchHeight);

    let maxSimilarity = -Infinity;
    let bestX = 0, bestY = 0;

    // 遍历所有可能的匹配位置
    for (let y = 0; y <= searchHeight - templateHeight; y++) {
      for (let x = 0; x <= searchWidth - templateWidth; x++) {
        const similarity = calcSimilarity(searchGray, templateGray, x, y, templateWidth, templateHeight, searchWidth);
        if (similarity > maxSimilarity) {
          maxSimilarity = similarity;
          bestX = x;
          bestY = y;
        }
      }
    }

    // 构造四个角坐标
    return [
      {x: bestX, y: bestY},
      {x: bestX + templateWidth, y: bestY},
      {x: bestX + templateWidth, y: bestY + templateHeight},
      {x: bestX, y: bestY + templateHeight}
    ]
  }

  // 绘制矩形框函数
  function rectangle(context, corner1, corner2, corner3, corner4) {
    context.beginPath();
    context.moveTo(corner1.x, corner1.y);
    context.lineTo(corner2.x, corner2.y);
    context.lineTo(corner3.x, corner3.y);
    context.lineTo(corner4.x, corner4.y);
    context.closePath();
    context.strokeStyle = "#ff0000";
    context.lineWidth = 2;
    context.stroke();
  }

  // 辅助函数:像素数据转灰度矩阵
  function toGray(pixelData, width, height) {
    const gray = new Array(height);
    for (let y = 0; y < height; y++) {
      gray[y] = new Array(width);
      for (let x = 0; x < width; x++) {
        const idx = (y * width + x) * 4;
        // RGB转灰度公式
        gray[y][x] = 0.299 * pixelData[idx] + 0.587 * pixelData[idx + 1] + 0.114 * pixelData[idx + 2];
      }
    }
    return gray;
  }

  // 辅助函数:计算两个区域的相似度(归一化互相关)
  function calcSimilarity(searchGray, templateGray, x, y, tplW, tplH, searchW) {
    let sum = 0;
    let tplSum = 0;
    let searchSum = 0;
    for (let i = 0; i < tplH; i++) {
      for (let j = 0; j < tplW; j++) {
        const tplVal = templateGray[i][j];
        const searchVal = searchGray[y + i][x + j];
        sum += tplVal * searchVal;
        tplSum += tplVal * tplVal;
        searchSum += searchVal * searchVal;
      }
    }
    return sum / Math.sqrt(tplSum * searchSum);
  }

  // 执行逻辑
  const corners = locate(ctx1, ctx2);
  rectangle(ctx2, ...corners);
}

优化建议

  • 如果模板在搜索图中存在缩放、旋转、透视变换等情况,可引入opencv.js的ORB特征点匹配能力,鲁棒性更强
  • 大尺寸图片匹配时可以先对图像做降采样处理,大幅减少计算量,提升匹配速度
  • 可设置相似度阈值,只有当最高匹配度超过阈值时才绘制框,避免误匹配

内容的提问来源于stack exchange,提问作者sld

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 06:18:03