本文将使用opencv-python识别自定义物体,能够区分识别到的物体,如果用作人脸识别,则能够区分出不同的人脸id,也就是能够分得清张三,李四,王二麻子
(这方案已经很老了,去学 Tensorflow2或者Pytorch 吧)
本文提供的所有资源仅供学习使用,不可商用
文末有完整工程链接
效果:
识别出局座,大紧,大众和沃尔沃
vs2017+python+opencv配置请参考vs2017+python+opencv配置_qq_43440703的博客-CSDN博客
本文中文乱码问题参考博客CV2 puttext不能显示中文问题_天上飞下一毛雪的博客-CSDN博客_cv2.puttext 显示中文
为什么能让程序识别出我们想要让它识别的物体,程序怎么能认得哪个是我们想要识别的物体
此时我们需要事先训练程序,我们需要事先告诉它,哪个人是局座,哪个人是大紧,哪个车是沃尔沃,哪个车是大众
如何训练程序去认识这些人和物,我们在本文最后去讲
本教程中出现的所有的训练数据文件都包含在文末的工程文件中,下载后可直接运行
注意:
本教程只使用了少量的样本训练,精度一般,主要是了解思想
本教程中对应物体的训练数据仅对本视频文件有较好的识别概率,其他场景效果不行
如果需要在任何场景中都能识别局座或者其他人和物,需要重新使用大量到的样本数据去训练,需要成千上万个样本,本程序只是一个示例教程
掌握了思想,就可以自己去准备样本去训练
程序实现:
新建一个Python应用程序
安装opencv-python
from PIL import Image, ImageDraw, ImageFont
import cv2
import numpy as np
import time
#由于直接用opencv显示中文会乱码,所以先将图片格式转化为PIL库的格式,用PIL的方法写入中文,然后在转化为CV的格式
def change_cv2_draw(image,strs,local,sizes,colour):
cv2img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
pilimg = Image.fromarray(cv2img)
draw = ImageDraw.Draw(pilimg)
font = ImageFont.truetype("SIMYOU.TTF",sizes, encoding="utf-8") #SIMYOU.TTF为字体文件
draw.text(local, strs, colour, font=font)
image = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
return image
#src为输入的图像
#classifier为对应识别物体的分类器
#strs为识别出的物体的中文说明
#colors表示框的颜色
#minSize为识别物体的最小尺寸,当识别的物体尺寸低于这个尺寸,则不检测,就当没识别到
#minSize为识别物体的最大尺寸,当大于该尺寸时不识别
def myClassifier(src,classifier,strs,colors,minSize,maxSize):
gray=cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
#detectMultiScale()方法里面的参数在另一篇博客中有详解:https://blog.csdn.net/GottaYiWanLiu/article/details/90442274
obj = classifier.detectMultiScale(gray,scaleFactor = 1.15, minNeighbors = 5,minSize=minSize,maxSize=maxSize)
for (x,y,w,h) in obj:
cv2.rectangle(src,(x,y),(x+w,y+w),colors,2) #画框,(x,y)为识别物体的左上角顶点,(w,h)为宽和高
src=change_cv2_draw(src,strs,(x,y-20),20,colors)#显示中文
return src
#读取视频文件 若 cap=cv2.VideoCapture(0),则为获取摄像头画面
cap=cv2.VideoCapture("001.mp4")
#读取对应物体的训练数据, 注意,以下这些训练数据仅对本视频文件有较好的识别概率,其他场景不行
#其他场景中,需要重新使用大量到的样本数据去训练,本程序只是一个示例教程
juzuo=cv2.CascadeClassifier("juzuo.xml") #局座人脸的训练数据
dajin=cv2.CascadeClassifier("dajin.xml") #大紧人类的训练数据
volvo=cv2.CascadeClassifier("volvo.xml") #沃尔沃汽车的训练数据
volkswagen=cv2.CascadeClassifier("volkswagen.xml") #大众汽车的训练数据
while True:
_,frame=cap.read()
frame=myClassifier(frame,juzuo,"局座",(0,0,255),(40,40),(60,60))
frame=myClassifier(frame,dajin,"大紧",(0,255,0),(40,40),(70,70))
frame=myClassifier(frame,volvo,"沃尔沃",(255,0,0),(35,35),(70,70))
frame=myClassifier(frame,volkswagen,"大众",(0,255,255),(40,40),(70,70))
cv2.imshow("frame",frame)
cv2.waitKey(30)
如果想按Esc键退出程序
将最后一行改为:
c=cv2.waitKey(30)
if c==27:
cv2.destroyAllWindows()
break
所有参数说明看注释
如何训练我们想要识别的物体?
参考博客:
opencv3.3版本训练自己的物体分类器_刘延林 | 梦陆的博客-CSDN博客
首先我们需要安装3.0以上4.0以下的opencv
本人使用的opencv3.4.0
官网下载:Releases - OpenCV
安装完以后
在路径opencv\build\x64\vc14\bin\下有我们需要的训练程序
opencv_createsamples.exe和opencv_traincascade.exe
以本文为例:
首先新建一个文件夹取名 JuZuo
然后将opencv\build\x64\vc14\bin\下的所有文件复制到该文件夹下
然后在此文件夹下再新建一个pos文件夹,一个neg文件夹,一个xml文件夹
如下图所示:
其中neg文件夹保存我们的负样本
pos文件夹保存我们的正样本,
正负样本都是图片文件
正样本就是我们需要识别的物体的图片,而负样本中不能出现正样本
负样本下载(本人花积分从csdn上下载的):
我推荐自己去网上搜,尊重别人劳动成果,我本来想把我下载的博主的链接粘贴过来,结果找了半天没找到
先用这个吧
链接:https://pan.baidu.com/s/1ahJA6BsY4oVL20oY3GSQjg
提取码:2o95
负样本的尺寸没有具体要求,只要比正样本大就行
而正样本,尺寸需要统一,为了保准训练的速度,本文正样本图片尺寸统一20x20
需要使用ps或者其他软件裁剪一下
局座正样本下载(本人一点一点的裁的):
链接:https://pan.baidu.com/s/1Erwm59tzfdDHL3HTnu4QpA
提取码:gi7p
然后将负样本所有图片放到neg文件夹下
将局座的所有正样本图片放到pos文件夹下
然后win+r 输入cmd,打开cmd
比如本人的JuZuo文件夹在D盘
则输入 d: 然后回车
然后来到我们的负样本文件夹
输入:cd D:\JuZuo\neg 回车
此时我们已经进入neg文件夹
输入:dir /b/s/p/w *.jpg > neg.txt 回车
此时会在neg文件末尾生成一个neg.txt文件
然后我们进入pos文件夹
输入 cd D:\JuZuo\pos 回车
此时我们输入:dir /b/s/p/w *.jpg > pos.txt 回车
此时会在pos文件末尾生成一个pos.txt文件
如下图:
此时我们将neg.txt和pos.txt文件都移动到D:\JuZuo\路径下
即移动到上一层目录
此时我们需要修改一下pos.txt
此时我们借助Notepad++程序,百度Notepad++下载
右键pos.txt,使用Notepad++打开
然后 按 Ctrl+H
将所有的jpg替换成jpg 1 0 0 20 20
替换完后:
一定要记得保存
修改完后,
在回到D:\JuZuo\文件夹下
在cmd 命令提示符里输入: cd D:\JuZuo 回车
然后输入:opencv_createsamples.exe -vec pos.vec -info pos.txt -num 200 -w 20 -h 20 回车
其中-num 后面的200,是正样本的数量,比如有300个正样本,不一定要用满,比如我用200个,后面两个20 就是正样本的尺寸
如下图:
此时会在JiuZuo文件夹下创建一个pos.vec文件
此时我们新建一个文本文档
命名任意,但是需要将后缀名改为bat,比如start.bat
如下图:
此时右键start.bat,编辑
opencv_traincascade.exe -data xml -vec pos.vec -bg neg.txt -numPos 200 -numNeg 400 -numStages 15 -w 20 -h 20 -maxFalseAlarmRate 0.4 -precalcValBufSize 2048 -precalcIdxBufSize 2048 -mode ALL
pause
将这一段话复制进去保存
numPos为正样本数量,numNeg为负样本数量,numStages为分类器的级数,w和h为正样本的宽和高,maxFalseAlarmRate为最大误报率,precalcValBufSize为缓存大小,用于存储预先计算的特征值单位为MB,precalcIdxBufSize为缓存大小,用于存储预先计算的特征索引(feature indices),单位为MB。内存越大,训练时间越短。
具体参数说明请参考官方文档:
然后双击start.bat启动
然后会在xml中生成cascade.xml文件,此文件就是训练后的文件
我们只需在代码中读取此文件即可
工程链接:
链接:https://pan.baidu.com/s/1cK19bZkNFwnQDBxAo9UDfg
提取码:fosm