1. 图像读取
读取方式:
cv2.IMREAD_COLOR:彩色图像
cv2.IMREAD_GRAYSCALE:灰度图像
import cv2
img=cv2.imread('myimg.jpg') # opencv读取的格式默认是BGR
2. 图像通道转换
转换方式:
cv2.COLOR_BGR2GRAY:彩->灰
cv2.COLOR_GRAY2BGR:灰->彩
2.1. 彩图转换为灰度图
gray_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2GRAY)
2.2. 灰度图转换为彩图
bgr_img = cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR)
2.3. 灰度图转换为HSV
hsv_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2HSV)
3. 截图
image = img[0:100, 0:100]
4. 二值化
ret, dst = cv2.threshold(src, thresh, maxval, type)
函数的返回值是两个值:
- ret:这是输入图像的深度。
- dst:这是阈值化后的图像。
函数的参数:
- src:输入的灰度图像。
- thresh:阈值,用于决定像素值将被视为前景或背景。
- maxval:当像素值超过(或小于,取决于阈值类型)阈值时要赋予的值。
- type:阈值类型,决定如何进行二值化操作。有以下几种类型:
- cv2.THRESH_BINARY:阈值的二值化操作,大于阈值使用 maxval 表示,小于阈值使用 0 表示。
- cv2.THRESH_BINARY_INV:阈值的二值化翻转操作,大于阈值的使用 0 表示,小于阈值的使用 maxval 表示。
- cv2.THRESH_TRUNC:进行截断操作,大于阈值的使用阈值表示,小于阈值的不变。
- cv2.THRESH_TOZERO:进行化零操作,大于阈值的不变,小于阈值的使用 0 表示。
- cv2.THRESH_TOZERO_INV:进行化零操作的翻转,大于阈值的使用 0 表示,小于阈值的不变。
# 应用阈值化操作,这里使用 THRESH_BINARY 类型
ret, thresh = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY)
# 将灰度值大于175的像素设置为255,小于175的像素设置为0
5. 图像滤波
原始图像(来源网络):
5.1. 平滑
5.1.1. 均值滤波
# 均值滤波
blur = cv2.blur(img,(5,5)) # (5,5)表示滤波器的大小
5.1.2. 高斯滤波
# 高斯滤波:高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
blur_gaussian = cv2.GaussianBlur(img,(5,5),0) # (5,5)表示滤波器的大小,0表示标准差
5.1.3. 中值滤波
# 中值滤波
blur_median = cv2.medianBlur(img,5)
5.1.4. 方框滤波
# 方框滤波:基本和均值一样,可以选择归一化,容易越界
box = cv2.boxFilter(img,-1,(3,3), normalize=True)
box = cv2.boxFilter(img,-1,(3,3), normalize=False)
5.2. 锐化
5.2.1. Scharr算子
# 使用Sobel算子计算图像在x方向和y方向的梯度,可以在边缘方向上增强边缘
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
# 用来对Sobel梯度图像进行绝对值化和缩放的,这个操作也可以使得边缘和角点的特征更加明显
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
# 将x方向和y方向的梯度图像进行加权合并
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
5.2.2. laplacian算子
# 使用Scharr算子计算图像在x方向和y方向的梯度
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
# 用来对Scharr梯度图像进行绝对值化和缩放的,使得边缘和角点的特征更加明显
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
# 是将x方向和y方向的梯度图像进行加权合并,合并后的图像就是Scharr梯度图像
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
5.2.3. 拉普拉斯算子
# 拉普拉斯算子,cv2.CV_64F 指定了输出图像的深度为64位浮点型
laplacian = cv2.Laplacian(img,cv2.CV_64F)
# 是用来对Laplacian梯度图像进行绝对值化和缩放,使得边缘和角点的特征更加明显
laplacian = cv2.convertScaleAbs(laplacian)
# 将拉普拉斯算子的结果加到原始图像上,实现锐化操作
sharp = cv2.addWeighted(img,1.5,laplacian,-0.5)
6. 形态学操作
6.1. 膨胀操作
作用于扩大图像中物体的边界
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
# 膨胀操作,iterations表示次数
dilation = cv2.dilate(img,kernel,iterations = 1)
6.2. 腐蚀操作
腐蚀操作用于消除图像中小于某个阈值的像素点,从而缩小图像中物体的边界。
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
# iterations表示次数
erosion = cv2.erode(img,kernel,iterations = 1)
6.3. 开运算
开运算是先进行腐蚀操作,再进行膨胀操作。
这个操作可以消除图像中较小的对象,同时也可以平滑较大对象的边缘。
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
# 开运算操作
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
6.4. 闭运算
闭运算是先进行膨胀操作,再进行腐蚀操作。
这个操作可以消除图像中较大的空洞,同时也可以平滑较小对象的边缘。
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
# 闭运算操作
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
6.5. 梯度运算
梯度=膨胀-腐蚀
形态梯度对于检测对象的轮廓非常有用,是膨胀操作和腐蚀操作之间的差异
计算形态学梯度,可以得到原始图像与结构元素的差分。
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
grad = cv2.morphologyEx(gray.copy(), cv2.MORPH_GRADIENT, kernel)
6.6. 顶帽/白帽运算
礼帽 = 原始输入-开运算结果
检测图像的亮区域
作用主要是增强图像的亮度,同时保留图像中的较亮的区域。
可以用来消除图像中的暗点噪声,同时也可以增强图像的对比度。
通过对原始图像和结构元素进行卷积来实现,它会使得高于周围像素的孤立点或斑块更加突出,而较低的区域会变暗。
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
tophat = cv2.morphologyEx(gray.copy(), cv2.MORPH_TOPHAT, kernel)
6.7. 黑帽运算
黑帽 = 闭运算-原始输入
检测图像的亮区域
主要用于增强图像的暗部区域,同时保留图像中较暗的区域。
可以用来消除图像中的亮点噪声,同时也可以增强图像的对比度。
黑帽变换也可以通过对原始图像和结构元素进行卷积来实现,但它会使得低于周围像素的孤立点或斑块更加突出,而较亮的区域会变暗。
# 定义结构元素
kernel = np.ones((30,30),np.uint8)
closing = cv2.morphologyEx(gray.copy(), cv2.MORPH_BLACKHAT, kernel)
7. BGR通道
7.1. 获取三色通道
b, g, r = cv2.split(img)
7.2. 显示三通道图片
7.2.1. 只保留R
# 只保留R
cur_img = img.copy()
cur_img[:,:,0] = 0
cur_img[:,:,1] = 0
cv_show('R',cur_img)
7.2.2. 只保留G
# 只保留G
cur_img = img.copy()
cur_img[:,:,0] = 0
cur_img[:,:,2] = 0
cv_show('G',cur_img)
7.2.3. 只保留B
# 只保留B
cur_img = img.copy()
cur_img[:,:,1] = 0
cur_img[:,:,2] = 0
cv_show('B',cur_img)
8. 图像边界填充
填充方式:
BORDER_REPLICATE:复制法,也就是复制最边缘像素。
BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT:常量法,常数值填充。
# 定义图像边界的尺寸,即顶部、底部、左侧和右侧各100像素
top_size, bottom_size, left_size, right_size = (100, 100, 100, 100)
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_CONSTANT, value=0)
import matplotlib.pyplot as plt
plt.subplot(331), plt.imshow(img, 'gray'), plt.title('ORIGINAL')
plt.subplot(332), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(333), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(334), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(335), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(336), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
# 显示所有的子图
plt.show()
9. 边缘检测
# 应用Canny边缘检测算法
edges = cv2.Canny(gray, 100, 200)
10. 图像轮廓
10.1. 轮廓提取
cv2.findContours说明:
使用模板:cv2.findContours(image, mode, method, offset=(0, 0))
返回值:
- contours:是一个列表,其中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。
- hierarchy:是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓对应4个hierarchy元素,表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。
参数:
- image: 二值图像,通常使用cv2.threshold或cv2.adaptiveThreshold进行阈值处理得到。
- mode: 轮廓查找模式,有以下三种:
- cv2.RETR_EXTERNAL:只检索最外面的轮廓。
- cv2.RETR_LIST:检索所有的轮廓,并以列表形式返回。
- cv2.RETR_CCOMP:检索所有的轮廓,并将它们组织为两个层次:外部的和内部的。
- cv2.RETR_TREE:检索所有的轮廓,并以树状结构组织它们。
- method: 轮廓近似方法,有以下两种:
- cv2.CHAIN_APPROX_NONE:存储所有轮廓点。
- cv2.CHAIN_APPROX_SIMPLE:存储轮廓的稀疏点集。
- offset: 偏移量,用于从输入图像的左上角开始偏移,然后绘制轮廓。通常可以设置为(0, 0)。
# 提取轮廓(版本不同,返回值的数量有可能有差异),使用二值图像可以提高精度
_,contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓并显示结果
cv2.drawContours(img_copy, contours, -1, (255, 0, 255), 2)
# 显示img_copy
10.2. 轮廓特征
- 面积:
cv2.contourArea(cnt) # cnt为轮廓列表中的某一个轮廓
- 周长:
cv2.arcLength(cnt, True) # True表示闭合的
10.3. 轮廓近似
10.3.1. 边界多边形
# 轮廓提取
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 遍历轮廓
for contour in contours:
epsilon = 0.1 * cv2.arcLength(contour, True)
# 使用等距距离方法近似轮廓。这将得到一个多边形,该多边形尽可能地逼近原始轮廓。
approx = cv2.approxPolyDP(contour, epsilon, True)
image = cv2.drawContours(image, [approx], 0, (0, 0, 255), 2)
10.3.2. 边界矩形
# 轮廓提取
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 遍历轮廓
for contour in contours:
x,y,w,h = cv2.boundingRect(cnt)
# 绘制外接矩形
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')
10.3.3. 边界圆
# 轮廓提取
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 遍历轮廓
for contour in contours:
# 计算最小外接圆,返回两个值:圆心坐标和半径
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
# 绘制外接圆
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,'img')