在画布getImageData周围画一个框

时间:2015-05-28 15:32:26

标签: javascript html5 canvas html5-canvas

我目前正在使用画布中的一些图像,我想在具有透明背景的图像周围绘制一个框(参见底部的示例)

我的数据通过:context.getImageData(0, 0, canvas.width, canvas.height);

我的结果中只有黑色(不透明)数据;有了这个,我尝试了几个堆栈溢出器建议的marching squares algorithm,但我无法理解这一点。

我也试过循环浏览所有数据并得到minXminYmaxXmaxY,所以我可以用这4个点绘制一个方框,但是我不知道他们怎么做 对此有何建议?

http://i.stack.imgur.com/VkxlW.png

1 个答案:

答案 0 :(得分:1)

逻辑步骤

要扫描形状的边界框,您可以执行以下步骤。假设您从画布中提取了位图(ImageData),xy用于迭代位图:

  1. 逐行扫描,从上到下扫描。首先找到实体像素,将当前y位置存储为y1,跳到下一步

  2. 逐行从底部扫描到y1。首先找到实体像素,将当前y位置存储为y2

  3. y1y2内从左向右水平扫描。使用画布的 width 初始化x1。如果在当前行上找到一个实体像素且 x低于当前x1 值,请设置x1 =当前{{ 1}}并跳到下一行

  4. 从右侧水平扫描到x。使用 0 初始化x1。当在当前行上找到实体像素并且 x2高于当前x 值时,设置x2 =当前{{ 1}}并跳到下一行

  5. 区域大小当然是:x2x

  6. 抗锯齿形状会影响尺寸。您可以包括检查实体的alpha通道以减少这种影响。

    通过更新循环以使用新的x1 / x2值作为限制,可以针对左右边缘优化扫描。使用width = x2 - x1检查像素值。

    证明的概念

    显示上述步骤结果的非优化实现。它将检查任何非alpha值。例如,您可以将0xff000000替换为0x80000000以检查alpha值> 127如果你想减少抗锯齿的影响。如果您没有阿尔法,只需检查实际颜色值(请注意,某些图像经过颜色校正,因此可以考虑容差)。

    
    
    height = y2 - y1
    
    Uint32Array
    
    var ctx = document.querySelector("canvas").getContext("2d"),
        btn = document.querySelector("button"),
        w = ctx.canvas.width,
        h = ctx.canvas.height,
        img = new Image();
    img.crossOrigin = ""; img.onload = plot; img.src = "//i.imgur.com/lfsyAEc.png";
    
    btn.onclick = plot;
    
    function plot() {
      var iw = img.width, ih = img.height,
          x = Math.random() * (w - iw * 0.5), y = Math.random() * (h - ih * 0.5),
          s = (Math.random() * 30 - 15)|0;
      ctx.clearRect(0, 0, w, h);
      ctx.translate(x, y);
      ctx.rotate(Math.random() * Math.PI - Math.PI * 0.5);
      ctx.drawImage(img, -(iw + s) * 0.5, -(ih + s) * 0.5, iw + s, ih + s);
      ctx.setTransform(1,0,0,1,0,0);
      analyze();
    }
    
    function analyze() {
      var data = new Uint32Array(ctx.getImageData(0, 0, w, h).data.buffer),
          len = data.length,
          x, y, y1, y2, x1 = w, x2 = 0;
      
      // y1
      for(y = 0; y < h; y++) {
        for(x = 0; x < w; x++) {
          if (data[y * w + x] & 0xff000000) {
            y1 = y;
            y = h;
            break;
          }
        }
      }
    
      //todo y1 and the others can be undefined if no pixel is found.
      
      // y2
      for(y = h - 1; y > y1; y--) {
        for(x = 0; x < w; x++) {
          if (data[y * w + x] & 0xff000000) {
            y2 = y;
            y = 0;
            break;
          }
        }
      }
    
      // x1
      for(y = y1; y < y2; y++) {
        for(x = 0; x < w; x++) {
          if (x < x1 && data[y * w + x] & 0xff000000) {
            x1 = x;
            break;
          }
        }
      }
    
      // x2
      for(y = y1; y < y2; y++) {
        for(x = w - 1; x > x1; x--) {
          if (x > x2 && data[y * w + x] & 0xff000000) {
            x2 = x;
            break;
          }
        }
      }
      
      // mark area:
      ctx.strokeStyle = "hsl(" + (360 * Math.random()) + ", 80%, 50%)";
      ctx.strokeRect(x1 + 0.5, y1 + 0.5, x2 - x1, y2 - y1);
    }
    &#13;
    &#13;
    &#13;