OpenCV 滤波与卷积之 —— 边界与阈值化

2022-08-09 15:02:23 浏览数 (1)

本文摘录OpenCV 中的卷积、滤波相关操作内容,重点介绍 Opencv 操作中处理边界卷积与阈值化相关的操作。

预备知识

滤波、核和卷积

滤波器指的是一种由一幅图像(x,y)根据像素点x,y附近的区域计算得到一幅新图像’(x,y)的算法。其中,模板规定了滤波器的形状以及这个区域内像素的值的组成规律,也称“滤波器”或者核。本章中出现的滤波器多数为线性核,也就是说I"(x,y)的像素的值由(x,y)及其周围的像素的值加权相加得来。这个过程可以用下面的方程表示:

锚点

图中的每个核都有一个点的值加粗显示,这个点就称作“核的锚点”。它定义了核与源图像的对齐关系。例如图(D)所示的核,数字41加粗显示,这意味着用于计算I’(x,y)的累加项中,一个项就是41/273I(x,y)相乘的结果(同样,I(x-1,y)I(x 1,y)26/273相乘的结果是另外两个项)。

边界外推和边界处理

在对图像进行卷积操作时需要处理边界,常用的方法是在卷积真正像素时向外扩展出虚拟数据,之后再进行卷积。在卷积函数的处理过程中为源图像添加虚拟像素是非常必要的。那么,如何对缺少相邻像素点的边缘像素点计算出一个有效的结果?实际上,在没有公认方法的情况下,我们一般通过自定义的方式在某一场景中处理问题。

1. cv2.copyMakeBorder()
  • 一个为图像创建边框的函数,通过指定两幅图像,第一幅是源图像,第二幅是扩充之后的图像,同时指明填充方法,这个函数就会将第一幅图像填补后的结果保存在第二幅图像中。
  • 函数使用
代码语言:javascript复制
cv2.copyMakeBorder(	src, 			# 输入图像
                    top, 			# 上方 padding 像素数
                    bottom, 		# 下方 padding 像素数
                    left, 			# 左侧 padding 像素数
                    right, 			# 右侧 padding 像素数
                    borderType, 	# 像素拓展方法
                    value)			# 如果为固定值拓展,需要设置该参数

  • borderType 参数说明

borderType

含义

cv2.BORDER_CONSTANT

复制指定的常量扩展边界

cv2.BORDER_WRAP

复制对边的像素扩展边界

cv2.BORDER_REPLICATE

复制边缘的像素扩展边界

cv2.BORDER_REFLECT

通过镜像复制扩展边界

cv2.BORDER_REFLECT_101

通过镜像复制扩展边界,边界像素除外

cv2.BORDER_DEFAULT

cv2.B0_RDER_REFLECT101的别名

  • 代码示例
代码语言:javascript复制
image = mt.cv_rgb_imread('img1.jpg')
res = cv2.copyMakeBorder(image, 1, 1, 1, 1, borderType=cv2.BORDER_CONSTANT, value=(255, 255, 0))
res = cv2.copyMakeBorder(res, 180, 180, 180, 180, borderType=cv2.BORDER_REFLECT)
PIS(res)

2. cv2.borderInterpolate()

计算扩充的像素对应原图哪个坐标的像素

代码语言:javascript复制
cv2.borderInterpolate(10, 1000, cv2.BORDER_REFLECT)

阈值化操作

图像处理过程中经常会遇见这种情况:我们已经完成了多层处理步骤并需要做出一个最终决定,或者将高于或低于某一值的像素置零同时其他的像素保持不变。OpenCV中的函数cv2.threshold()实现了这些功能

其原理是对于数组中每个值,根据其高于或低于这个阈值做出相应的处理,给定一个数组和阈值。根据个人喜好,也可以把阈值化操作理解成一个用 1×1 的核进行卷积,对每个像素进行一次非线性操作。

1. cv2.threshold()
  • 函数使用
