javascript - 如何检测透明 Canvas 上的形状?

标签 javascript html canvas html5-canvas png

我正在寻找一种检测透明 PNG 中形状的方法。 例如,我将创建一个 940x680 的透明 Canvas ,然后在该 Canvas 的某处放置一个完全不透明的对象。

我希望能够检测到该对象的大小 (w, h) 和顶部 + 左侧位置。

这是原始图像的示例:

Transparent PNG Canvas with Image Object

这是我想要实现的示例(边界框叠加,顶部 + 左边距数据):

Results Image

我找到了一种可以进行透明度检测的资源,但我不确定如何将类似的东西扩展到我正在寻找的东西。

var imgData,
    width = 200,
    height = 200;

$('#mask').bind('mousemove', function(ev){
    if(!imgData){ initCanvas(); }
    var imgPos = $(this).offset(),
      mousePos = {x : ev.pageX - imgPos.left, y : ev.pageY - imgPos.top},
      pixelPos = 4*(mousePos.x + height*mousePos.y),
         alpha = imgData.data[pixelPos+3];

    $('#opacity').text('Opacity = ' + ((100*alpha/255) << 0) + '%');
});

function initCanvas(){
    var canvas = $('<canvas width="'+width+'" height="'+height+'" />')[0],
           ctx = canvas.getContext('2d');

    ctx.drawImage($('#mask')[0], 0, 0);
    imgData = ctx.getImageData(0, 0, width, height);
}

Fiddle

最佳答案

你需要做什么:

  • 获取缓冲区
  • 获取该缓冲区的 32 位引用(如果您的其他像素是透​​明的,则可以使用 Uint32Array 缓冲区进行迭代)。
  • 扫描 0 - 宽度以找到 x1 边
  • 扫描宽度 - 0 找到 x2 边
  • 扫描 0 - 高度找到 y1 边缘
  • 扫描高度 - 0 找到 y2 边缘

这些扫描可以合并,但为简单起见,我将分别显示每个步骤。

Online demo of this can be found here.

结果:

Snapshot

当图像加载时绘制它(如果图像很小,那么这个例子的其余部分将是浪费,因为你在绘制它时会知道坐标 - 假设你绘制的图像很大,里面有一个小图像)

(注意:为了简单起见,这是一个未优化的版本)

ctx.drawImage(this, 0, 0, w, h);

var idata = ctx.getImageData(0, 0, w, h),      // get image data for canvas
    buffer = idata.data,                       // get buffer (unnes. step)
    buffer32 = new Uint32Array(buffer.buffer), // get a 32-bit representation
    x, y,                                      // iterators
    x1 = w, y1 = h, x2 = 0, y2 = 0;            // min/max values

然后扫描每条边。对于左边缘,您从 0 扫描到每行的宽度(未优化):

// get left edge
for(y = 0; y < h; y++) {                       // line by line
    for(x = 0; x < w; x++) {                   // 0 to width
        if (buffer32[x + y * w] > 0) {         // non-transparent pixel?
            if (x < x1) x1 = x;                // if less than current min update
        }
    }
}

对于右边缘,你只需反转 x 迭代器:

// get right edge
for(y = 0; y < h; y++) {                       // line by line
    for(x = w; x >= 0; x--) {                  // from width to 0
        if (buffer32[x + y * w] > 0) {
            if (x > x2) x2 = x;
        }
    }
}

对于顶边和底边也是一样的,只是迭代器是相反的:

// get top edge
for(x = 0; x < w; x++) {
    for(y = 0; y < h; y++) {
        if (buffer32[x + y * w] > 0) {
            if (y < y1) y1 = y;
        }
    }
}

// get bottom edge
for(x = 0; x < w; x++) {
    for(y = h; y >= 0; y--) {
        if (buffer32[x + y * w] > 0) {
            if (y > y2) y2 = y;
        }
    }
}

结果区域是:

ctx.strokeRect(x1, y1, x2-x1, y2-y1);

您可以实现各种优化,但它们完全取决于场景,例如,如果您知道大概的位置,那么您就不必迭代所有行/列。

您可以通过跳过 x 个像素来蛮力猜测他的位置,当您发现一个不透明的像素时,您可以根据该像素等建立最大搜索区域,但这超出了这里的范围。

希望这对您有所帮助!

关于javascript - 如何检测透明 Canvas 上的形状?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23255825/

相关文章:

Javascript 'Promise' 如何进行同步

javascript - 我可以定义跨多个页面使用的 JavaScript 全局变量吗?

javascript - 获取 URL # 片段 XMLHttpRequest

javascript - amcharts - 图表不显示值/使用 ajax 绘制 amcharrt/如何通过查询数据库绘制 amchart

javascript - HTML5 Canvas 问题

javascript - 从其他地方开始下一行

javascript - 我应该如何延迟ajax请求?

javascript - 如何验证输入日期 html 年份?

html - 如何在 J2me 中使用 PlatformRequest() 在浏览器中调用本地 HTMl 文件?

python - tkinter - 无限 Canvas "world"/"view"- 跟踪 View 中的项目