上一篇教程: 如何使用 OpenCV 扫描图像、查找表和时间测量
下一篇教程: 图像操作
原始作者 | Bernát Gábor |
兼容性 | OpenCV >= 3.0 |
矩阵的掩码操作非常简单。其思想是根据掩码矩阵(也称为内核)重新计算图像中每个像素的值。该掩码包含一些值,这些值将调整相邻像素(以及当前像素)对新像素值的影响程度。从数学角度来看,我们进行加权平均,并使用我们指定的权重值。
我们以图像对比度增强方法为例。基本上,我们希望对图像的每个像素应用以下公式
\[I(i,j) = 5*I(i,j) - [ I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]\]
\[\iff I(i,j)*M, \text{其中 } M = \bordermatrix{ _i\backslash ^j & -1 & 0 & +1 \cr -1 & 0 & -1 & 0 \cr 0 & -1 & 5 & -1 \cr +1 & 0 & -1 & 0 \cr }\]
第一种表示方法是使用公式,第二种表示方法是使用掩码对第一种表示方法进行压缩。您可以通过将掩码矩阵的中心(在上面用零零索引表示)放在要计算的像素上,并将重叠矩阵的值乘以像素值,然后将结果相加来使用掩码。这两种方法是一样的,但是对于大型矩阵,后一种表示方法更容易理解。
您可以从 这里 下载此源代码,或者在 OpenCV 源代码库的示例目录中查看 samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp
。
您可以从 这里 下载此源代码,或者在 OpenCV 源代码库的示例目录中查看 samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java
。
您可以从 这里 下载此源代码,或查看 OpenCV 源代码库示例目录中的 samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py
。
现在让我们看看如何使用基本像素访问方法或使用 filter2D() 函数来实现这一点。
这是一个执行此操作的函数
首先,我们确保输入图像数据为无符号字符格式。为此,我们使用 CV_Assert 函数(宏),当其中的表达式为假时,它会抛出错误。
首先,我们确保输入图像数据为无符号 8 位格式。
首先,我们确保输入图像数据为无符号 8 位格式。
我们使用与输入图像相同大小和相同类型的输出图像。正如您在 存储 部分中看到的,根据通道数,我们可能有一个或多个子列。
我们将通过指针遍历它们,因此元素总数取决于此数字。
我们将使用普通的 C [] 运算符访问像素。因为我们需要同时访问多行,所以我们将获取每行的指针(前一行、当前行和下一行)。我们需要另一个指针指向我们将保存计算结果的位置。然后只需使用 [] 运算符访问正确的项目。为了将输出指针提前移动,我们只需在每次操作后增加它(一个字节)即可
在图像的边界上,上面的符号会导致不存在的像素位置(如负一负一)。在这些点上,我们的公式是未定义的。一个简单的解决方案是在这些点上不应用内核,例如,将边界上的像素设置为零
我们需要访问多行和多列,这可以通过向当前中心 (i,j) 加或减 1 来完成。然后我们应用 sum 并将新值放入 Result 矩阵中。
在图像的边界上,上面的符号会导致不存在的像素位置(如 (-1,-1))。在这些点上,我们的公式是未定义的。一个简单的解决方案是在这些点上不应用内核,例如,将边界上的像素设置为零
我们需要访问多行和多列,这可以通过向当前中心 (i,j) 加或减 1 来完成。然后我们应用 sum 并将新值放入 Result 矩阵中。
在图像处理中,应用此类滤波器非常普遍,因此在 OpenCV 中有一个函数可以处理应用掩码(在某些地方也称为内核)。为此,您首先需要定义一个保存掩码的对象
然后调用 filter2D() 函数,指定要使用的输入、输出图像和内核
该函数甚至还有一个可选的第五个参数来指定内核的中心,第六个参数用于在将过滤后的像素存储到 K 中之前添加一个可选值,第七个参数用于确定如何处理操作未定义的区域(边界)。
此函数更短、更简洁,并且由于有一些优化,因此通常比手工编码的方法更快。例如,在我的测试中,第二个函数只花了 13 毫秒,而第一个函数花了大约 31 毫秒。差异相当大。
例如
您可以在我们的YouTube 频道上查看程序运行的示例。