版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaopangzi313/article/details/78925991
在人脸检测中,有时候会用到haar分类器,我们会使用opencv\sources\data\haarcascades下haarcascade_frontalface_alt.xml文件,但是系统提供xml文件场景有限,有时候我们需要自己定制。比如说,如果检测手掌,这个时候系统没有提供相关的xml,就需要自己制作。
以下为制作和测试流程:
1.下载负类图像样本并采集目标图片
采用爬虫的方式,这里采集Image Net上的图片作为负样本,代码如下:
def download_images():
#Image Net 挖掘机类图片
img_url = 'http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n03996416'
# 创建图片保存目录
if not os.path.exists('neg'):
os.makedirs('neg')
urls = urllib.request.urlopen(img_url).read().decode()
img_index = 1
url_list = urls.split('\n')
for index, url in enumerate(url_list):
try:
print(url)
urllib.request.urlretrieve(url, 'neg/' + str(img_index) + '.jpg')
# 把图片转为灰度图片
gray_img = cv2.imread('neg/' + str(img_index) + '.jpg', cv2.IMREAD_GRAYSCALE)
# 更改图像大小
image = cv2.resize(gray_img, (150, 150))
# 保存图片
cv2.imwrite('neg/' + str(img_index) + '.jpg', image)
img_index += 1
except Exception as e:
print(e)
# 去除重复的图片
delete_dup_files()
执行完后,在neg目录中会生成 灰度图像如下,
目标图像根据需求制定,如下hand.jpg:
2.制作xml
def make_neg_txt_file():
file_list = os.listdir('neg')
for s_file in file_list:
temp_list = s_file.split('_')
if len(temp_list) > 1:
new_filename = temp_list[1]
os.rename('neg/' + s_file, 'neg/' + new_filename)
with open('neg.txt', 'w') as f:
for img in os.listdir('neg'):
line = 'neg/' + img + '\n'
f.write(line)
def make_xml_file():
# 制作负样本TXT文件
if not os.path.exists('neg.txt'):
make_neg_txt_file()
# 生成pos.txt 文件,其中hand.jpg为目标图像
if not os.path.exists('pos.txt'):
cmd_pos = 'opencv_createsamples -img hand.jpg -bg neg.txt -info pos.txt -maxxangle 0.5 -maxyangle 0.5'
os.system(cmd_pos)
# 生成向量文件 pos.vec
if not os.path.exists('pos.vec'):
cmd_vec = 'opencv_createsamples -info pos.txt -num 30 -w 20 -h 30 -vec pos.vec'
os.system(cmd_vec)
# 开始训练,生成xml文件
if not os.path.exists('data'):
os.system('mkdir data')
# numPos一般是numNeg的1倍,一般比样本数小
if not os.path.exists('data/cascade.xml'):
print('=' * 30)
cmd_train = 'opencv_traincascade -data data -vec pos.vec -bg neg.txt -numPos 30 -numNeg 15 -numStages 15 -w 20 -h 30'
os.system(cmd_train)
print('=' * 30)
执行完后在当前目录会生成如下:
neg.txt=>其中为负样本的路径
pos.txt=>其中为目标图像在负样本中的坐标
pos.vec=>pos.txt的向量格式
3.测试
测试代码如下:
# 测试 haar分类器
def test_haar_clasifier(cascade_file="data/cascade.xml"):
mouse_haar = cv2.CascadeClassifier(cascade_file)
cam = cv2.VideoCapture(0)
while True:
ret, img = cam.read()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
mouse = mouse_haar.detectMultiScale(gray_img, 1.2, 3) # 调整参数
for mouse_x, mouse_y, mouse_w, mouse_h in mouse:
cv2.rectangle(img, (mouse_x, mouse_y), (mouse_x + mouse_w, mouse_y + mouse_h), (0, 255, 0), 2)
cv2.imshow('img', img)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
cam.release()
cv2.destroyAllWindows()
测试结果如下:
手掌可以检测到,但是效果不好,可以通过增加负类样本改善效果。
完整代码下载