Canvas手绘区域占目标图形面积百分比的正确计算方案问询
Canvas手绘区域覆盖目标图形面积占比计算方案
核心思路
采用像素级采样+图形掩码的方式计算,直接基于Canvas像素数据统计,避免路径几何计算的误差(尤其适配U形这类复杂镂空图形),确保结果精准。
实现步骤
1. 生成目标图形的像素掩码
创建离屏Canvas绘制目标图形(红色三角形、黑色U形),提取所有属于目标图形的像素坐标,存储为可快速查询的集合。
// 创建目标图形的像素掩码 function createTargetMask(mainCanvas) { const offscreenCanvas = document.createElement('canvas'); offscreenCanvas.width = mainCanvas.width; offscreenCanvas.height = mainCanvas.height; const ctx = offscreenCanvas.getContext('2d'); // 绘制红色三角形(替换为你的实际图形路径) ctx.fillStyle = '#ff0000'; ctx.beginPath(); ctx.moveTo(50, 50); ctx.lineTo(200, 50); ctx.lineTo(50, 200); ctx.closePath(); ctx.fill(); // 绘制黑色U形(替换为你的实际图形路径,用evenodd实现镂空) ctx.fillStyle = '#000000'; ctx.beginPath(); ctx.rect(250, 50, 150, 150); ctx.rect(270, 70, 110, 110); ctx.fill('evenodd'); // 提取目标像素集合 const imageData = ctx.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height); const data = imageData.data; const targetPixels = new Set(); for (let y = 0; y < offscreenCanvas.height; y++) { for (let x = 0; x < offscreenCanvas.width; x++) { const index = (y * offscreenCanvas.width + x) * 4; const r = data[index]; const g = data[index + 1]; const b = data[index + 2]; // 标记红色或黑色的目标像素 if ((r === 255 && g === 0 && b === 0) || (r === 0 && g === 0 && b === 0)) { targetPixels.add(`${x},${y}`); } } } return { mask: targetPixels, totalPixels: targetPixels.size }; }
2. 提取手绘蓝色区域的像素
从主Canvas中提取所有蓝色手绘区域的像素坐标,同样存储为集合(支持抗锯齿颜色阈值匹配)。
// 提取手绘蓝色区域的像素集合 function getBlueHanddrawnPixels(mainCanvas) { const ctx = mainCanvas.getContext('2d'); const imageData = ctx.getImageData(0, 0, mainCanvas.width, mainCanvas.height); const data = imageData.data; const bluePixels = new Set(); for (let y = 0; y < mainCanvas.height; y++) { for (let x = 0; x < mainCanvas.width; x++) { const index = (y * mainCanvas.width + x) * 4; const r = data[index]; const g = data[index + 1]; const b = data[index + 2]; // 宽松匹配蓝色区域(适配手绘抗锯齿的颜色偏差) if (b > 180 && r < 80 && g < 80) { bluePixels.add(`${x},${y}`); } } } return bluePixels; }
3. 计算覆盖占比
统计蓝色区域与目标图形的像素交集数量,除以目标图形总像素数得到占比。
// 计算蓝色区域覆盖目标图形的百分比 function calculateCoverage(targetMask, bluePixels) { let coveredCount = 0; for (const pixel of bluePixels) { if (targetMask.mask.has(pixel)) { coveredCount++; } } return Math.round((coveredCount / targetMask.totalPixels) * 100 * 10) / 10; // 保留一位小数 }
关键注意事项
- 坐标一致性:离屏Canvas尺寸必须与主Canvas完全一致,否则像素坐标对应会出错。
- 颜色阈值调整:手绘蓝色存在抗锯齿时,不要用严格RGB值匹配,设置合理的颜色范围避免漏统计。
- 性能优化:大尺寸Canvas可分块遍历像素,或使用
Uint32Array直接读取像素值提升效率。
内容的提问来源于stack exchange,提问作者paskalnikita
相关产品推荐
相关产品推荐

