Python · 计算机视觉 探险之旅

发布于:2022-11-13 ⋅ 阅读:(2250) ⋅ 点赞:(2)

第一章节   概念基础        

一、入门

        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数据集还没搞下来,先暂缓处理

哎无聊的选修课,懒得维护了,艹


网站公告

今日签到

点亮在社区的每一天
去签到