今天开始系统的过一遍OpenCv的流程,opencv处理图像很强大,下面记录学习过程
一. 图像基本操作
1.图片数据读取
如上代码,要注意的地方是图片路劲是英文路径!!!
cv2.imshow('image', img) # 图像的显示,也可以创建多个窗口
其中参数'image'是显示窗口的标题
上述代码可以打包成一个函数,方便后续调用,也让代码可读性增加
2.图片参数分析
利用代码:print(img.shape, img1.shape)输出图片的尺寸
输出结果:(900, 900, 3) (1080, 1920, 3)
说明img和img1两张图片都是3通道,尺寸长宽分别是900 x 900和1080 x 1920
3.只提取灰度图片
如果读取图片的时候加上第二参数cv2.IMREAD_GRAYSCALE,或者0
就可以读取灰度图
输出结果如下
同时图片参数的输出也只有长宽两个参数
4.保存图片
利用cv2.imwrite()可以保存处理过的图片
cv2.imwrite('D:\\opencv\\picture\\catGray.jpg', img) cv2.imwrite('D:\\opencv\\picture\\TOMGRAY.jpg', img1)
可以看到灰度图已经保存在指定的路径中
5.计算图片像素
利用print(img.size, img1.size)可以计算图片像素大小
可以看到输出结果为 810000和2073600,这和上面计算出的图片长宽数据是一致的
6.截取部分图像数据
cat = img[400:800, 100:800]
这里的尺寸,参数1是高度从400到800,参数2是宽度从100到800
7.截取部分图像数据
import cv2 import matplotlib.pyplot as plt import numpy as np img = cv2.imread('D:\\opencv\\picture\\cat.jpg') # opencv读取的格式是RGB img1 = cv2.imread('D:\\opencv\\picture\\TOM.jpg', 0) b, g, r = cv2.split(img) # 分离图像的三个通道 print(b, g, r) print(b.shape, g.shape, r.shape) # 可以看到分离通道后的图尺寸还是相同的 img2 = cv2.merge((b, g, r)) # 处理完分离后的图像还可以合成回去 print(img2.shape)
这里可以看到b,g,三个通道分离后的数据是不一样的,分离后的图像尺寸不变
8.只保留某一通道
b g r三颜色通道分别对应0, 1, 2
如下述代码将绿色,蓝色两个通道过滤掉,只剩下红色通道
cur_img[:, :, 0] = 0 cur_img[:, :, 1] = 0
同类理获得其他通道
9.边界填充
边界填充有主要以下几种,详情见代码
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('D:\\opencv\\picture\\cat.jpg') # opencv读取的格式是RGB
img1 = cv2.imread('D:\\opencv\\picture\\TOM.jpg', 0)
b, g, r = cv2.split(img)
img2 = cv2.merge([r, g, b])
top_size, bottom_size, left_size, right_size = (300, 300, 300, 300)
replicate = cv2.copyMakeBorder(img2, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img2, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img2, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img2, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img2, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_CONSTANT, value=0)
plt.subplot(231), plt.imshow(img2, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()
运行结果如下
BORDER_REPLICATE: 复制法,也就是复制最边缘像素。
BORDER_REFLECT: 反射法,对感兴趣的图像中的像素在两边进行复制例如: fedcba|abcdefgh|hgfedcb
BORDER_REFLECT 101: 反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT: 常量法,常数值填充,这里用的是0值填充,就是黑色外边框。
10.视频数据读取
这里解释一下while循环
while open: # 如果if代码中的open的布尔值为True,就一直处理图像到视频结束
ret, frame = vc.read()
if frame is None: # 如果能读到视频中的图像,就一直读取下去
break # 如果读取不到视频中的图像了,则退出程序
if ret: # 简单写法,if ret == True 如果这一帧的图像存在
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 将图像转换成灰度图
cv2.imshow('result', gray)
if cv2.waitKey(10) & 0xFF == 27: # waiykey是视频的时间,0xFF == 27是键盘退出键,按下Esc键可以直接退出循环
break
二. 形态学
1.腐蚀操作
<1>腐蚀操作原理
就像土壤侵蚀一样,这个操作会把前景物体的边界腐蚀掉。这是怎么做到的呢?卷积核沿着图像滑动,如果与卷积核对应的图像的所有像素值都是1,那么该区域的所有像素值就是1,否则为0。用于去除白噪声和断开两个连在一起的物体等。用到的函数是cv2.erode()。
<2>案例
这里有一张图片,是一个"道"字,但是边缘有毛刺一样的东西
这里对这个"道"字进行腐蚀操作,可以看到毛刺已经去掉
代码分析
(1)erode()函数
erode()函数可以对输入图像用特定结构元素进行腐蚀操作,该结构元素确定腐蚀操作过程中的邻域的形状,各点像素值将被替换为对应邻域上的最小值
这里对主要参数进行解释
src:表示输入图像;
kernel:表示定义的卷积核
这里要是把卷积核整大一点,可以看到图像被腐蚀的更多
iterations:表示迭代腐蚀的次数,通俗的说就是腐蚀多少次。
这里要是把腐蚀的次数加大一点,可以看到文字更细了,腐蚀的更多了
2.膨胀操作
<1>膨胀操作原理
对二值化物体边界点进行扩充,将与物体接触的所有背景点合并到该物体中,使边界向外部扩张。如果两个物体间隔较近,会将两物体连通在一起。对填补图像分割后物体的空洞有用。
<2>案例
上述"道"字被腐蚀之后,可以利用膨胀操作,可以看到断连的部分已经连接起来了
3.开运算与闭运算
<1>概念
开运算:先腐蚀,再膨胀
闭运算:先膨胀,再腐蚀
<2>开运算案例
<3>闭运算案例
这里发现先进行膨胀,然后再腐蚀,毛刺更多了,是因为毛刺被膨胀加强了,然后再想腐蚀就麻烦了
开和闭主要影响图像边界,一个让凸出来的部分消失,一个让凹进去的部分填平
4.梯度运算
<1>概念
梯度 = 膨胀 - 腐蚀
梯度运算可以得出一个图像的轮廓信息
<2>案例
如下图案例所示,膨胀操作之后的图像减去腐蚀操作之后的图像,得到了图像中间的空心轮廓
5.礼帽与黑帽
<1>概念
礼帽 = 原始输入 - 开运算
黑帽 = 闭运算 - 原始输入
<2>礼帽案例
可以看到输出的图片只剩下了毛刺
<3>黑帽案例
可以看到输出的图片只剩下了边框
附注:这里总结几个报错
1.cv2.error: OpenCV(4.5.3)
初学第一个代码就报错了
cv2.error: OpenCV(4.5.3) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-q3d_8t8e\opencv\modules\imgproc\src\color.
cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'
经过查询,发现是图片中出现了中文路径,这里把路径换成英文的就没事了
2.plt.imshow()不显示图片
用matplotlib库中的plt.imshow()不显示图片,但是程序运行正常
解决办法,在代码最后一行加plt.show(),如下图所示
3.plt.imshow()图片显示失真
如下左边图所示,图中的猫猫颜色已经失真了,代码如上面错误2中
这是因为cv2中图像通道是按照bgr排列的,而matplotlib是按照rgb排列的
因此要将颜色通道重新排列,可以看到右侧猫猫颜色已经正常了
b, g, r = cv2.split(img)
img2 = cv2.merge([r, g, b])