我有一个像素矩阵和一个自定义过滤器,它使用根据特定内核的邻居,它作为参数给出,以及内核半径。 (比如说 - 交叉\方形内核等)
目前,这是通过迭代像素完成的,并且每个像素都会超过整个半径并询问每个像素是否在内核中。
部分代码段:
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
}
}
}
}
显然,由于分支成本高,这不是很有效 什么可能更有效(并且最好是优雅),但一般(而不是内核类型特定)实现呢?
感谢。
答案 0 :(得分:3)
如果您正在进行简单的卷积,您可以简单地将滤镜蒙版放入Mat中,并将图像和蒙版传递给函数filter2d,如here所述。为此,掩模不需要是可分离的。
如果您要进行相关而不是卷积,则必须沿两个轴翻转遮罩,然后应用filter2d。
如果要执行非线性过滤,最好的方法是从BaseFilter类派生自己的过滤器。由于我自己还没有这样做,所以我不能再给你一些关于如何做到这一点的提示。
我指向OpenCV功能的原因是它们使用SIMD指令和TBB进行了高度优化。你可能不会比这更快。另一点是,在使用它们时,你不必考虑边界。
显然,这些函数都假定为矩形内核,但通常可以通过将内核值设置为某个特殊值来欺骗OpenCV,以便中间结果不会影响整体结果。对于具有盘形内核的卷积,这将是0,因为图像元素的0倍是0并且将不会对总和求出贡献。虽然这似乎是一种不必要的计算,但它通常比执行检查更快,因为正如您所说的那样,支持分支。