代码语言:javascript复制
cv2.threshold(
	src,				# 输入图像
	thresh,				# 阈值
	maxValue,			# 超过阈值数据转换的最大值
	thresholdType		# 阈值化方法
)

  • thresholdType

阈值类型

操作

cv2.THRESH_BINARY

DST = (SRC > thresh) ? MAXVALUE : 0

cv2.THRESH_BINARY_INV

DST = (SRC > thresh) ? 0 : MAXVALUE

cv2.THRESH_TRUNC

DST = (SRC > thresh) ? THRESH : SRC

cv2.THRESH_TOZERO

DST = (SRC > thresh) ? SRC : 0

cv2.THRESH_TOZERO_INV

DST = (SRC > thresh) ? 0 : SRC

cv2.THRESH_OTSU

Otsu 算法选择阈值

  • 示例代码
代码语言:javascript复制
img = mt.cv_rgb_imread('img1.jpg')
res = cv2.threshold(img, 120, 200, cv2.THRESH_BINARY)
PIS(res[1])

  • 函数cv2.threshold()也可以自动决定最优的阈值,你只需对参数thresholdType传递值cv2.THRESH_OTSU即可。
  • Otsu 算法的思路为遍历所有可能的阈值,选择加权方差最大的那一个作为结果,具体参考 Otsu
代码语言:javascript复制
img = mt.cv_rgb_imread('img1.jpg')
res = cv2.threshold(img[:,:,0], 0, 255, cv2.THRESH_OTSU)
PIS(res[1])

2. cv2.adaptiveThreshold()

有一种与之前不同的阈值化方法,这种方法中阈值在整个过程中自动产生变化。在OpenCV中,函数cv2.adaptiveThreshold(),实现了这种方法

  • 官方文档:https://docs.opencv.org/4.5.5/d7/d1b/group__imgproc__misc.html#ga72b913f352e4a1b1b397736707afcde3
  • 函数使用
代码语言:javascript复制
cv.adaptiveThreshold(
    src, 				# 输入图像
    maxValue, 			# 分配给满足条件的像素的非零值
    adaptiveMethod, 	# 要使用的自适应阈值算法
    					# 用 BORDER_REPLICATE | BORDER_ISOLATED 来处理边界。
    thresholdType, 		# 阈值类型必须是  THRESH_BINARY 或 THRESH_BINARY_INV
    blockSize, 			# 用于计算像素阈值的像素邻域的大小, 3,5,7 等
    C[, dst]			# 用于减去的常数
    ) -> dst

  • adaptiveMethod cv2.adaptiveThreshold()根据adaptiveMethod的设置,允许两种不同的自适应阈值方法。两种方法都是逐个像素地计算自适应阈值T(x,y),方法是通过计算每个像素位置周围的b×b区域的加权平均值然后减去常数C,其中b由blockSize给定。 不同的是,如果选择的均值方法是cv2.ADAPTIVE_THRESH_MEAN_C,那么均值时取得权值是相等的;如果选择的均值方法是cv2.ADAPTIVE_THRESH_GAUSSIAN_C,(x,y) 周围的像素的权值则根据其到中心点的距离通过高斯方程得到。
  • 不同的是,如果选择的均值方法是cv2.ADAPTIVE_THRESH_MEAN_C,那么均值时取得权值是相等的;如果选择的均值方法是cv2.ADAPTIVE_THRESH_GAUSSIAN_C,(x,y) 周围的像素的权值则根据其到中心点的距离通过高斯方程得到。
  • thresholdType
  • 相对于一般的阈值化操作,当图像中出现较大的明暗差异时,自适应阈值时非常有效的。这个函数仅处理单通道8位或浮点型图像。
  • 示例代码
代码语言:javascript复制
img = mt.cv_rgb_imread('img1.jpg', gray=True)
res = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 0)
PIS(res)

示例源码

  • https://github.com/zywvvd/Python_Practise

参考资料

  • 《学习 OpenCV3》 第十章

0 人点赞