如何使用JS实现Canvas内目标图像定位并框选的计算机视觉功能
需求实现方案
该需求完全可行,以下是具体实现方案:
参考图像
- 待定位的目标图:

- 待匹配的搜索图:

实现逻辑说明
定位逻辑(对应locate函数)
- 分别提取两个Canvas的像素数据,转为灰度矩阵降低计算复杂度
- 遍历搜索图所有可能的目标放置位置,计算当前位置子图与目标图的像素相似度,这里采用计算量较小的归一化互相关算法做相似度判断
- 取相似度最高的位置作为目标匹配结果,计算得到该区域的四个角坐标(左上、右上、右下、左下)返回
框选逻辑(对应rectangle函数)
- 接收Canvas上下文和四个角坐标参数
- 设置描边样式,按顺序连接四个坐标点完成矩形绘制
完整可运行代码
// 等待所有资源加载完成后执行 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
相关产品推荐
相关产品推荐

