简介
OpenCV是一个流行的开源计算机视觉库,由英特尔公司发起发展。它提供了超过2500个优化算法和许多工具包,可用于灰度、彩色、深度、基于特征和运动跟踪等的图像处理和计算机视觉应用。OpenCV主要使用C++语言编写,同时也支持Python、Java、C等语言。由于其开源和广泛使用的特点,在计算机视觉和机器学习领域得到了广泛的应用。
1.图像阈值
图像阈值化(Image Thresholding)是一种常用的图像处理技术,它用来将图像分割成不同的区域或提取出感兴趣的目标。阈值化基于图像中像素灰度值的阈值进行二值化处理,将像素分为两个类别:满足条件的像素为一个类别,不满足条件的像素为另一个类别 。
图像阈值化的主要步骤如下:
-
灰度化:将彩色图像转换为灰度图像,这样每个像素只有一个灰度值。
-
选择阈值:根据应用需求和图像特性,选择一个适当的阈值。
-
阈值化处理:将图像中的每个像素与阈值进行比较,并根据比较结果设置像素的输出值。
在 OpenCV 中,可以使用 cv2.threshold()
函数来执行图像阈值化操作。
ret, dst = cv2.threshold(src, thresh, maxval, type[, dst])
-
ret
:阈值化操作的阈值,即根据阈值对图像进行二值化后得到的阈值。 -
dst
:阈值化后的输出图像,即应用阈值化操作后得到的二值图像。
其中,src
是输入的源图像,thresh
是用于二值化的阈值,maxval
是输出图像中设置为最大值的像素值,type
是阈值化的类型。
除了上述两个返回参数外,你还可以选择性地传递额外的 dst
参数作为输出图像的占位符,以便在函数调用时直接指定输出图像的尺寸和数据类型。如果未提供 dst
参数,函数将会创建一个与输入图像 src
相同尺寸和数据类型的输出图像。
请注意,阈值化类型 type
可以是以下选项之一:
-
cv2.THRESH_BINARY
:二值阈值化,大于阈值的像素值设为maxval
,小于等于阈值的像素值设为 0。 -
cv2.THRESH_BINARY_INV
:反二值阈值化,大于阈值的像素值设为 0,小于等于阈值的像素值设为maxval
。 -
cv2.THRESH_TRUNC
:截断阈值化,大于阈值的像素值设为阈值,小于等于阈值的像素值保持不变。 -
cv2.THRESH_TOZERO
:零阈值化,大于阈值的像素值保持不变,小于等于阈值的像素值设为 0。 -
cv2.THRESH_TOZERO_INV
:反零阈值化,大于阈值的像素值设为 0,小于等于阈值的像素值保持不变。
import cv2
import matplotlib as plt
import numpy as np
# 读取图像
image = cv2.imread('image/1.jpg')
# 使用不同阈值化方法进行图像处理
# 阈值为127,最大值为255
# cv2.THRESH_BINARY: 二值阈值化
ret, img = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)
# cv2.THRESH_BINARY_INV: 反二值阈值化
ret, img1 = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY_INV)
# cv2.THRESH_TRUNC: 截断阈值化
ret, img2 = cv2.threshold(image, 127, 255, cv2.THRESH_TRUNC)
# cv2.THRESH_TOZERO: 零阈值化
ret, img3 = cv2.threshold(image, 127, 255, cv2.THRESH_TOZERO)
# cv2.THRESH_TOZERO_INV: 反零阈值化
ret, img4 = cv2.threshold(image, 127, 255, cv2.THRESH_TOZERO_INV)
# 将多个处理后的图像水平拼接在一起
result = np.hstack([img, img1, img2])
# 显示结果图像
cv2.imshow('IMG', result)
cv2.waitKey()
cv2.destroyAllWindows()
这边展示前三种的效果,有兴趣可以全部尝试一下
2.形态学
2.1 膨胀操作
1、什么是膨胀与腐蚀
膨胀与腐蚀属于形态学范围,具体的含义根据字面意思来理解即可。但是更形象的话就是“增肥”与“减肥”。
它们的用途就是用来处理图形问题上。总结性的来说: + 膨胀用来处理缺陷问题; + 腐蚀用来处理毛刺问题。
膨胀就是把缺陷给填补了,腐蚀就是把毛刺给腐蚀掉了。这里其实说的并不严谨,也是为了大家理解方便。下面我们就用实例来进行演示。
dst = cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
参数说明:
src
:输入图像,可以是灰度图像或彩色图像,数据类型为uint8
。kernel
:膨胀操作的结构元素,用于定义膨胀的形状和大小。通常为矩形、十字形或椭圆形。dst
:输出图像,与输入图像具有相同的大小和类型,可选参数。anchor
:锚点位置,默认为 (-1, -1),表示锚点位于结构元素的中心点。iterations
:膨胀操作的迭代次数,默认为 1。borderType
:边界扩展类型,默认为cv2.BORDER_CONSTANT
。borderValue
:边界值,在使用cv2.BORDER_CONSTANT
边界扩展类型时有效,默认为 0。
import cv2
import numpy as np
image = cv2.imread('image/img.png')
kernel = np.ones((3 * 3), dtype=np.uint8)
dilate = cv2.dilate(image, kernel, 1)
result = np.hstack([image, dilate])
cv2.imshow('IMG', result)
cv2.waitKey()
cv2.destroyAllWindows()
可以看到右边的线条比左边的要粗一下,这个就是膨胀操作
kernel = np.ones((4 * 4), dtype=np.uint8) 更改卷积核大小
dilate = cv2.dilate(image, kernel, 3)更改迭代次数
二者均可使膨胀效果更为明显
2.2 腐蚀操作
腐蚀操作和膨胀操作相反,也就是将毛刺消除
这边的函数参数和膨胀的是一样的这里就不做详细说明了。
import cv2
import numpy as np
image = cv2.imread('image/img.png')
# kernel = np.ones((3 * 3), dtype=np.uint8)
# dilate = cv2.dilate(image, kernel, 1)
# result = np.hstack([image, dilate])
kernel = np.ones((3*3),dtype=np.uint8)
erosion = cv2.erode(image,kernel,1)
result = np.hstack([image,erosion])
cv2.imshow('IMG', result)
cv2.waitKey()
cv2.destroyAllWindows()
2.3 开运算和闭运算
开运算:先腐蚀,在膨胀 闭运算:先膨胀,在腐蚀
我们在上面的膨胀和腐蚀的图片中可以看到,图片大小程度上都受到了损失,字体信息缺失或者变粗等等。如果我们不想更改原有信息,即字体粗细。那么我们可以使用上面的两种运算。例如开运算,先对字体进行变细,在对字体进行变粗,整体上字体粗细不会发生变化。毛刺信息在腐蚀的时候就已经消除了,膨胀也不会膨胀出多余信息。
2.3.1、开运算
dst = cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
src
:输入图像,可以是灰度图像或彩色图像,数据类型为uint8
。op
:形态学操作类型,可选项包括cv2.MORPH_ERODE
(腐蚀)、cv2.MORPH_DILATE
(膨胀)、cv2.MORPH_OPEN
(开运算)、cv2.MORPH_CLOSE
(闭运算)等。kernel
:形态学操作的结构元素,用于定义操作的形状和大小。通常为矩形、十字形或椭圆形。dst
:输出图像,与输入图像具有相同的大小和类型,可选参数。anchor
:锚点位置,默认为 (-1, -1),表示锚点位于结构元素的中心点。iterations
:形态学操作的迭代次数,默认为 1。borderType
:边界扩展类型,默认为cv2.BORDER_CONSTANT
。borderValue
:边界值,在使用cv2.BORDER_CONSTANT
边界扩展类型时有效,默认为 0。
import cv2
import numpy as np
image = cv2.imread('image/img_1.png')
kernel = np.ones((4 * 4), dtype=np.uint8)
# dilate = cv2.dilate(image, kernel, 1)
# result = np.hstack([image, dilate])
# kernel = np.ones((4 * 4), dtype=np.uint8)
opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel, 1)
result = np.hstack((image, opening))
# erosion = cv2.erode(image, kernel, 2)
# result = np.hstack([image, erosion])
cv2.imshow('IMG', result)
cv2.waitKey()
cv2.destroyAllWindows()
我们发现大部分毛刺已经消除,而且字体信息也没有发生变化,这也就是我们想要的效果。虽然仍然有一部信息没有被清除,我们只需要调整卷积核的大小就可以实现。
2.3.2、闭运算
字体不改变的前提下,我们把字体缺陷信息补全。
3.梯度计算
梯度计算主要显示的是边缘信息。计算的方法:
膨胀的图像 - 腐蚀的图像
我们明显的看出,用大一圈的图像减去小一圈的图像正好就是边缘的信息。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
我们可以看出来,我们形成了一个空心的字体样式
4、高帽和黑帽
高帽计算
我们知道开运算的结果就是去除毛刺,我们原始图像减去开运算结果就是我们要消除的毛刺信息。
可以看出来,所有的毛刺信息我们全部提取了出来。
可以看出来,所有的毛刺信息我们全部提取了出来。
黑帽操作
高帽操作显示毛刺,那么黑帽就是显示缺陷。
高帽操作显示毛刺,那么黑帽就是显示缺陷。
这里我们看的不是很明显,我们只需要只要黑帽所处理的问题是什么。针对不同的场景应用不用的方法。