2

我正在尝试使用我不熟悉的概念来解决 C++ 中的一个具有挑战性的问题。

我正在尝试将过滤器应用于矩阵。但是,就像我说的那样,我对此很陌生,经过一番调查后,我发现此链接显示应用过滤器基本上是乘法

但是让我感到困惑的是,如果我的过滤器是 [0,1,0] 并且我必须将其应用于 5x5 矩阵。我怎么能做到这一点?

带有内核的 GIMP 过滤

第一个链接的替代方案

编辑:第二个链接真的让我很困惑。我现在几乎正在尝试决定“申请”过程。如果我遵循创建一个只有对角线 [0,1,0] 的 3x3 矩阵的想法,我会像在第二个链接中那样应用它,还是必须将它应用到矩阵中的每个单元格。或者,如果它真的是一维过滤器,我应该再次将它应用到每个单元格还是忽略边缘和角落?

4

4 回答 4

4

那是一个卷积核。

这个想法是你用它和它的邻居的加权平均值替换每个像素,其中权重由你的卷积核给出。该过程很好地解释了例如here

我发现你有一个一维卷积核(即适用于一维图像)很奇怪,当通常用于图像处理时使用二维卷积核(它也从上面/下面的行中获取像素) ,但可能是您的算法只需要使用当前行中的像素。

于 2012-04-04T00:55:27.317 回答
3

我认为被忽略的事情是使用输入数据的子集对输入数组的每个元素重复乘法。

GIMP 示例展示了如何使用 3x3 过滤器对单个像素过滤 5x5 图像:

. . . . .                  . . . . .
. - - - .     . . .        . . . . .
. - @ - .  x  . . .   ->   . . @ . . 
. - - - .     . . .        . . . . .
. . . . .                  . . . . .

我用 a 标记了一个输入像素,用 标记了@它的邻居-。您使用较小的矩阵:

- - -     . . .
- @ -  x  . . .  = 3x3 array
- - -     . . .

将生成的 3x3 数组中的数字相加,并将该值存储到图像中,代替@像素。

举个例子,当使用 3x1 过滤器过滤 5x5 图像时:

. . . . .                  . . . . .
. . . . .                  . . . . .
. - @ - .  x  . . .   ->   . . @ . . 
. . . . .                  . . . . .
. . . . .                  . . . . .

您将使用输入数组的较小子集来匹配您的内核;

- @ -  x  . . .  = 1x3 array

然后,再次将结果数组中的数字相加,并将该值存储到新图像中以代替@像素。

于 2012-04-04T00:55:10.780 回答
2

您在答案中寻找的内容令人困惑。如果我们假设您的过滤器存储在std::vector<double>被调用filter并且您的图像实际上是 2D 并且具有类型std::vector< std::vector<double> >称为image,那么我们可以执行以下操作来应用 1-D 过滤器[-1,0,1]

 std::vector< std::vector<double> > new_image;
 std::vector<double> filter;
 filter.push_back(-1.0); filter.push_back(0.0); filter.push_back(1.0);

 for(int i = 0; i < image.size(); i++){
     for(int j = 0; j < image.at(i).size(); j++){

         new_image.at(i).push_back( filter.at(0)*image.at(i).at(j-1)
                                    + filter.at(1)*image.at(i).at(j)
                                    + filter.at(2)*image.at(i).at(j+1) );

     }
 }

例如,如果您想要一个像这样的二维过滤器

 [0 1 0]
 [1 0 1]
 [0 1 0]

然后我们假设它也被存储为向量的向量,并且基本上也是如此。

 std::vector< std::vector<double> > new_image;

 for(int i = 0; i < image.size(); i++){
     for(int j = 0; j < image.at(i).size(); j++){

         top_filter_term = filter.at(0).at(0)*image.at(i-1).at(j-1)
                          + filter.at(0).at(1)*image.at(i-1).at(j)
                          + filter.at(0).at(2)*image.at(i-1).at(j+1);

         mid_filter_term = filter.at(1).at(0)*image.at(i).at(j-1)
                          + filter.at(1).at(1)*image.at(i).at(j)
                          + filter.at(1).at(2)*image.at(i).at(j+1);

         bot_filter_term = filter.at(2).at(0)*image.at(i+1).at(j-1)
                          + filter.at(2).at(1)*image.at(i+1).at(j)
                          + filter.at(2).at(2)*image.at(i+1).at(j+1);

         new_image.at(i).push_back(top_filter_term + mid_filter_term + bot_filter_term);

     }
 }

请注意——我没有对过滤器数组进行边界检查,你真的应该只在远离图像边缘的地方应用它,或者添加代码来应用你想要的过滤器的任何类型的边界条件. 我也没有对此进行优化发表任何声明。对于大多数用途,使用矢量是一种很好的方法,因为它们可以动态调整大小并提供足够的内置支持来执行许多有用的图像操作。但是对于真正大规模的处理,您需要优化过滤操作等内容。

至于您关于过滤 3D 数组的问题,有几件事需要考虑。一,确保您确实想要过滤整个数组。对于许多图像处理任务,将所有颜色通道拆分为它们自己的 2D 数组,进行处理,然后将它们重新组合在一起会更好、更有效。如果您确实想要一个真正的 3D 过滤器,那么请确保您的过滤器实际上是 3D 的,也就是说,它将是一个由向量​​组成的向量。然后,您将使用与上述完全相同的逻辑,但您将为应用于图像的每个颜色通道或“切片”的过滤器部分添加一层额外的术语。

于 2012-04-04T01:11:19.383 回答
0

我认为您在谈论滤色器。从技术上讲,5X5 图像实际上是 5X5X3 (A),其中“3”对应于 3 种基本颜色 (RGB)。现在,创建一个对角线为 [0,1,0] (T) 的 3X3 矩阵。

现在将这两个矩阵(AXT)相乘得到新的 5X5X3 图像矩阵。

于 2012-04-04T00:34:18.947 回答