8

我有一个二进制图像,二进制值是 0 或 255。图像数据的类型是unsigned char。在这里,我需要对这张图片进行中值滤波。

我认为使用直方图找到中位数应该很快。使用一些代码来解释:

unsigned int hist[2] = {0, 0};

for (int i = 0; i < kernel_h; ++i) {
     for (int j = 0; j < kernel_w; ++j) {
          if (image(i,j) == 0) {
              hist[0]++;
          }
          else {
              hist[1]++;
          }
     }
}

然后,我们可以非常快地得到中值。但是由于这种情况,代码仍有待改进:</p>

int counter = 0;

for (int i = 0; i < kernel_h; ++i) {
     for (int j = 0; j < kernel_w; ++j) {
          if (image(i,j) == 0) {
              counter++
          }
          else {
              counter--;
          }
     }
}

但是我想知道是否有其他方法可以消除 if-else 分支,例如使用位操作将 {0, 255} 映射到某个东西,这样我们就可以在不分支的情况下更新标志。

有人有什么建议吗?

4

2 回答 2

11

255 的所有位都是 1,因此您可以将“如果”简化为:

hist[image(i,j) & 1]++;

如果你想使用计数器,你可以这样做:

counter += (image(i,j) & 2)-1;
于 2013-10-04T06:20:46.087 回答
5

这种计算可以O(n)在像素数量上变得更快,更具体,并且与内核大小无关。

这个想法是首先进行“扫描转换”,计算一个总面积表,其中每个 (x, y) 像素的值被从 (0, 0) 到 (x, y) 的所有像素的总和替换。

鉴于此,您可以使用固定时间知道在任何矩形中设置了多少像素

st(x0, y0) + st(x1, y1) - st(x0, y1) - st(x1, y0)

并且假设每个像素是 0 或 1,总和会给你个数。

总计算时间是O(n)建立和表并O(n)进行中值过滤,无论进行计数的区域有多大。

在中值滤波的情况下,您可以根据总和预先计算结果,内部循环中的公式可能是:

result[x] = res[p0[x] + p1[x+box] - p0[x+box] - p1[x]];

此外,总和表不需要完全计算(因此每个像素需要一个整数),但它可以在计算结果时“懒惰地”计算,并且您只需要与内核高度一样多的表行仍然保持计算时间O(image_width*image_height),但只需要kernel_height*image_width内存。

于 2013-10-04T06:29:37.427 回答