前言
- 没想到吧,这就总结了。没错我学习的三分钟热度真的太强了,这几天作业都没好好做,全在看这一套opencv的教程。那么就在大概第四天的时候把这一套教程给全部实验了一遍。
- 不管怎么说,这一套教程呢,我作为小白学者觉得非常不错,讲的不深也有一些小挑战(略微简单,不过需要细品)。其实可以通过这些知识和技巧来做自己的延申,我还没有多尝试,唯一一次尝试使用对比字母轮廓形状的方法找到正确的字母,用他给的‘A’成功了,自己在网上找了个‘C’,预处理还做了闭运算轮廓只有一条,结果算法结果是像A我真的吐了。
- 那么鉴于我一下子就学完了,而且每一章都像之前那样复制性的总结其实没多大意义,教程我电脑里也有,想复习了再去看看就可,所以这次来一个总结,目的就是略微的提到写我觉得的重点。
知识点回忆
1. 摄像头 or 视频
2. matplotlib的使用
3. 图像基本操作
4. 颜色空间转换
5. 阈值分割
6. 图形几何变换
7. 绘图功能
8. 图像混合
1. 摄像头 or 视频
- 我看了下,之前讲完了前三个部分,调用电脑摄像头,可以用来截取一帧图像、可以将摄像头的连续若干帧图像保存成视频的形式
- 可以打开一个视频,如果你利用cv2来创建一个滑动条
cv2.createTrackbar()
(滑动就会对应有回调函数)还能实现拖动视频播放进度,借助cv2.setTrackbarPos()
、cv2.getTrackbarPos()
其实看函数名也知道是干什么的,这里不多讲了
cv2.VideoCapture()
可以打开摄像头或者视频文件,cap.get(propId)
、cap.set(propId,value)
来得到和修改摄像头的很多属性
cv2.imwrite()
来保存图片或者视频,保存视频的时候要注意提前设置好视频编码方式,我看有挺多的可能根据需要到时候就会了解吧、当然读取图片还是得cv2.imread()
捕获视频中的一帧
ret, frame = capture.read()
2. matplotlib的使用
- 其实这整套教程也没咋用到,他和matlab里的plot用法有点像,都是subplot。不过要注意,他来显示图像时,
plt.imshow()
中后一个参数cmap的参数选择,灰度图就是cmap = 'gray'
,而且imshow之后必须要加plt.show()
,要不然图片就不显示,可以看一下老师怎么写的
1 | titles = ['Original', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV'] |
- matplotlib中图像显示RGB顺序,opencv是BGR,显示时需要通道倒置一下
3. 图像基本操作
- 读取像素点的值直接
img[100, 90]
,修改也是这样。
img.shape
形状中包括行数、列数和通道数
- 截取ROI,非常简单一看就懂,
face = img[100:200, 115:188]
,这也只能是个矩形,不过得到轮廓或者利用掩码方式得到一块想要的区域也行
- 彩色图的BGR三个通道是可以分开单独访问的,
b, g, r = cv2.split(img)
;也可以合并组成图像img = cv2.merge((b, g, r))
4. 颜色空间转换
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
图像形式转换,教程中用他来转换成HSV颜色模型,改成cv2.COLOR_BGR2HSV
就行了
mask = cv2.inRange(hsv, lower_blue, upper_blue)
,其实inRange这个函数我感觉不太重要,因为后面有阈值分割,但可能这个是针对真彩图像,与阈值分割多是用于灰度图
- 然后很重要的一个
res = cv2.bitwise_and(frame, frame, mask=mask)
,这个位操作是图像只存在0和255也就是二值图像的关键操作,可以在以后的二值图像处理里起到作用,特别是应用在掩码图的得到
5. 阈值分割
- 这一段是之后的基础,全都讲起来有点麻烦了,我就不多说。额,先说一句,这个应该是用在处理灰度图上的
- 固定阈值:
ret, th = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
,第二个参数是设定的阈值,第三个是最大值,最后一个阈值的方式,种类主要5种
- 自适应阈值:
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 4)
,不同之处就在第三个参数,小区域阈值的计算方式;最后一个参数:最终阈值等于小区域计算出的阈值再减去此值(光看看不懂,想试试就自己试试)
Otsu阈值:看代码就知道怎么用了,原理自便
1
2
3
4
5
6
7
8
9# 固定阈值法
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
# Otsu阈值法
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 先进行高斯滤波,再使用Otsu阈值法
blur = cv2.GaussianBlur(img, (5, 5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)光线不均匀的图片就用自适应阈值就完事了
6. 图形几何变换
- 其实我觉得这一章是很重要的,因为图像处理应该会有很多时候待处理的目标是需要几何变换特别是立体上的仿射变换
cv2.resize()
可以自己定义大小,也可以按比例缩放,用处会很多,我不知道和下面这个有什么关系,用处大不大,或者说在哪里使用
1 | lower = cv2.pyrDown(img) # 向下采样一级 |
cv2.flip(img, 1)
第二个参数决定是镜像、垂直、镜像垂直翻转
- 平移图片,需要用到矩阵,用仿射变换函数
cv2.warpAffine()
实现;旋转也是,而且用这个函数前,还要加个得到旋转对应的矩阵的函数cv2.getRotationMatrix2D()
,你看这还只是2D的
$$
M = \left[
\begin{matrix}
1 & 0 & t_x \newline
0 & 1 & t_y
\end{matrix}
\right]
$$
仿射变换
- 二维的,懂了吗,基本的图像变换就是二维坐标的变换:从一种二维坐标(x,y)到另一种二维坐标(u,v)的线性变换,你得先得到一个矩阵,那么就可以转换了,矩阵T(2×3)就称为仿射变换的变换矩阵
$$
\begin{matrix}
u=a_1x+b_1y+c_1 \newline
v=a_2x+b_2y+c_2
\end{matrix}
$$
$$
\left[
\begin{matrix}
u \newline
v
\end{matrix}
\right] = \left[
\begin{matrix}
a_1 & b_1 \newline
a_2 & b_2
\end{matrix}
\right] \left[
\begin{matrix}
x \newline
y
\end{matrix}
\right]+\left[
\begin{matrix}
c_1 \newline
c_2
\end{matrix}
\right]
$$
$$
R=\left[
\begin{matrix}
a_1 & b_1 \newline
a_2 & b_2
\end{matrix}
\right], t=\left[
\begin{matrix}
c_1 \newline
c_2
\end{matrix}
\right],T=\left[
\begin{matrix}
R & t
\end{matrix}
\right]
$$
- 然后几行代码看懂,现根据三个点和对应的三个点得到变换矩阵,然后直接转整个图像
1 | # 变换前的三个点 |
透视变换
- 三维的,就是立体上如何把一个目标看得顺眼一点,一个身份证你斜着拍的,那我想让他能像平着拍的一样舒服,那就用这个方法
$$
\begin{matrix}
X=a_1 x + b_1 y + c_1 \newline
Y=a_2 x + b_2 y + c_2 \newline
Z=a_3 x + b_3 y + c_3
\end{matrix}
$$
$$
\left[
\begin{matrix}
X \newline
Y \newline
Z
\end{matrix}
\right] = \left[
\begin{matrix}
a_1 & b_1 & c_1 \newline
a_2 & b_2 & c_2 \newline
a_3 & b_3 & c_3
\end{matrix}
\right] \left[
\begin{matrix}
x \newline
y \newline
1
\end{matrix}
\right]
$$
- OpenCV中首先根据变换前后的四个点用
cv2.getPerspectiveTransform()
生成3×3的变换矩阵,然后再用cv2.warpPerspective()
进行透视变换
1 | # 原图中卡片的四个角点 |
变换 | 矩阵 | 自由度 | 保持性质 |
---|---|---|---|
平移 | [I, t](2×3) | 2 | 方向/长度/夹角/平行性/直线性 |
刚体 | [R, t](2×3) | 3 | 长度/夹角/平行性/直线性 |
相似 | [sR, t](2×3) | 4 | 夹角/平行性/直线性 |
仿射 | [T](2×3) | 6 | 平行性/直线性 |
透视 | [T](3×3) | 8 | 直线性 |
7. 绘图功能
感觉画图功能不太用得到,不过也是用起来很方便,绘制形状的函数有一些共同的参数
- color:绘制的颜色,是彩色图就估计是BGR,就输一个三维元组ok;灰度图就一个255以内的数
- thickness:线宽,默认为1;对于矩形/圆之类的封闭形状而言,传入-1表示填充形状
- 建议画什么线型都加一个
lineType=cv2.LINE_AA
比较好看
img = np.zeros((512, 512, 3), np.uint8)
可以直接用这样一句话来创建一个纯色图
cv2.line(img, (0, 0), (512, 512), (255, 0, 0), 5)
,起点、终点
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
,左上、右下
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
,圆心、半径
cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, (255, 0, 0), -1)
,椭圆中心、x/y轴长度、旋转角度、起始角度、结束角度,具体自己试试
1 | # 使用cv2.polylines()画多条直线 |
- 添加文字:
cv2.putText(img, 'ex2tron', (10, 500), font,4, (255, 255, 255), 2, lineType=cv2.LINE_AA)
8. 图像混合
👴乏了,找时间再写吧