实际应用筛选器的内容

What is actually applying a filter?

本文关键字:筛选 应用      更新时间:2023-10-16

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

我正在尝试对矩阵应用过滤器。然而,正如我所说,我在这方面还很陌生,经过一些调查,我发现了这个链接,它表明应用滤波器基本上是一个乘法

然而,让我困惑的是,如果我的滤波器是[0,1,0],并且我必须将其应用于5x5矩阵。我该怎么做?

基于内核的GIMP过滤

第一链路的替代方案

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

这是一个卷积内核。

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

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

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

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

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

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

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

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

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

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

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

- @ -  x  . . .  = 1x3 array

然后,再次对所得阵列中的数字求和,并将该值存储到新图像中以代替@像素。

这会混淆您在答案中寻找的内容。如果我们假设您的过滤器存储在一个名为filterstd::vector<double>中,并且您的图像实际上是2D的,并且类型为std::vector< std::vector<double> >,称为image,那么我们可以执行以下操作来应用一维过滤器[-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的,也就是说,它将是一个向量的向量。然后,您将使用与上面完全相同的逻辑,但对于应用于图像的每个颜色通道或"切片"的过滤器部分,您将有一层额外的术语。

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

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