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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:10:09