总共要获取到这些文件,opencv_createsamples.exe,opencv_traincascade.exe这两个文件在opencv的目录下可以找到
要训练,肯定要获取大量样本,我们先来制作neg和pos两个文件夹,使用这位大佬的程序,python下载百度的图片。https://blog.csdn.net/qq_34106574/article/details/90230962
import re
import requests
from urllib import error
from bs4 import BeautifulSoup
import os
num = 0
numPicture = 0
file = ''
List = []
def Find(url):
global List
print('正在检测图片总数,请稍等.....')
t = 0
i = 1
s = 0
while t < 1000:
Url = url + str(t)
try:
Result = requests.get(Url, timeout=7)
except BaseException:
t = t + 60
continue
else:
result = Result.text
pic_url = re.findall('"objURL":"(.*?)",', result, re.S) # 先利用正则表达式找到图片url
s += len(pic_url)
if len(pic_url) == 0:
break
else:
List.append(pic_url)
t = t + 60
return s
def recommend(url):
Re = []
try:
html = requests.get(url)
except error.HTTPError as e:
return
else:
html.encoding = 'utf-8'
bsObj = BeautifulSoup(html.text, 'html.parser')
div = bsObj.find('div', id='topRS')
if div is not None:
listA = div.findAll('a')
for i in listA:
if i is not None:
Re.append(i.get_text())
return Re
def dowmloadPicture(html, keyword):
global num
# t =0
pic_url = re.findall('"objURL":"(.*?)",', html, re.S) # 先利用正则表达式找到图片url
print('找到关键词:' + keyword + '的图片,即将开始下载图片...')
for each in pic_url:
print('正在下载第' + str(num + 1) + '张图片,图片地址:' + str(each))
try:
if each is not None:
pic = requests.get(each, timeout=7)
else:
continue
except BaseException:
print('错误,当前图片无法下载')
continue
else:
string = file + r'\\' + keyword + '_' + str(num) + '.jpg'
fp = open(string, 'wb')
fp.write(pic.content)
fp.close()
num += 1
if num >= numPicture:
return
if __name__ == '__main__': # 主函数入口
word = input("请输入搜索关键词(可以是人名,地名等): ")
# add = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=%E5%BC%A0%E5%A4%A9%E7%88%B1&pn=120'
url = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word + '&pn='
tot = Find(url)
Recommend = recommend(url) # 记录相关推荐
print('经过检测%s类图片共有%d张' % (word, tot))
numPicture = int(input('请输入想要下载的图片数量 '))
file = input('请建立一个存储图片的文件夹,输入文件夹名称即可')
y = os.path.exists(file)
if y == 1:
print('该文件已存在,请重新输入')
file = input('请建立一个存储图片的文件夹,)输入文件夹名称即可')
os.mkdir(file)
else:
os.mkdir(file)
t = 0
tmp = url
while t < numPicture:
try:
url = tmp + str(t)
result = requests.get(url, timeout=10)
print(url)
except error.HTTPError as e:
print('网络错误,请调整网络后重试')
t = t + 60
else:
dowmloadPicture(result.text, word)
t = t + 60
print('当前搜索结束,感谢使用')
print('猜你喜欢')
for re in Recommend:
print(re, end=' ')
我这里尝试的是识别狗,通过上述获取一定数量的正负样本,正样本,负样本的,样本越准确,数量越大,最后的效果越好。
然后通过下面的程序把样本统一修改为灰度图,尺寸改为80*80,最好根据实际情况修改,我这样最后制作出来的样本效果我感觉并不理想。负样本这里我没有改尺寸,还是保留的原始尺寸,只做了灰度处理。
# 改变图片尺寸为统一大小,在当前目录创建一个名为pos的文件夹,文件名最好不要出现中文
# 把需要统一尺寸的正样本放到里面,写上尺寸,运行程序就可以了,一般来说建议长宽在100像素一下,不然训练会很慢
import cv2
import os
w = 80
h = 80
def getimage(file_dir):
images = {}
for root, dirs, files in os.walk(file_dir):
for name in files:
images[name] = os.path.join(root, name)
return images
if __name__ == '__main__':
n = -1
aa = os.getcwd()
dirpath = os.path.join(aa, 'pos')
imagedic = getimage(dirpath)
try:
for key, value in imagedic.items():
img = cv2.imread(value)
print(value)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img2 = cv2.resize(img1, (w, h))
cv2.imwrite('pos' + str(n + 1).rjust(3, '0') + '.jpg', img2)
n += 1
except KeyboardInterrupt:
print('暂停一下')
接下来生成pos.txt文件,使用下面的代码自动生成即可。注意边上的1 0 0 80 80.
# -*- coding:utf-8 -*-
# 会在当前目录生成一个如图所示的文件,记得修改 w h 为上面修改后的尺寸值
import os
def getimage(file_dir):
images = {}
for root, dirs, files in os.walk(file_dir):
for name in files:
images[name] = os.path.join(root, name)
return images
if __name__ == '__main__':
n = 0
aa = os.getcwd()
dirpath = os.path.join(aa, 'pos')
imagedic = getimage(dirpath)
# print (imagedic)
try:
for key, value in imagedic.items():
with open('pos.txt', 'a') as f:
f.write('pos/' + str(key).rjust(3, '0') + ' 1 0 0 60 60''\n')
except KeyboardInterrupt:
print('暂停一下')
一样的方法生成neg.txt,但是要注意边上的1 0 0 80 80 这里就不需要了
接下来创建一个文件,crate_samples.bat
里面填上
".\opencv_createsamples.exe" -info "pos.txt" -vec pos.vec -num 2519 -w 80 -h 80
要注意路径,以及正样本数量填写,和尺寸填写。完成后保存。双击打开就会得到pos.vec文件了。
然后再创建train.bat训练文件,注意这里面的样本数,正样本数要比实际的要少,每计算一层后会逐增。负样本按照实际来没问题,numStages我这里用的是15层,反正我这里电脑在那里开了2天。3000就相当于内存,最后是尺寸。
".\opencv_traincascade.exe" -data ".\TrainCascadeClassification" -vec pos.vec -bg neg.txt -numPos 1500 -numNeg 4351 -numStages 15 -precalcValBufSize 3000 -precalcIdxBufSize 3000 -featureType LBP -w 80 -h 80
Pause
还得新建一个TrainCascadeClassification 文件夹,最后训练好的文件都会被保存在这个文件夹内。
双击开始训练,如果第一层开始跑起来了,就没啥大问题,没运行起来的话看看路径对不对。
打开文件夹,最后会生成一堆文件,用第一个cascade.xml就行了。
用个程序调用下试试。
# _*_ coding : UTF-8_*_
# 开发者 : Ninwji
# 开发时间 :2019/10/19 21:58
# 文件名称 :OpenImg.PY
# 开发工具 :PyCharm
# -*- coding: utf-8 -*-
import cv2
# 加载检测器
classPath = 'xxx/train/TrainCascadeClassification/cascade.xml'
face_cascade=cv2.CascadeClassifier(classPath)
print("加载检测器")
# 读取图片并灰度化
img = cv2.imread('xxx/dog_9.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print("读取图片灰度化")
cv2.imshow('show', gray)
# 框出并加上文字说明
faces = face_cascade.detectMultiScale(
gray,
scaleFactor= 1.08,
minNeighbors=5,
minSize=(70, 70),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), 2)
cv2.putText(img,'dog',(x,y-7), 3, 1.2, (0, 255, 0), 2, cv2.LINE_AA)
print("显示效果")
cv2.imshow('dog', img)
cv2.imwrite("xxx/dog3.png",img)
c = cv2.waitKey(0)
背景干净一点的时候还是能识别出来点东西的,还试了一些别的图片,可能样本的问题,还是比较容易误判的。