用机器学习的方式,达到某种学习功能
机器学习:训练样本+特征+分类器(特征提取->进行判决)
深度学习:海量训练样本+人工神经网络(需要自己训练特征,海量样本)
主要围绕四个方面:
- 样本准备
- 获取机器学习特征
- 利用分类器对特征进行分类
- 预测 检验
一、样本获取
考虑自己搜集,通过视频分解图像,获取大量样本
步骤:
- load图片
- 获取图片Info信息
- parse进行解码
- imshow展示,imwrite保存
1.1 视频分解图片
# 视频分解图片
# 1 load 2 info 3 parse 4 imshow imwrite
import cv2
cap = cv2.VideoCapture("1.mp4")# 获取一个视频打开cap 1 file name
isOpened = cap.isOpened# 判断是否打开,只有正确打开才能执行后续操作
print(isOpened)
fps = cap.get(cv2.CAP_PROP_FPS)#帧率(一个视频每秒钟可以给大家展示的多少张图片)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))#w h
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(fps,width,height)#每秒钟展示的多少张图片,以及相应的宽度以及高度
i = 0#记录当前总共读取或者保存了多少张
while(isOpened):#看是否有效
if i == 10:#最多保存十张图片
break
else:
i = i+1
(flag,frame) = cap.read()# 读取每一张 flag(表示是否读取成功) frame(表明图片的内容)
fileName = 'image'+str(i)+'.jpg'#将整型转换成字符串类型
print(fileName)
if flag == True:#表明读取一张图片成功
cv2.imwrite(fileName,frame,[cv2.IMWRITE_JPEG_QUALITY,100])#图片名称,图片内容,质量等级控制
print('end!')
运行结果:
<built-in method isOpened of cv2.VideoCapture object at 0x0000000004D7F330>
帧率:29.008016032064127 宽度540 高度960(一秒钟可以展示29张图片,人眼最低是15帧)
image1.jpg
image2.jpg
image3.jpg
image4.jpg
image5.jpg
image6.jpg
image7.jpg
image8.jpg
image9.jpg
image10.jpg
end!
1.2 图片合成视频
import cv2
img = cv2.imread('image1.jpg')
imgInfo = img.shape
size = (imgInfo[1],imgInfo[0])
print(size)
#视频写入方法。可以将当前视频写入进去
# 1 名字, 2 -1 选择一个支持的解码器, 3 5帧 ,4 大小
videoWrite = cv2.VideoWriter('2.mp4',-1,5,size)# 写入对象 1 file name
# 2 编码器 3 帧率 4 size
for i in range(1,11):
fileName = 'image'+str(i)+'.jpg'
img = cv2.imread(fileName)
videoWrite.write(img)# 写入方法 1 jpg data 参数就是图片的数据,编码之前的数据
print('end!')
结果:
(540, 960)
end!
二、特征
什么是特征?
特征:
图像处理中表示某个区域的像素点,经过某种四则运算之后得到的结果(具体值,向量,矩阵,多维)
本质:像素的运算结果
如何利用特征区分目标、分类?
- 阈值判决(但是判决可能很复杂)
- 如何得到判决?使用机器学习
2.1 Haar特征
主要用于人脸识别上
14个图片,分别对应14个特征
黑白矩阵就是特征模板
- 用白色区域的特征之和,减去黑色区域的特征之和,就是最终的特征(某个区域内的四则运算)
- 整个区域权重 + 黑色权重,等同于第一个公式
Haar特征遍历
- Haar模板都要遍历一遍,需要从上到下,从左到右,size当前模板的大小,100*100 模板是10**10 则需要100个这样的模板
- 缩放
# 2 如何利用特征 区分目标? 阈值判决
# 3 得到判决?机器学习
# 1 特征 2 判决 3 得到判决
# 公式推导 1 -2
# 特征 = 整个区域*权重1 + 黑色*权重2 = (黑+白)*1+黑*(-2)=
# = 黑+白-2黑 = 白-黑
# 1 haar模版 上下 左右 image size 模版 size 100*100 10*10 100次 step = 10
# 1 100*100 2 10*10 3 step 10 4 模版1
# 模版 滑动 缩放 10*10 缩放之后,变成11*11 20级(总共可能需要缩放20次)
# 举例 图片大小:1080*720 ; 每次滑动两个像素,所以步长是2step2; 原始模板大小:10*10
# 计算量 = 14模版*20缩放*(1080/2*720/2)*(100点+- ) = 50-100亿
# (50-100)*15(不能低于15) = 1000亿次才能把Haar特征计算完,计算量太大了
积分图
# A 1第一块; B 包含第一块,第二块1 2; C 1块+3块 D 1 2 3 4四个区域加起来的部分
# 4块的像素计算 = A-B-C+D = 1+1+2+3+4 - 1 -2 - 1 -3 = 4 (10*10简化为3次+-)
沿着任意一个方框,都可以通过相邻的四个矩阵的运算操作,来获得最终的结果
2.2 Hog特征
不同于Haar特征,Haar特征直接进行模板计算,模板计算的结果叫做Haar特征
但是Hog,在模板计算的基础上更加复杂一些
蓝色:整个图片的大小
wins窗体:也设置为整个图片的大小,一般情况下要小一点
红色:block部分
绿色:cell部分
#1 什么是hog》?特征 某个像素 某种运算
#2 2·1 模块划分 2·2 梯度 方向 模版 2·3 根据梯度,方向进行bin 如何进行投影 2·4 计算每个模块hog
#2·1 模块划分
# image(整个ppt) win(蓝色长方形) block(红色) ;cell (绿色)(size)
# image》win〉block》cell
# block setp(滑动步长) win step cell bin
#win窗体 特征计算最顶层单元 -》obj (一个窗口必须包含一个目标,才能唯一描述当前obj的目标)
# 1 win size大小可以任意 50*100 20*50 官方推荐:64*128这个宽高比比较合适
# 2 2.1 block(指红色的部分)一般比win小,而且一般win是block的整数倍 《win 2.2 win size w h / block (wh) 16*16
# 3 block step 如何win下滑动 如果block是16*16,那么推荐大小8*8
# 4 计算block cout = ((64-16)/8+1)*((128-16)/ 8+1)= 105 block
# 5 cell size 8*8
# 6 block = ?cell不可滑动 16*16 = 2*2 = 》4cell cell1-cell4
# 7 bin?
Hog维度
#7 cell和bin紧紧关联在一起的 bin 梯度:就是个运算
# 每个像素-》梯度(每个像素都有一个梯度) :大小 f 方向 angle(bin和方向有关)
# 0-360 /40 = 9块 =称为9单元,一个bin就是一个bin 9bin
# 1bin = 40 cell-》360必须完整包含369度信息,就等价于包含9个bin-〉9bin
# hog特征维度:Haar特征是一个具体的值,Hog特征得到的是一个向量,所以就有一个维度的概念
# haar 值 hog 向量 (维度)-》完全描述 一个obj info all(因为是用来分类的,所以应该能完全描述一个obJ对象,包含这个obj对象的所有信息)
# 维度 = 105(block个数)*4(每个block中cell的个数)*9(每个cell对应的bin的个数)=3780 (每一个win窗体中有多少个block)
梯度计算
#2·2 梯度(基于像素计算) 方向 模版
# (计算单位是像素)像素都有一个梯度 》hog== win(所有的像素共同组合在一起,构成了Hog特征)
# 特征模版-》haar类似(Haar也是利用模板)
# 水平方向【1 0 -1】;竖直方向【【1】【0】【-1】】
# (将像素与模板进行卷积运算)a = p1*1+p2*0+p3*(-1) = 相邻像素之差
# b = 上下像素之差
# f(浮值) = 根号下(a方+b方)
# angle = arctan(a/b)
投影
# bin 投影 主要依赖于梯度
# bin 0-360 划分成9bin;每个bin范围 0-40
# bin1 0-20 180-200
# ij f a = 10
# 0-20 center bin1 ; 如果a=190 180 200 bin1
# f 计算
# 25 bin1 bin2
# f1 = f(原先f的幅度)*f(夹角) f2 = f*(1-f(夹角)) f(夹角) 计算出的范围0-1.0(是一个浮点类型)
# +1 hog (投影到哪个区间,就对哪个区域加一)
如何计算整体的特征
#整体hog cell复用
# 3780维(来自于win窗体,每一个维度就是其中的一个bin)
# 3780 《-win(block cell bin)
# 1《-bin
# cell0 cell3 bin0-bin8
# cell0: bin0 bin1 。。。bin8
# cell1: bin0 bin1 。。。bin8
# cell2: bin0 bin1 。。。bin8
# cell3: bin0 bin1 。。。bin8
#假设有个像素ij 投影到了cell0下的 bin0下=《f0,
#i+1 j(行加一,列不变) cell0 bin0 = f1
#ij。。。。
# sumbin0(f0+f1.。)= bin0(累加的形式)
# 权重累加
#ij bin0 bin1
# cell复用
# 一个block 存在4个cell
# 【0】【】【】【3】 cell0到cell3
# cell0 bin0-bin9
# 真正计算会将block进行另外一个维度的划分,这个维度上分为cellx0 cellx2 cellx4
# cellx0:ij-》bin bin+1(只对当前的cell0起作用)
# cellx2:ij -》 cell2 cell3 -》bin bin+1 bin bin+1
# cellx4:ij
# 【cell 9】【4cell】【105】 = 3780
特征判决
# 【3780】hog svm line训练【3780】(以SVM的线性分类器为例,先经过训练,同样得到一个3780维的向量)
#。hog*svm = 得到一个固定的值
# 值》T(判决门限) 目标obj
三、分类器
3.1 Adaboost分类器
Adaboost分类器优点:前一个基本分类器分出的样本,会在下一个分类器中得到加强
每一个强分类器都会计算出一个独立的特征点,使用这个独立的特征,对每一个特征进行阈值判决
#haar + adaboost face
# eg:苹果 苹果 苹果 香蕉想通过这个分类器把苹果区分出来
# 训练出结果:0.1 0.1 0.1 0.5,再进行一次,会使得负样本得到加强。
# 训练终止条件:1 for count ;2 检测概率,最小的检测概率,p
# 1 分类器的结构 2 adaboost 计算过程 3 opencv自带的,xml 文件结构
# haar> T1 and haar>T2 2个强分类器,一般adaboost个数是15-20个强分类器 (Haar特征需要进行阈值判决),每一级都通过才认可
# 1 分类器的结构
# 3个强分类器 1 x1 t1 2 x2 t2 3 x3 t3
# x1>t1 and x2>t2 and x3>t3 目标-》苹果
# 强分类器作用:判决
# 弱分类器结构
# 弱分类器作用:计算强分类器特征x1 x2 x3
# x2 = sum(y1,y2,y3)
# y1 弱分类器特征是如何计算的?归结于node结点,每一个弱分类器支持三个haar特征
# node
# 3个haar-》 node
# 1node haar1 > nodeT1(阈值判决) z1 = a1
# 1node haar1 < nodeT1 z1 = a2
# Z(整的node结点) = sum(z1,z2,z3)>T(弱分类器判决门限) y1 = AA(三个之和)
# Z = sum(z1,z2,z3)<T y1 = BB
# haar->Node z1 z2 z3 Z=sum(z1,z2,z3)每一个node结点对应一个haar特征,opencv最多有三个haar特征,所以最多三个node
# Z>T y1 y2 y3(第二层:弱分类器)
# x = sum(y1,y2,y3) > T1 obj(强分类器)【目标:就是要判决出苹果】
Adaboost分类器训练
- 初始化数据权值分布(所有权值都要相等)
- 遍历阈值 p 得到一系列误差概率
- 计算权重系数
- 更新训练数据的权值分布update
#adaboost 训练
# 1 初始化数据权值分布
# 苹果 苹果 苹果 香蕉
# 0.1 0.1 0.1 0.1
# 2 遍历阈值 p
# minP t
# 3 G1(x)权重系数
# 4 权值分布 update
# 0.2 0.2 0.2 0.7
## 训练终止条件:1 for count 2 p(误差概率p)
3.2 SVM
本质:是一个分类器,寻求一个最优的超平面完成分类
# 1 思想 分类器
# 2 如何? 寻求一个最优的超平面 分类
# 3 核:line 线性核
# 4 数据:训练样本
# 5 训练 SVM_create train predict
# svm本质 寻求一个最优的超平面 分类
# svm 核: line
# 身高体重的分类 训练 预测
import cv2
import numpy as np
import matplotlib.pyplot as plt
#1 准备data
rand1 = np.array([[155,48],[159,50],[164,53],[168,56],[172,60]])#5个人,分别指的身高、体重(女)
rand2 = np.array([[152,53],[156,55],[160,56],[172,64],[176,65]])#男
# 2 label 准备标签
label = np.array([[0],[0],[0],[0],[0],[1],[1],[1],[1],[1]])
# 3 data 标签准备好后,需要对数据进行一定的处理
data = np.vstack((rand1,rand2))# 把rand1、2合并在一起
data = np.array(data,dtype='float32')
# svm 所有的数据都要有label,标签描述当前数据的唯一的属性
# [155,48] -- 0 女生 [152,53] ---1 男生
# 监督学习 0 负样本 1 正样本
# 4 SVM训练
# 首先创建一个SVM
svm = cv2.ml.SVM_create() # ml:机器学习模块; SVM_create() 创建;完成当前支持向量机的创建
# 属性设置;设置SVM各种属性
svm.setType(cv2.ml.SVM_C_SVC) # svm type 首先设置SVM类型
svm.setKernel(cv2.ml.SVM_LINEAR) # line 设置内核,这里使用线性分类器
svm.setC(0.01) # 和svm核有关的参数
# 训练
result = svm.train(data,cv2.ml.ROW_SAMPLE,label)#1数据;2类型简单类型;3 标签
# 预测;看效果
pt_data = np.vstack([[167,55],[162,57]]) #0 女生 1男生 完成两个数据的拼接
pt_data = np.array(pt_data,dtype='float32')#数据进行转化一下
print(pt_data)
(par1,par2) = svm.predict(pt_data)#预测方法,结果是一个元组类型
print(par2)
结果:
[[ 167. 55.]
[ 162. 57.]]
[[ 0.]
[ 1.]]
四、 基于Haar+Adaboost人脸识别
案例:人脸识别:
# 1 load xml; 2 load jpg ;3 haar gray ;4 detect; 5 对于检测出的结果进行遍历,绘制,draw
import cv2
import numpy as np
# step1:load xml 1 file name 完成xml文件的引入,参数就是文件的名称
face_xml = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#训练好的人脸识别的分类器
eye_xml = cv2.CascadeClassifier('haarcascade_eye.xml')#眼睛识别的训练好的adaboost分类器
# step2:load jpg加载图片
img = cv2.imread('face.jpg')
cv2.imshow('src',img)
# step3:灰度转化haar gray 需要把b,g,r图片转化为灰度图片
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# detect faces 1 data灰度图片的数据; 2 scale比例缩放; 3 目标大小,比如不能小于5个像素 检测出的人脸
faces = face_xml.detectMultiScale(gray,1.3,5)
print('face=',len(faces))#检测当前的人脸
# draw给每一个人脸画一个框
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)#绘制的数据; 绘制的起始目标;宽度,高度;颜色;线条宽度
roi_face = gray[y:y+h,x:x+w]#表示已经找到的人脸的范围
roi_color = img[y:y+h,x:x+w]#再记录一个彩色的人脸
# 1 gray
eyes = eye_xml.detectMultiScale(roi_face)
print('eye=',len(eyes))#眼睛个数
#绘制一下眼睛,还是使用for循环,眼睛开始位置的x,y坐标,宽,高
#for (e_x,e_y,e_w,e_h) in eyes:
#cv2.rectangle(roi_color,(e_x,e_y),(e_x+e_w,e_y+e_h),(0,255,0),2)
cv2.imshow('dst',img)
cv2.waitKey(0)
结果
face= 1
eye= 2
人脸识别:使用Haar特征+adaboost分类器 (一共分为三级:强分类器,弱分类器,node结点)
五、Hog+SVM小狮子识别
小狮子识别:SVM+Hog特征(比Haar特征难很多)
其中neg是负样本(1931个);pos是正样本(820个)
正负样本的尺寸都一样
# 1 样本 2 训练 3 test 预测
# 1 样本
# 1.1 pos 正样本 包含所检测目标 neg 不包含obj
# 1.2 如何获取样本 1 来源于网络 2 来源于公司内部 3 自己收集
# 一个好的样本 远胜过一个 复杂的神经网络 (K w)(M)(样本组织很重要)
# 1.1 网络公司卖样本 样本:1张图 1元 贵
# 1.2 网络 爬虫 自己爬
# 1.3 公司: 很多年积累(mobileeye做汽车辅助驾驶 ADAS 99%) 红外图像
# 1.4 自己收集 视频 100秒视频 比如一秒会有30帧 = 那就一共有3000张图片
# 正样本:尽可能的多样 环境多样 干扰多样
# 820 pos neg 1931 ; 一般正负样本比例 1:2 1:3
# name
# 训练
# 1 参数 2hog 3 svm 4 computer hog(完成Hog计算) 5 label 6 train(完成训练) 7 pred(完成预测) 8 draw(看效果的话,可以绘图)
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 1 par 正负样本个数
PosNum = 820
NegNum = 1931
winSize = (64,128)# 窗体大小 行:64 高:128
blockSize = (16,16)# 105
blockStride = (8,8)#4 cell 步长
cellSize = (8,8)
nBin = 9#9 bin 3780
# 2 hog create hog 1 win 2 block 3 blockStride 4 cell 5 bin
hog = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nBin)
# 3 svm分类器创建
svm = cv2.ml.SVM_create()
# 4 computer hog
featureNum = int(((128-16)/8+1)*((64-16)/8+1)*4*9) #3780 特征维度
#行:正负样本的个数;列:特征个数
featureArray = np.zeros(((PosNum+NegNum),featureNum),np.float32)#标签和特征准备好
#定义标签
labelArray = np.zeros(((PosNum+NegNum),1),np.int32)
# svm 监督学习 样本 标签 svm -》image hog(SVM在学习时,学习的是图片中的Hog特征)
for i in range(0,PosNum):
fileName = 'pos/'+str(i+1)+'.jpg'#文件名称的加载
img = cv2.imread(fileName)
hist = hog.compute(img,(8,8))# 3780维 计算hog特征
for j in range(0,featureNum):
featureArray[i,j] = hist[j]
# featureArray中装载的是SVM的Hog特征 hog [1,:] hog1 [2,:]hog2 每一个Hog特征是3780维
labelArray[i,0] = 1
# 正样本 label 1
for i in range(0,NegNum):
fileName = 'neg/'+str(i+1)+'.jpg'
img = cv2.imread(fileName)
hist = hog.compute(img,(8,8))# 3780
for j in range(0,featureNum):
featureArray[i+PosNum,j] = hist[j]
labelArray[i+PosNum,0] = -1
# 负样本 label -1
svm.setType(cv2.ml.SVM_C_SVC)#添加进当前的类型
svm.setKernel(cv2.ml.SVM_LINEAR)#线性内核
svm.setC(0.01)
# 6 train
# 参数一:表示特征数组, 2 机器学习 3 标签
ret = svm.train(featureArray,cv2.ml.ROW_SAMPLE,labelArray)
# 7 myHog :《-myDetect
# myDetect-《resultArray rho
# myHog-》detectMultiScale
# 7 检测 核心:create Hog -》 myDetect—》array-》
# resultArray-》resultArray = -1*alphaArray*supportVArray
# rho-》svm-〉svm.train=SVM得到之后,才能得到RHO
alpha = np.zeros((1),np.float32)#np的方法来获取 一行一列
rho = svm.getDecisionFunction(0,alpha)# 1 0 ; 2 数组
print(rho)
print(alpha)
alphaArray = np.zeros((1,1),np.float32)# 大小设置为1*1
supportVArray = np.zeros((1,featureNum),np.float32)#支持向量机数组 1 1 ; 2 特征维度
resultArray = np.zeros((1,featureNum),np.float32)
alphaArray[0,0] = alpha
resultArray = -1*alphaArray*supportVArray
# detect 计算
myDetect = np.zeros((3781),np.float32)
for i in range(0,3780):
myDetect[i] = resultArray[0,i]
myDetect[3780] = rho[0]
# rho svm (判决)
myHog = cv2.HOGDescriptor() #Hog构建
myHog.setSVMDetector(myDetect)# .set方法设置其属性
# load
imageSrc = cv2.imread('Test2.jpg',1)
# (8,8) win 核心是MyHog
objs = myHog.detectMultiScale(imageSrc,0,(8,8),(32,32),1.05,2)#1 待检测的原图 2 0 3 8*8(滑动步长) 4 32*32 5 1.05缩放
# xy wh 三维 参数放到最后一维
#获取检测出的目标,宽,高信息
x = int(objs[0][0][0])#是一个三维,通过三维来访问
y = int(objs[0][0][1])
w = int(objs[0][0][2])
h = int(objs[0][0][3])
# 绘制展示
cv2.rectangle(imageSrc,(x,y),(x+w,y+h),(255,0,0),2)#起始位置,颜色,宽度
cv2.imshow('dst',imageSrc)
cv2.waitKey(0)
结果
(0.19288761757743814, array([[ 1.]]), array([[0]], dtype=int32))
[ 0.]