第一章节 概念基础
一、入门
1. 计算机视觉 · 定义
按照一定的算法,让计算机获得类似于人类视觉的能力;
不仅仅“视”(看到),更重要的是实现“觉”(信息分析)
2. Marr 的视觉计算理论
计算机视觉工程的先驱者
3. 三个阶段
A. , 将输入的原始图像进行处理,抽取图像中诸如角点、边缘、纹理、线条、边界等基本特征,这些特征的集合称为基元图(primitive sketch);
B. 在以观测者为中心的坐标系中,由输入图像和基元图恢复场景可见部分的深度、法线方向、轮廓等,这些信息的包含了深度信息,但不是真正的物体三维表示,因此,称为二维半图(2.5 dimensional sketch)
C. 在以物体为中心的坐标系中,由输入图像、基元图、二维半图来恢复、表示和识别三维物体(综合运用,进入三维时代)
二、图像基础
1. 模拟图像
由实际图像“拍摄”出来的【像素图】,是对实际图像的模拟
此过程也可称为离散化
2. 计算机图像
原点方向或产生变化
3. 三原色
红绿蓝RBG(Matplotlib库导入顺序,而OpenCV库恰好反过来)
4. 像素邻域
5. 像素距离
6. 部署Python环境,配置CV2和Matplotliv库
《关于我摸鱼一天后搞定PyCharm这件事》Python环境配置_影月丶暮风的博客-CSDN博客
7. 常见图像保存方式
float64 uint8 是两种常见的方式,二者之间可以相互转化
float范围在0~1 uint在0~255
OpenCV 图像导入测试
"""
显示图像(OpenCV)
"""
import cv2
# CV2是 BGR读入,显示也是BGR
# matplotlib是RBG显示,使用要记得反相
t1 = cv2.imread("HF.jpg", 1) # 读入图片(按照BGR格式)
# 处理形式写0是【灰度读取】,不写或写1 为【彩色读取】(图像地址不可是中文)
# cv2.namedWindow("Image_Test") # 创建窗口
cv2.imshow("Image_Test", t1) # 显示图像
if cv2.waitKey() == 27: # 等待摁下 esc键后销毁窗口
cv2.destroyAllWindows()
Matplotlab 与 CV2 的互动
"""
显示图像(matplotlib)
"""
# 导入模块
import cv2
import matplotlib.pyplot as plt
# 读取图像
T1 = cv2.imread("HF.jpg")
# 直接使用 Matplotlib 显示图像 (显示异常) cv导入为BGR顺序
plt.imshow(T1) # matplotlib是 RGB顺序
plt.show()
# 将颜色通道从 BGR 转换为 RGB
# T1 = T1[:, :, ::-1] # 方法一
T1 = cv2.cvtColor(T1, cv2.COLOR_BGR2RGB) # 方法二
# 使用 Matplotlib 显示图像
plt.imshow(T1)
plt.show()
8. 关于滤波核:越大越能去除噪点,但是会牺牲清晰度;越小越清晰,但是无法消除噪点
所以太大太小都不是好的,应该适中;另外,滤波核喜欢取得奇数个数的像素点.
第二章节 图像边缘与角点检测
一、图像文件结构
1. 位图
由像素构成,分为8 16 24bit三种位型,分别为256色 65536色 2^24色
来表示一个像素点,越高位数能表示的色彩也就越丰富,相应地会更占内存
A. BMP文件由文件头、位图信息头、颜色信息和图像数据四部分组成
文件头主要包含文件的大小、文件类型、图像数据偏离文件头的长度等信息;
位图信息头包含图象的尺寸信息、图像用几个比特数值来表示一个像素、图像是否
压缩、图像所用的颜色数等信息
颜色信息包含图像所用到的颜色表,显示图像时需用到这个颜色表来生成调色板,
但如果图像为真彩色呢?
图像数据表示图像的相应的像素值。
B. 图像的像素值在文件中的存放顺序为从左到右,从下到上
C. 文件存储图像的每一行像素值时,如果存储该行像素值所占的字节数为4 的倍数
则正常存储,否则,需要在后端补0 ,凑足4的倍数
D. JPGE和GIF 都是 有损压缩
jpge常见三种:标准型,渐进型,JPGE2000
(从上到下加载显示,从模糊到清晰显示,更好的压缩避免异常显示)
这是我老婆!
2. 图像预处理
A. 模糊化
用于消除噪声(白点); 常见三种方法:均值滤波、中值滤波、高斯滤波
本质上都是取得一定区域的像素块,合成一个新的像素块来代替一块
均值滤波(取平均值)中值滤波(取中位数)高斯(加权平均值)
如果能预测噪点出现的位置,高斯滤波在对应区域削弱权值,达到消除效果
"""
图像模糊
"""
# 导入模块
import cv2
import matplotlib.pyplot as plt
# 设置正常显示正文和负号
import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 正常显示中文
mpl.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 均值模糊
img = cv2.imread("HF.jpg", 0) # 读取灰度图
dst = cv2.blur(
img, # 输入图像
(5, 5) # 内核大小
)
# 图像显示
plt.subplot(1, 2, 1)
plt.imshow(img, 'gray')
plt.title('noise')
plt.subplot(1, 2, 2)
plt.imshow(dst, 'gray')
plt.title('blur')
plt.show()
# 中值模糊
img = cv2.imread("HF.jpg", 0) # 读取灰度图
dst = cv2.medianBlur(
img, # 输入图像
(5) # 内核大小
)
# 图像显示
plt.subplot(1, 2, 1)
plt.imshow(img, 'gray')
plt.title('noise')
plt.subplot(1, 2, 2)
plt.imshow(dst, 'gray')
plt.title('medianBlur')
plt.show()
# 高斯模糊代码
img = cv2.imread("HF.jpg", 0) # 读取灰度图
dst = cv2.GaussianBlur(
img, # 输入图像
(5, 5), # 内核大小
0 # 高斯核标准差
)
# 图像显示
plt.subplot(1, 2, 1)
plt.imshow(img, 'gray')
plt.title("noise")
plt.subplot(1, 2, 2)
plt.imshow(dst, 'gray')
plt.title("GaussianBlur")
plt.show()
B. 锐化
用于强化细节轮廓对比度,增强图像
强化图像≠强化数据,前者是为了图片质量优化,后者是给出更多的样本来训练神经网络
"""
图像锐化
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# 设置正常显示中文和负号
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 读取灰度图
moon = cv.imread("HF.jpg", 0)
moon_copy = np.copy(moon)
# print(moon.dtype)
moon_float = moon_copy.astype("float") # 修改图像类型
# print(moon_float.dtype)
# 计算梯度图
row, column = moon.shape
gradient = np.zeros((row, column))
for x in range(row - 1):
for y in range(column - 1):
gx = abs(moon_float[x + 1, y] - moon_float[x, y]) # 通过相邻像素相减计算图像梯度
gy = abs(moon_float[x, y + 1] - moon_float[x, y]) # 通过相邻像素相减计算图像梯度
gradient[x, y] = gx + gy
# 叠加灰度图与梯度图得到锐化图
sharp = moon_float + gradient
sharp = np.where(sharp < 0, 0, np.where(sharp > 255, 255, sharp)) # 将小于0的像素设置为0,将大于255的像素设置为255
# 修改图像类型
gradient = gradient.astype("uint8")
sharp = sharp.astype("uint8")
# 显示图像
plt.subplot(1, 3, 1)
plt.imshow(moon, "gray")
plt.title("灰度图")
plt.subplot(1, 3, 2)
plt.imshow(gradient, "gray")
plt.title("梯度图")
plt.subplot(1, 3, 3)
plt.imshow(sharp, "gray")
plt.title("锐化图")
plt.show()
3. 边缘检测 · 以灰度为例 · 启示录
看一阶微分函数的激变点
4.灰度直方图
横坐标:左深右浅,灰度 纵坐标:像素点个数
直方图均衡化:数量少 且 有一定横轴跨度 -----> 合成一个像素 (横向压缩)
数量多 且 横轴跨度窄 ----> 横轴拉长(横向扩张)
5. 边缘检测
A. 边缘分析
黑色低,白色高,依照路径灰度变化形成函数,看一阶二阶导数情况
B. 一阶导数算子 (梯度算子)
罗伯特交叉算子(两个斜向),蒲瑞维特算子(水平纵向),索贝尔算子(加权水平纵向)
C. 二阶导数算子
拉普拉斯算子(中间正数,周围一圈都是负数,总和=0),马尔算子(预处理)
6. 边缘闭合
像素连接,有相似性,认为边界是连在一起的(看梯度幅度,梯度方向,变化不大的)
A. 模板 非最大消除
四个方向:横向 纵向 主对角向 副对角向
B. 插值 非最大消除
?
C. Canny 边缘检测 双阈值算法
去噪、计算梯度幅度方向、非极大值抑制、双阈值(滞后阈值)算法确定边缘部署阈值max min
边缘从max上下来,在中间区域连续的,可以算作边缘(保留)
从max下来,直穿min线的,切除掉
边缘就没通过max的,直接去除
edges1 = cv2.Canny(img, 200, 300)
# 如果发现边缘很稀疏,那可以把200调小一点(更宽松的门槛)
# 如果发现到处都是边缘,那就把200变大一点(提高门槛)
D. 轮廓查找函数
cv2.findContours(contour,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
只能对 二值图像 进行轮廓查找
7. 角点检测
A. 什么是角点:物体轮廓方向改变的点
B. 核心思想
搞个圆形模板,每个像素的灰度值和核心的灰度值进行比
相似的标记为1,认为是边缘;反之标记为0,认为不是边缘
8. harris角点检测
滑动窗口: 窗口内像素(灰度)变化情况为E
1 怎么动变化不大,说明在平面
2 在边缘线上变化不大,沿着边缘滑动,认为是边缘
3 无论往哪个方向走变化都大
二值轮廓查找
import cv2
img = cv2.imread('img/0402.jpg')
# 采用二值化方式处理图像,像素值在182-255之间为1, 小于182像素值的数据为0
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 182, 255, 0)
cv2.imshow('Gray', img_gray) # 灰度图效果
# 使用简易方式,获取全部轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow('Bin', thresh) # 二值化效果
# 传入的参数,图像,轮廓坐标,所有轮廓,轮廓颜色(红色), 线宽
img = cv2.drawContours(img, contours, -1, (0, 0, 255), 2)
cv2.imshow('Contour', img) # 绘制轮廓效果
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
Harris角点检测
import cv2
import numpy as np
img = cv2.imread('img/0403.jpg') # 读取图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转化为灰度图
gray = np.float32(gray) # 检测角点必须保证图像为浮点数据类型
# gray:输入的浮点灰度图
# 2: 检测中考虑的领域大小
# 3:sobel求导中使用的窗口大小 3*3
# 0.04: Harris 角点检测方程中的自由参数,取值参数为[0.04, 0.04]
dst = cv2.cornerHarris(gray, 2, 3, 0.04) # 这里是设定一个阈值 当大于这个阈值分数的都可以判定为角点
img[dst > 0.01 * dst.max()] = [0, 0, 255] # [0, 0, 255]红色
cv2.imshow('dst', img)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
Canny边缘检测
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 画图文字使用黑体字显示(显示中文,默认不支持中文)
t1 = cv2.imread('img/0401.jpg') # 读取图片
t1 = cv2.cvtColor(t1, cv2.COLOR_BGR2RGB) # 转换通道
t2 = cv2.Canny(t1, 200, 300) # 使用Canny算法,滞后阈值分别设定为200,300
# 如果发现边缘很稀疏,那可以把200调小一点
# 如果发现到处都是边缘,那就把200变大一点
plt.subplot(121) # 绘制第一张子图,总共为1行2列
plt.title('原始图')
plt.imshow(t1)
# 去除图片的坐标尺
plt.xticks([])
plt.yticks([])
plt.subplot(122) # 绘制第2张子图,总共为1行2列
plt.title('轮廓处理1')
plt.imshow(t2, cmap='gray')
plt.xticks([])
plt.yticks([])
# 显示图像效果
plt.show()
第三章节
一、基本图形绘制
1. 直线 矩形+多边形 圆形+椭圆
2. ASRC - 代码示例
import cv2
import numpy as np
# t1 = cv2.imread("Test_1/HF.jpg", 1)
t1 = np.zeros((512, 1024, 3), np.int8) # 原点在左上角
# 直线 目标图像 起点 终点 颜色BGR 粗细
# cv2.line(t1, (0, 0), (256, 256), (0, 0, 256), 5)
# 矩形 目标图像 起点 终点 颜色 粗细
# cv2.rectangle(t1, (10, 10), (128, 128), (0, 0, 255), 3)
# 圆形 目标 圆心 半径 颜色 填充模式-1 正数表示粗细
# cv2.circle(t1, (256, 256), 100, (0, 0, 255), 10)
# 椭圆 图形 圆心 长短轴(从圆心到边) 顺时针旋转角度 开始角度 结束角度 颜色 填充模式
# cv2.ellipse(t1, (256, 256), (256, 128), 10, 0, 360, (0, 0, 255), -1)
# 多边形 部署结点Array 图形 结点集 是否闭合 颜色 粗细
# idx = np.array([[50, 50], [400, 100], [462, 462], [100, 400]], np.int64)
# cv2.polylines(t1, [idx], True, (0, 0, 255), 3)
# 文字 字体部署 目标图像 文字内容 文本框左下角坐标 文本字体 文字大小 文字颜色 文字粗细 文字线形
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(t1, "Teloy_SXH", (10, 300), font, 4, (255, 255, 255), 3, cv2.LINE_AA)
cv2.imshow("Image_Test", t1) # 显示图像
if cv2.waitKey() == 27: # 等待摁下 esc键后销毁窗口
cv2.destroyAllWindows()
二、几何变换
0. 齐次坐标
为了统一旋转和平移的操作,减少运算量,给二维平面部署的时候,新增一个参数
平移加法,旋转乘法,转化为【矩阵运算】的过程,实现坐标转换
二维齐次坐标 ( x , y , h )
说明:xy点对应的是三维空间的一条直线,h=0表示无穷远点
h下降,图片放大
A. 平移变换
B. 旋转变换
C. 放缩变换
1. 平移
X = x + t1 Y = y + t2
2. 旋转
注意绕着哪个点,【原点】【图像中心点】;逆时针为正向变换
3. 放缩
4. (错切)
y不变,x = x + t * y (反之亦然);图形从正方形横向拉伸成平行四边形
5. 综合变换
先移动到坐标原点,旋转后再移动回去;其中,矩阵运算从右边到左边
so 三个矩阵分别实现:【移动 +x +y】【逆时针旋转θ】【移动 -x -y】
6. OpenCV 实现
import cv2
import matplotlib.pyplot as plt
import numpy as np
t1 = cv2.imread("Test_1\HF.jpg") # 640 * 640
T1 = cv2.cvtColor(t1, cv2.COLOR_BGR2RGB) # 颜色转化
plt.imshow(T1)
plt.show() # 获得带坐标的独立窗口
# 缩放测试
# t2 = cv2.resize(t1, (100, 100)) # 精准放缩 图片对象 宽度高度
t2 = cv2.resize(t1, None, fx=0.5, fy=0.5) # 比例放缩
T2 = cv2.cvtColor(t2, cv2.COLOR_BGR2RGB) # 颜色转化
plt.imshow(T2)
plt.show() # 获得带坐标的独立窗口
# 平移测试
M = np.float64([[1, 0, 100], [0, 1, 500]]) # 3*3 矩阵 没写的最后一行填写 0 0 1
t3 = cv2.warpAffine(t2, M, (800, 800))
T3 = cv2.cvtColor(t3, cv2.COLOR_BGR2RGB) # 颜色转化
plt.imshow(T3)
plt.show() # 获得带坐标的独立窗口
# 旋转测试
M = cv2.getRotationMatrix2D((320, 320), 45, 1) # 旋转中心 旋转角度 缩放比例 形成矩阵
t4 = cv2.warpAffine(t1, M, (800, 800)) # 图像来源 旋转矩阵 旋转后图像的大小 (注意旋转中心的选择)
T4 = cv2.cvtColor(t4, cv2.COLOR_BGR2RGB) # 颜色转化
plt.imshow(T4)
plt.show() # 获得带坐标的独立窗口
三、图像采集
1. 坐标系统
世界坐标系,摄像机坐标系,图像平面【像素/物理】坐标系
均满足右手法则,啊
2. 小孔成像
倒像,满足三角形相似性;中线上的交叉点与焦距有关
3. 相机 扫视角与倾斜角(分离模型)
扫视角是相机方向与世界坐标系x的夹角,倾斜角是和世界坐标系z轴的夹角
4. 分离模型转化为重合模型
调整扫视角,再调整倾斜角,让坐标轴xyz与世界坐标轴重合起来
5. 亮度与灰度信息的捕获
四、图像测距
1. 单目相机(结构光法)
最简单快捷,但是精度较低,需要数据库进行计算支持,需要参照点
2. 双目相机
由2个已知距离的摄像头测距,精度较高,无需使用数据库样本,占用内存少
成本略高于单目测距,俩相机之间的距离有一定限制
3. 雷达 / 红外线
精度最高,成本最高,无需数据库支持
五、图像标定
0. 标定的目的
修正畸变图像,进行有效映射
1. 标定程序和步骤
A. 外部参数:标定物的世界坐标 相机坐标 朝向
内部参数:摄像头内部焦距、成像原点 五个畸变参数(k1,k2,k3,p1,p2)等
双目摄像头还需标定右摄像头相对左摄像头的旋转矩阵R,平移向量t。
B. 懒得分析了贴图
2. 两级标定法
3. 张正友标定法 (棋盘)
4. 自适应标定法
5. 相关实践运用
图像校正、视角变换,图像拼接、增强现实
理论部分基本结束
第四章节
一、概念引入
1. SVM支持向量机
特点:更好的鲁棒性,有监督的分类算法
思想:平面上有2类点,希望找到一个划分超平面,有最好的泛化能力,获得区分能力
2. 基于深度学习的目标检测
识别图像的内容是什么:需要大量的训练数据得出参数后,再进行模型验证和参数调整
3. 如何进行机器学习?
分类器函数h(x),训练参数θ,调整参数(人工过程)
内部是确定好结构的卷积神经网络,期待随机梯度下降,由经验策略辅助
线性组合+非线性激活。通过反向传播算法,计算损失函数对于网络参数的梯度
4. 关于sklearn库
Scikit-learn 0.20.4 以上版本将joblib作为独立库独立出去了,因此更高版本的
sklearn库中无法调取joblib工具;取而代之的是直接import joblib
但这依旧会导致一些老代码出现异常,我暂时还没研究出解决办法(倒腾大半天了)
sklearn中关于SVM算法分为2类,分类算法库、回归算法库
5. 关于HOG 方向梯度直方图
A. HOG特征通过计算和统计局部区域的梯度方向直方图来构成特征
B. 对光学形变有较好的不变性
C. 在行人检测过程中,有利于忽略行人的一些小动作而专注于整体直立状态
6. 关于HOG特征提取
A. 色彩和伽马归一化
进行色彩调整,使过曝光/欠曝光的部分得以修复
B. 计算水平垂直梯度,得出 总体度值+方向
C. 图像切分为多个cell,计算各个cell的梯度直方图
以cell=8*8为例子,获得8*8*2=128个特征值(梯度大小+方向)
D. 选取4个Cell,一起形成1个Block(2*2的cell捆绑)(滑动窗口方式)
滑动窗口使多个block可以有交叠的部分
以8*16的cell为例子,获得(8-1)*(16-1)=105个block
每个cell有3*3=9个数值,2*2个cell=4个cell/1个block 1个block有4*9=36个特征
全图像获得105*36=3780个特征描述
7. 关于IOU交并比
在行人检测中,目标行人的框,算法得出的框;两个框面积取并作为分母
两个框面积取交作为分子,取得的百分比;体现结果重合度
8. 补充例题
图像512,cell正方形宽8,一行可以切分出64个cell,所以M=N=64
看block由4个cell拼成,滑动步伐也是1个cell(上下或左右)
那么切分的特征块有(64-1)*(64-1)=3969块 不同的block
(向左滑动1格cell或向下亦同,即使有重叠部分与上一块block,依旧算作一个新block)
维度cell=9 block维度由4个cell组成 =4*9=36 总维度=单block维度*block块数=b*d=142884
二、卷积神经网络
1. 基本设计
可以直接输入处理整个图像,不同于SVM将图像展开成一维度向量,卷积神经网络可以处理整个图像,可以在局部特征提取的过程中保留特征的共享性,以此在一定程度上减少待求参数的数量; 另外,图像输入有几个通道,就有几个通道的卷积核,
2. 卷积层
A. 以3*3的卷积核为例,以滑动窗口的方式,扫描整个图像,将一个窗口(按照一定权
值)浓缩为一个像素(特征);
B. 每次扫描后,得出的特征图就会变小一圈 所以叫做内卷求积
3. 激活层
和卷积层捆绑一块的,只是为了实现区分判断,最早期开始是使用 sigmoid
后面开始使用relu,后者的优势在于计算量更小
4. 池化层
在局部区域计算最大值或平均值,降低分辨率提高鲁棒性,节省计算量
5. 全连接层
本质是多层感知器,内置多个参数,通过矩阵乘法将输入特征映射为输出特征
6. 概率连接(类别概率)
到此为止,丢失进度已经全部追回,Pycharm还没调好sklern中的 joblib 问题
svm示例和人物识别代码还没跑,MNIST数据集还没搞下来,先暂缓处理
哎无聊的选修课,懒得维护了,艹