1

我试图找到图像中包含数据的第一个垂直和水平行。

我很容易得到第一个水平行,因为在调用 时getImageData,生成的像素数据数组是逐行水平存储的。我有这样的数据:

var data = context.getImageData(0, 0, width, height).data;
var heightFirst = 0;

for (var r = 0; r <= data.length; r += 4) {
    if (data[r + 3] > 0) {
        var y = (r / width) / 4;
        heightFirst = y;
        break;
    }
}

我现在需要垂直迭代数据。我意识到这可能是使用嵌套的 for 循环并执行以下操作来完成的:

for (var r = 0; r <= data.length; r += 4) {
    for (var c = 0; c < canvasHeight; c++) {    
        if (data[(r + 3) + (c * width)] > 0) {

        }
    }
}

我不确定确切的实施/计算有人可以帮我吗?

编辑

正如@bobbybee 和@danielpolencic 所提到的,以4 * 宽度递增的循环将增加一个垂直列:

for (var r = 0; r <= data.length; r += (4 * width)) {
  if (data[r + 3] > 0) {
    // do whatever
  }
}

但是,这只获取第一列像素的信息。我想下一步是重复上面的循环,但将其增加列数(由于颜色数据而乘以 4),循环如下:

for (var c = 0; c < canvas.width; c ++) {
    for (var r = 0; r <= data.length; r += ((4 * canvas.width) + (c * 4))) {
        if (data[r + 3] > 0) {
            firstX = c;
        }
    }
}

这似乎不太对劲。我把它放在这个 fiddle上,你可以看到它应该返回 10,因为这是从左边算起的第一列,但它正在将 99 写入日志。感觉离我很近!

4

3 回答 3

2

您可以在一个循环中完成所有操作,而无需嵌套。

现场演示

var minX = canvas.width,
    minY = canvas.height;

for (var p = 0; p <= data.length; p += 4) {
     var curX = (p / 4) % canvas.width,
         curY = ((p / 4) - curX) / canvas.width;

    /* if what we're checking is higher than our recorded minX and 
      minY skip to the next row */

    if(curX > minX && curY > minY){
        // if minY is greater than 0 continue, if its 0 it can be no less so break.
        if(minY > 0){
            p=(curY+1)*(canvas.width*4); 
        }else{
            break;
        }
    }

    if (data[p + 3] > 0) {
        if (curX < minX) {
            minX = curX;
        };

        if (curY < minY) {
            minY = curY;
        };
    }
}

以下是从一维数组中获取 x 和 y 的公式

X = Index % Width

Y = (Index - x) / Width

在我们的例子中,因为我们正在处理被分成 4 个分量值(r/g/b/alpha)的像素数据,所以我们需要将索引除以 4,就像我在上面的演示中所做的那样。

接下来我使用minXminY设置画布的宽度和高度。每当我们点击一​​个像素时,我们都会检查它的xory是否低于我们的最低值xy存储。如果它们较低,那么我们保持价值并继续前进。

然而,它更容易阅读,并且使用多个循环来读取数据更快。

for (var x = 0; x <= canvas.width; x++) {
  for (var y = 0; y <= canvas.height; y++) {
    if (minY < y) {
      break;
    }
    if (data[((y * canvas.width + x) * 4) + 3] > 0) {
      if (x < minX) {
        minX = x;
      }
      if (y < minY) {
        minY = y;
      }
    }
  }
}

获取lastX和lastY的Demo

for (var x = 0; x <= canvas.width; x++) {
    for (var y = 0; y <= canvas.height; y++) {
        if (data[((y * canvas.width + x) * 4) + 3] > 0) {
            if (x < firstX) {
                firstX = x;
            }
            if (y < firstY) {
                firstY = y;
            }

            if (x > lastX) {
                lastX = x;
            }
            if (y > lastY) {
                lastY = y;
            }
        }
    }
}
于 2013-08-14T02:21:39.907 回答
1

这可以通过一个循环来完成(这里不需要嵌套循环):

for(var y = 0; y < data.length; y += canvas.width * 4) {
    if (data[y + 3] > 0 ) { /*...*/ }
}

或挤出一点速度:

var y = 0,
    length = data.length,     /// cache length
    width = canvas.width * 4; /// cache width

while(y < length) {
    if (data[y + 3] > 0 ) { /*...*/ }
    y += width;
}
于 2013-08-14T00:02:38.497 回答
1

就像@bobbybee 正确指出的那样,循环的步骤是4 * image_width.

for (var r = 0; r <= data.length; r += (4 * width)) {
    for (var c = 0; c < canvasHeight; c++) {
        if (data[r + 3] > 0) {

        }
    }
}
于 2013-08-13T20:36:10.040 回答