正如我们刚看到的,OpenCV的许多预定义滤波器都使用了一个核。请记住,一个核就是一组权值,决定如何根据一个输入像素的邻域计算每个输出像素。核的另一个术语是卷积矩阵。它将一个区域内的像素混合或者卷积。类似地,基于核的滤波器也称为卷积滤波器。
OpenCV提供了一个非常通用的filter2D()函数,可以应用我们指定的所有核或者卷积矩阵。要理解如何使用这个函数,我们先来了解一下卷积矩阵的格式。它是一个拥有奇数行和奇数列的二维数组。中心元素对应于感兴趣的像素,其他元素对应于该像素的邻域。每个元素包含一个整数值或者浮点值,这是一个应用于输入像素值的权值。考虑以下这个例子:
这里,感兴趣的像素的权值是9,其直接相邻的每个像素的权值是-1。对于感兴趣的像素,输出颜色是其输入颜色的9倍减去8个相邻像素的输入颜色。如果感兴趣的像素与其邻域有一些不同,这个差异就会增强。其效果是,当邻域之间的对比度增强时,图像看起来更清晰。
继续这个例子,我们可以将卷积矩阵分别应用于源图像和目标图像,如下所示:
第2个参数指定目标图像每个通道的深度(例如,cv2.CV_8U表示每个通道8位)。负值(例如,此例中为-1)表示目标图像和源图像有相同的深度。
对于彩色图像,请注意,filter2D()将核同等地应用于每个通道。为了在不同的通道使用不同的核,还必须使用split()和merge()函数。
基于这个简单的例子,我们把2个类添加到filters.py:一个类为VConvolution-Filter,表示一般的卷积滤波器;另一个为子类SharpenFilter,专门表示锐化滤波器。编辑filters.py,这样我们就可以实现这2个新类,如下所示:
请注意,权值总和是1。这应该是我们想要保持图像整体亮度不变的情况。如果稍微修改一个锐化核,使其权值之和是0,就会得到一个边缘检测核,使边缘变为白色,非边缘变为黑色。例如,将下面的边缘检测滤波器添加到filters.py:
接下来,我们制作一个模糊滤波器。通常,对于模糊效果,权值的总和应该是1,而且整个邻域像素的权值都应该是正的。例如,我们可以简单地对邻域像素求平均,如下所示:
锐化、边缘检测和模糊滤波器都使用高度对称的核。然而,有时不是很对称的核会产生有趣的效果。我们来考虑这样一个核:使一边模糊(正权值),另一边锐化(负权值)。它会产生脊状或者浮雕的效果。下面是可以添加到filters.py中的一个实现:
这组自定义卷积滤波器非常基础。事实上,它比OpenCV现成的滤波器组更基本。但是,通过一些实验,你应该能够自己编写产生独特外观的核。