提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
*使用各种低通滤波器模糊图像
*将自定义滤波器应用于图像(2D卷积)
*学习不同的形态学操作,如侵蚀,膨胀,开放,关闭等。
*将看到不同的函数,如:cv.erode(),cv.dilate(),cv.morphologyEx()等。
*查找图像渐变,边缘等
*将看到以下函数:cv.Sobel(),cv.Scharr(),cv.Laplacian()等
将一平均滤波器的核(5x5)放在一个像素A上,求与核对应的图像上 25(5x5)个像素的和,取其平均值并用新的平均值替换像素A的值。重复以上操作直到将图像的每一个像素值都更新一遍。试试这段代码并检查结果:
代码如下(示例):
kernel = np.ones((5,5),np.float32)/25
dst = cv.filter2D(img,-1,kernel)
通过将图像与低通滤波器卷积核卷积来实现平滑图像。它有助于消除噪音,从图像中去除了高频内容(例如:噪声,边缘)。因此在此操作中边缘会模糊一点。(有的平滑技术也不会平滑边缘)。OpenCV主要提供四种平滑技术。
代码如下(示例):
#平均,由一个归一化卷积框完成的。它取卷积核区域下所有像素的平均
值并替换中心元素
blur = cv.blur(img,(5,5))
#高斯模糊,应该指定卷积核的宽度和高度,它应该是正数并且是奇数。
还应该分别指定X和Y方向的标准偏差sigmaX和sigmaY。如果仅指定了sigmaX,
则sigmaY与sigmaX相同。如果两者都为零,则根据卷积核大小计算它们。
blur = cv.GaussianBlur(img,(5,5),0)
#中位数模糊,取卷积核区域下所有像素的中值,并用该中值替换中心
元素。在上述滤波器中,中心元素是新计算的值,其可以是图像中的像素
值或新值。但在中值模糊中,中心元素总是被图像中的某个像素值替换,
它有效地降低了噪音。其卷积核大小应为正整数。
median = cv.medianBlur(img,5)
#双边过滤,双边滤波器在空间中也采用高斯滤波器,但是还有一个高斯
滤波器是像素差的函数。空间的高斯函数确保仅考虑附近的像素用于模糊
,而强度差的高斯函数确保仅考虑具有与中心像素相似的强度的像素用于
模糊。因此它保留了边缘,因为边缘处的像素将具有较大的强度变化。
blur = cv.bilateralFilter(img,9,75,75)
注意:如果不想使用规范化的框过滤器,请使用cv.boxFilter()。将参数normalize = False传递给函数。
形态学转换是基于图像形状的一些简单操作。它通常在二进制图像上执行。它需要两个输入参数,一个是我们的原始图像,第二个是称为结构元素或卷积核,它决定了操作的性质。
腐蚀和膨胀是两个基本的形态学运算符。然后它的变体形式如开运算,闭运算,梯度等也发挥作用。
代码如下(示例):
kernel = np.ones((5,5),np.uint8)
#腐蚀,腐蚀的基本思想就像土壤侵蚀一样,它会腐蚀前景物体的边界(总是试图保持前景为白色)。卷积核在图像中滑动(如在2D卷积中),只有当卷积核下的所有像素都是1时,原始图像中的像素(1或0)才会被认为是1,否则它会被腐蚀(变为零)。
erosion = cv.erode(img,kernel,iterations = 1)
#膨胀,恰好与腐蚀相反,它增加了图像中的白色区域或前景对象的大小增加。通常,在去除噪音的情况下,侵蚀之后是扩张。因为,侵蚀会消除白噪声,但它也会缩小我们的物体,所以我们扩大它。
dilation = cv.dilate(img,kernel,iterations = 1)
#开运算,开运算只是腐蚀之后紧接着做扩张处理的合成步骤。如上所述,它有助于消除噪音。
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
#闭运算,闭运算与开运算,膨胀和腐蚀相反。它可用于过滤前景对象内的小孔或对象上的小黑点。
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
#形态学梯度,它的处理结果是显示膨胀和腐蚀之间的差异。结果看起来像对象的轮廓。
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
#礼帽,它的处理结果是输入图像和开运算之间的区别。
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
#黑帽,它是输入图像闭运算和输入图像之间的差异。
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
我们在Numpy的帮助下手动创建了前面示例中的结构元素。它是正方形的,但在某些情况下可能需要椭圆或圆形卷积核。所以为此,OpenCV有一个函数cv.getStructuringElement()。只需传递卷积核的形状和大小,即可获得所需的卷积核。
代码如下(示例):
# 矩形核
>>> cv.getStructuringElement(cv.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]], dtype=uint8)
# 椭圆核
>>> cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0]], dtype=uint8)
# 十字形核
>>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]], dtype=uint8)
OpenCV提供三种类型的梯度滤波器或高通滤波器,Sobel,Scharr和Laplacian。
Sobel,Scharr 其实就是求一阶或二阶导数。Scharr是对Sobel(使用小的卷积核求解求解梯度角度时)的优化。Laplacian 是求二阶导数。
(1)Sobel算子和Scharr算子
Sobel算子是高斯联合平滑加微分运算,因此它更能抵抗噪声。你可以指定要采用的导数的方向,垂直或水平(分别通过参数,yorder和xorder),你还可以通过参数ksize指定卷积核的大小。如果ksize = -1,则使用3x3的Scharr滤波器,其结果优于3x3的Sobel滤波器。请参阅所用卷积核的文档。
(2)Laplacian算子
它计算由关系给出的图像的拉普拉斯算子,其中使用Sobel导数找到每个导数。
下面的代码显示了单个图表中的所有运算符,所有卷积核都是5x5大小。输出图像的深度为-1,以获得np.uint8类型的结果。
laplacian = cv.Laplacian(img,cv.CV_64F)
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
如果要检测两个边,更好的选择是将输出数据类型保持为某些更高的形式,如cv.CV_16S,cv.CV_64F等,取其绝对值,然后转换回cv.CV_8U。下面的代码演示了水平Sobel滤波器的这个过程以及结果的差异。
#输出 dtype = cv.CV_8U
sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5)
#输出 dtype = cv.CV_64F. 取绝对值并转换为cv.CV_8U
sobelx64f = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
以上是OpenCV一部分的基础操作,也是PS中锐化,色彩、亮度调整等操作的实现原理