根据内核/掩码在相关的相邻像素上有效地迭代

时间:2014-09-23 12:35:41

标签: c++ opencv filter pixel

我有一个像素矩阵和一个自定义过滤器,它使用根据特定内核的邻居,它作为参数给出,以及内核半径。 (比如说 - 交叉\方形内核等)
目前,这是通过迭代像素完成的,并且每个像素都会超过整个半径并询问每个像素是否在内核中。
部分代码段:

for (uint32_t y = 0; y < height; y++)
{
    for (uint32_t x = 0; x < width; x++)
    {
        // Compute bottom and top according to kernel radius and borders
        for (uint32_t wy = bottom; wy <= top; ++wy)
            {
                int ny = wy - y;
                for (uint32_t wx = left; wx <= right; ++wx)
                {
                    int nx = wx - x;
                    if (selectedKernel.at<unsigned char>(cv::Point(nx + halfWinX,
                                                                    ny + halfWinY)) == 0)
                    {
                        continue;  // Current pixel not in kernel, nothing to do
                    }
                    // Do the actual processing
                }
            }
    }
}

显然,由于分支成本高,这不是很有效 什么可能更有效(并且最好是优雅),但一般(而不是内核类型特定)实现呢?

感谢。

1 个答案:

答案 0 :(得分:3)

如果您正在进行简单的卷积,您可以简单地将滤镜蒙版放入Mat中,并将图像和蒙版传递给函数filter2d,如here所述。为此,掩模不需要是可分离的。

如果您要进行相关而不是卷积,则必须沿两个轴翻转遮罩,然后应用filter2d。

如果要执行非线性过滤,最好的方法是从BaseFilter类派生自己的过滤器。由于我自己还没有这样做,所以我不能再给你一些关于如何做到这一点的提示。

我指向OpenCV功能的原因是它们使用SIMD指令和TBB进行了高度优化。你可能不会比这更快。另一点是,在使用它们时,你不必考虑边界。

显然,这些函数都假定为矩形内核,但通常可以通过将内核值设置为某个特殊值来欺骗OpenCV,以便中间结果不会影响整体结果。对于具有盘形内核的卷积,这将是0,因为图像元素的0倍是0并且将不会对总和求出贡献。虽然这似乎是一种不必要的计算,但它通常比执行检查更快,因为正如您所说的那样,支持分支。