目录
一、准备阶段
正样本集:正样本集为包含“识别物体”的灰度图,一般大于等于2000张,尺寸不能太大,尺寸太大会导致训练时间过长。
负样本集:负样本集为不含“识别物体”的任何图片,一般大于等于5000张,尺寸比正样本集稍大。一般为正样品集的3倍。
在当前文件夹下新建五个文件夹,pos和neg放处理后的图片,ini_pos和ini_neg放原来的图像,xml放以后自定义生成的分类器
将下载的正负样本集分别放入ini_pos和ini_neg文件夹。
我百度图片上下载了船的图片到ini_pos,鱼的图片到ini_neg
注意:好的正训练集最好还是图片中只有你需要的物体,而没有其他物体和背景干扰,百度图片里面有动图gif格式图片,不能通过opencv读取,下载完后看好图片后缀。
下面是初始的俩个样品集
二、图片处理
样品集需要统一大小和统一改为灰度图
代码:
import cv2 as cv
import matplotlib.pyplot as plt
import os
#解决中文显示问题,固定格式,直接复制下面俩行代码就行
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
pospath = "./ini_pos"#正样本集文件夹路径
pos = os.listdir(pospath)#读取路径下的所有文件
negpath = "./ini_neg"
neg = os.listdir(negpath)
#图片处理,注意图片不能有gif格式
def picdif():
global pos,neg;
i=1;
for picname in pos:#遍历pos文件数组所有的文件名
#读取灰度图
pic=cv.imread(pospath+"\\"+picname)
pic=cv.cvtColor(pic,cv.COLOR_BGR2GRAY)
#修改尺寸
pic=cv.resize(pic,(40,40))
#保存图片
cv.imwrite("./pos/"+str("%03d"%i)+".jpg",pic)
i+=1
#同理对负样本集进行处理
j = 1;
for picname in neg: # 遍历neg文件数组所有的文件名
#读取灰度图
pic=cv.imread(negpath+"\\"+picname)
pic=cv.cvtColor(pic,cv.COLOR_BGR2GRAY)
#修改尺寸
pic=cv.resize(pic,(50,50))
#重命名,并保存图片
cv.imwrite("./neg/"+str("%03d"%j)+".jpg",pic)
j+=1
if __name__ == '__main__':
# 1.导入文件夹,对图像统一处理,统一尺寸大小,统一灰度图
picdif()
处理后的正负样本集和图片:
三、生成描述文件
正样本描述文件如下:
其中"1"为图片数量(0,0)坐标,(40,40)是正样本集的长宽
负样本描述文件如下:
代码更新:
a_main.py
import cv2 as cv import os #解决中文显示问题,固定格式,直接复制下面俩行代码就行 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False pospath = "./ini_pos"#正样本集文件夹路径 pos = os.listdir(pospath)#读取路径下的所有文件 negpath = "./ini_neg" neg = os.listdir(negpath) #图片处理,注意图片不能有gif格式 def picdif(): global pos,neg; i=1; for picname in pos:#遍历pos文件数组所有的文件名 #读取灰度图 pic=cv.imread(pospath+"\\"+picname) pic=cv.cvtColor(pic,cv.COLOR_BGR2GRAY) #修改尺寸 pic=cv.resize(pic,(40,40)) #保存图片 cv.imwrite("./pos/"+str("%03d"%i)+".jpg",pic) i+=1 #同理对负样本集进行处理 j = 1; for picname in neg: # 遍历neg文件数组所有的文件名 #读取灰度图 pic=cv.imread(negpath+"\\"+picname) pic=cv.cvtColor(pic,cv.COLOR_BGR2GRAY) #修改尺寸 pic=cv.resize(pic,(50,50)) #重命名,并保存图片 cv.imwrite("./neg/"+str("%03d"%j)+".jpg",pic) j+=1 # 描述文件生成 def createtxt(): global pos, neg #正样本描述文件: for picname in pos: line ="pos/"+picname+" 1 0 0 40 40"+"\n"#"1"为图片数量(0,0)是坐标,(40,40)是正样本集的w,h with open('pos.txt', 'a') as f: f.write(line) #负样本描述文件: for picname in neg: line ="neg/"+picname+"\n"#(0,0)是坐标,(40,40)是正样本集的w,h with open('neg.txt', 'a') as f: f.write(line) if __name__ == '__main__': # 1.导入文件夹,对图像统一处理,统一尺寸大小,统一灰度图 picdif() #pos和neg改成处理后的图片文件夹; pospath = "./pos"#正样本集文件夹路径 pos = os.listdir(pospath)#读取路径下的所有文件 negpath = "./neg" neg = os.listdir(negpath) #2.正负样本描述文件的生成 createtxt()
四、生成.vec文件
获取opencv_createsamples.exe和opencv_traincascade.exe
这两个软件在opencv安装包里是没有的,只有下载opencv以及opencv_contrib源码自己编译才会生成这两个可执行程序
我是直接下载别人的程序,下面是网址
opencv341_bin: 编译opencv以及opencv_contrib以后的bin文件夹,里面包含一些可执行程序https://gitee.com/lizaozao/opencv341_bin注意下载依赖项解压到opencv_createsamples.exe和opencv_traincascade.exe同一目录下
在该主目录文件下打开终端窗口,win11可直接通过右键“在终端打开”
输入
.\opencv_createsamples.exe -info pos.txt -vec detect_number.vec -bg neg.txt -num 19 -w 40 -h 40
-info 正样本txt
-vec 是你生成vec文件的位置和名称
-bg 负样本txt
-num 正样本数量
-w 正样本宽度
-h 正样本高度
五、生成.xml自定义分类器文件
当前主目录文件夹终端下输入
./opencv_traincascade.exe -data xml -vec detect_number.vec -bg neg.txt -numPos 19 -numNeg 25 -numStages 20 -featureType HAAR -w 40 -h 40
-data 前面创建好的xml文件夹
-vec 是你之前生成vec文件
-bg 负样本集txt
-numPos 正样本的数量
-numNeg 负样本的数量
-numStages 训练步数
-featureType 特征类型训练时,提取图像特征的类型,目前只支持LBP、HOG、Haar三种特征。但是HAAR训练非常非常的慢,而LBP则相对快很多,因为HAAR需要浮点运算,精度自然比LBP更高
-w -h 正样本的宽高
结果:
由于样本较少,训练十秒就完成了
六、识别检测
上一节课已经说了,直接上代码
main.py文件
import cv2 as cv import matplotlib.pyplot as plt #解决中文显示问题,固定格式,直接复制下面俩行代码就行 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False # 加载分类器 cascade = cv.CascadeClassifier("./xml/cascade.xml") cascade.load("./xml/cascade.xml") # 读取灰度图片 pic1 = cv.imread("boat.jpg") pic2= cv.imread("./ini_neg/0b46f21fbe096b639ef96b67fc926942eaf8ac49.jpeg") pic1=cv.resize(pic1,(100,100)) pic2=cv.resize(pic2,(400,400)) pic2[200:300,100:200]=pic1 gray = cv.cvtColor(pic2,cv.COLOR_BGR2GRAY) # 探测图片中的船只 faces = cascade.detectMultiScale( gray, scaleFactor = 1.1, minNeighbors = 150, minSize = (50,50), ) #绘制矩形 pic3=pic2.copy() for (x,y,w,h) in faces: cv.rectangle(pic3,(x,y),(x+h,y+w),(0,0,255),5) #绘图 fig,axes=plt.subplots(nrows=1,ncols=2) axes[0].imshow(pic2[:,:,::-1]) axes[0].set_title("原图") axes[1].imshow(pic3[:,:,::-1]) axes[1].set_title("识别") plt.show() cv.waitKey()
由于所选样本太太太太少,且有些正样本不纯不好,导致结果偏差比较大
根据以上教程,可以不断像文件夹添加样本图片达到上千,生成.vec和.xml文件,完成自己的物品识别,完整代码放在下面,可以自己下载修改