基本文件
工具下载:https://download.csdn.net/download/weixin_42206625/12869520
在 pc 上安装 opencv
打开命令行
pip install opencv-python==4.1.2.30
这里指定安装版本
正样本
首先用手机拍几十张上百张只有需识别对象的照片,
运行 正样本_txt生成.py 处理正样本,同时会生 pos.txt 正样本的描述文件,在运行前先在同级目录下创建 pos 文件夹
# -*- coding: utf-8 -*-
# 斌彬电脑
# @Time : 2020/9/14 0014 17:10
"""处理正样本"""
import os
import cv2
# 原始图片路径
path = "C:aa/pos_/"
# 正样本路径
path_2 = "pos/"
# 宽度,高度
w = 20
h = 20
# pos文件中图片数量
n = 0
with open('pos' + '.txt', 'w')as f:
for i in os.listdir(path):
print(i)
img = cv2.imread(path+str(i), cv2.IMREAD_GRAYSCALE)
# 将pos文件中图片压缩为50*50
img5050=cv2.resize(img, (w, h))
cv2.imshow("img", img5050)
cv2.waitKey(20)
n += 1
n_path = path_2 + 'pos' + str(n).rjust(3, '0') + '.jpg'
cv2.imwrite(n_path, img5050)
# 图片路径 txt 文件
# f.write(n_path + ' 1 0 0 w h' '\n')
f.write(n_path + ' 1 0 0 '+ str(w) + ' ' + str(h)+ '\n')
# 生成的 pos.txt :
'''
# 图片路径名称 检测出的样本数量如果是2个写2, 0 0是图像的坐标 50,50图片大小
C:aa/pos1/pos020.jpg 1 0 0 50 50
C:aa/pos1/pos021.jpg 1 0 0 50 50
'''
- path = 写自己用手机拍的正样本图片路径,
- path_2 = 处理后生成的正样本图片
- w = 正样本图片的宽度 (最好在20~120)
- h = 正样本图片的高度 (最好在20~120)
pos.txt 描述文件
负样本
可以用手机拍几十,百张拍照片作为负样本,最好在应用场景中拍,负样本中不要出现要识别的物体,张数大概是正样本的3倍,图片尺寸只要比正样本的大就行, 运行 负样本_txt生成.py 前,在同级目录惠创建 neg 文件夹,同时会生成负样本描述文件 neg.txt
# -*- coding: utf-8 -*-
# 斌彬电脑
# @Time : 2020/9/15 0015 14:22
"""处理负样本"""
import os
import cv2
# 原始图片路径
path = "C:aa/neg_/"
# 负样本路径
path_2 = "neg/"
# 宽度,高度
w = 50
h = 50
n = 0
with open('neg' + '.txt', 'a')as f:
for i in os.listdir(path):
print(path+str(i))
img = cv2.imread(path+str(i), cv2.IMREAD_GRAYSCALE)
# img5050=cv2.resize(img, (w, h))
# cv2.imshow("img", img5050)
# cv2.waitKey(20)
n += 1
n_path = path_2 + 'neg' + str(n).rjust(3, '0') + '.jpg'
cv2.imwrite(n_path, img)
# 图片路径 txt 文件
f.write(n_path +'\n')
# f.write(n_path + ' 1 0 0 ' + str(w) + ' ' + str(h) + '\n')
neg.txt
在 cmd 中 cd 到 opencv_createsamples.exe 所在文件夹下运行如下命令,生成训练用的 vec 文件,
opencv_createsamples.exe -vec pos.vec -info pos.txt -num 22 -w 20 -h 20
-vec :写 vec 文件名
-info:pos.txt 在处理正样本时生成的正样本说明文件
-num :正样本的系数
-w :正样本照片的宽度 要与 正样本_txt生成.py 的 w 值一至
-h :正样本照片的高度 要与 正样本_txt生成.py 的 h 值一至
pause
开始训练前在同目录下创建 xml 文件夹
运行如下命令,开始训练
opencv_traincascade.exe -data xml -vec pos.vec -bg neg.txt -numPos 22 -numNeg 63 -numStages 15 -w 20 -h 20 -minHitRate 0.999 -maxFalseAlarmRate 0.2 -weightTrimRate 0.95 -featureType LBP
-vec :写 vec 文件名
-info:pos.txt 在处理正样本时生成的正样本说明文件
-num :正样本的系数
-w :正样本照片的宽度 要与 正样本_txt生成.py 的 w 值一至
-h :正样本照片的高度 要与 正样本_txt生成.py 的 h 值一至
pause
完成后在 xml 中
就是训练好的 xmll
测试 xml 文件
# -*- coding: utf-8 -*-
# 斌彬电脑
# @Time : 2020/9/17 0017 14:54
"""测试训练好的分类器"""
import cv2
faceCascade = cv2.CascadeClassifier("cascade.xml")
cap = cv2.VideoCapture(0)
flag = 0
timeF = 10
while True:
flag+=1
ret, frame = cap.read()
img = frame.copy()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
rect = faceCascade.detectMultiScale(
gray,
scaleFactor=1.15,
minNeighbors=3,
minSize=(3,3),
flags = cv2.IMREAD_GRAYSCALE
)
for (x, y, w, h) in rect:
cv2.rectangle(frame, (x, y), (x+w, y+h), (200, 2, 0), 3)
print(x,y,w,h)
# 识别到物体后进行裁剪保存
# jiequ = img[x:(x+w), y:(y+h)]
# cv2.imwrite('c:aa/'+str(flag) + '.jpg', jiequ) # save as jpg
#读取到保存图片
# if(flag%timeF==0):
# cv2.imwrite('c:aa/'+str(flag) + '.jpg',frame) #save as jpg
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
下面是多物体识别
# -*- coding: utf-8 -*-
# 斌彬电脑
# @Time : 2020-06-20 下午 2:51
"""opencv多物体分类器,中文显示"""
from PIL import Image, ImageDtrraw, 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为识别物体的最小尺寸,当识别的物体尺寸低于这个尺寸,则不检测,就当没识别到
# minxize为识别物体的最大尺寸,当大于该尺寸时不识别
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")
cap = cv2.VideoCapture(0)
# 读取对应物体的训练数据, 注意,以下这些训练数据仅对本视频文件有较好的识别概率,其他场景不行
# 其他场景中,需要重新使用大量到的样本数据去训练,本程序只是一个示例教程
juzuo = cv2.CascadeClassifier("cascade.xml") # 螺丝
# 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)
简化版用在树莓派上
# -*- coding: utf-8 -*-
# 斌彬电脑
# @Time : 2020/9/20 0020 11:01
"""opencv多物体分类器,英文显示"""
import cv2
A = cv2.CascadeClassifier("cascade.xml")
B = cv2.CascadeClassifier("cascade.xml")
C = cv2.CascadeClassifier("cascade.xml")
def myClassifier(classes, gray, frame, name=None):
rect = classes.detectMultiScale(
gray,
scaleFactor=1.15,
minNeighbors=3,
minSize=(3, 3),
flags=cv2.IMREAD_GRAYSCALE
)
for (x, y, w, h) in rect:
cv2.rectangle(frame, (x, y), (x + w, y + h), (200, 2, 0), 3)
print(x, y, w, h)
print('类名:', name)
return frame
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
img = frame.copy()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = myClassifier(A, gray, frame,'A')
# frame = myClassifier(A, gray, frame,'B')
# frame = myClassifier(A, gray, frame,'C')
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()