在二进制 {0, 255} 图像中找到中位数时消除分支
Eliminate branching when find median in a binary {0, 255} image
我有一个二进制图像,二进制值是 0 或 255。 图像数据的类型是无符号字符。在这里,我需要对此图像进行中值过滤。
我认为使用直方图找到中位数应该很快。使用一些代码来解释:
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]++;
}
}
}
然后,我们可以非常快速地得到中值。但是由于这种情况,代码仍然可以改进:
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} 映射到某些内容,以便我们可以更新标志而不进行分支。
有人有什么建议吗?
255 的所有位都是 1,因此您可以将"if"简化为:
hist[image(i,j) & 1]++;
如果要使用计数器,可以执行以下操作:
counter += (image(i,j) & 2)-1;
这种计算可以更快、更具体地O(n)
像素数,并且与内核大小无关。
这个想法是首先进行"扫描转换",计算一个求和面积表,其中每个(x,y(像素的值被替换为从(0,0(到(x,y(的所有像素的总和。
鉴于此,您可以在固定时间内知道在任何矩形中使用
st(x0, y0) + st(x1, y1) - st(x0, y1) - st(x1, y0)
假设每个像素都是 0 或 1,总和会给你 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
内存。
相关文章:
- 在 1.5 秒内找到 3 到 4 个不同整数的中位数超过 2000 万
- 十进制的中位数是多少?
- 如何使用第一个、中间和最后一个元素的中位数正确分区?
- 使用 boost::累加器::统计来查找数组的中位数
- 从向量中提取最小值、最大值和中位数的最有效方法是什么
- 有没有办法避免此函数中的分支/条件逻辑?
- 如果方法是常量,如何找到向量的中位数?
- 在C++中实现两个大小相等的排序数组的中位数
- 查找一组循环数据的中位数
- 为什么我的中位数快速选择算法segfault
- 是否可以实施中位数的中位数intreselect而没有掉期或堆的分配
- 两个分类阵列的中位数不同
- C++平均值和中位数绝对偏差返回相同的奇怪符号
- 通过 uva 的中位数程序
- 找到二叉搜索树的中位数,C++
- 双向链表的中位数
- 通过 C 加加号中的函数查找中位数
- C++:平均中位数和众数
- SCIP中的分支机构和价格
- 在二进制 {0, 255} 图像中找到中位数时消除分支