此代码目的为调用百度的人体属性检测api进行数据集预标注。并将调用所获得的相关信息保存到xml文件。具体步骤如下:
1.下载并安装相关人体分析python sdk。
网址为:https://cloud.baidu.com/doc/BODY/s/djwvxz1ju
2.获取相关许可证秘钥
找度娘,定位到百度ai中的此页面,然后点击创建相关应用,获取你自己的AppID、API Key、以及Secret Key(下面要用)。
3.调用百度人体分析python api进行数据预标注。
(1) 本人由于只需要相关的人体检测框,若需要其他属性,可参考百度相关api输出说明文档。具体网址为见这里
(2)将下面代码保存为BodyAtt.py,并放到已经安装好的sdk主目录下(和setup.py同级目录),运行即可。调用方式为:
python BodyAtt.py --ImgDir ./TestDir/ --DirWeSave ./DirWeSave/
TestDir :是你要处理的图片所在文件夹,
DirWeSave:是你要保存结果的文件夹
# coding=UTF-8
# 利用baidu-aip库进行人脸识别
from aip import AipFace
from aip import AipBodyAnalysis
import shutil
import cv2
import os
import base64
from lxml.etree import Element, SubElement, tostring
from xml.dom.minidom import parseString
import pprint
import xml.etree.ElementTree as ET
import argparse
import csv
from xml.etree import ElementTree
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import fromstring, ElementTree
# 获取相关许可证信息。如何获取百度相关许可证信息,请自己找度娘
APP_ID = '******'
API_KEY = '***************'
SECRET_KEY = '*************************'
client = AipBodyAnalysis(APP_ID, API_KEY, SECRET_KEY)
# 百度人脸手续检测参数设置
options = {}
options["type"] = "age,gender,location,upper_wear,lower_wear,upper_color,lower_color,upper_wear_texture,bag,upper_wear_fg,headwear,glasses,umbrella,cellphone,orientation,occlusion,is_human"
def GetImgNameByEveryDir(file_dir):
# Input Root Dir and get all img in per Dir.
# Out Every img with its filename and its dir and its path
FileNameWithPath = []
FileName = []
FileDir = []
videoProperty=['.jpg']
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] in videoProperty:
FileNameWithPath.append(os.path.join(root, file)) # 保存图片路径
FileName.append(file) # 保存图片名称
FileDir.append(root[len(file_dir):]) # 保存图片所在文件夹
return FileName,FileNameWithPath,FileDir
def SavePropertyToXml(result,ImgName,Imgpath,ImgDirName,ImgWidth,ImgHeight,ImgChannel,xml_name_new):
node_root = Element('annotation')
# 图片文件夹
node_folder = SubElement(node_root, 'folder')
node_folder.text = ImgDirName
# 图片Name
node_filename = SubElement(node_root, 'filename')
node_filename.text = ImgName
# 图片路径
node_path = SubElement(node_root, 'path')
node_path.text = Imgpath[1:]
# 图片中人脸个数
node_object_num = SubElement(node_root, 'person_num')
node_object_num.text = str(result['person_num'])
# 图片信息(宽、高、通道数)
node_size = SubElement(node_root, 'size')
node_width = SubElement(node_size, 'width')
node_width.text = str(ImgWidth)
node_height = SubElement(node_size, 'height')
node_height.text = str(ImgHeight)
node_depth = SubElement(node_size, 'depth')
node_depth.text = str(ImgChannel)
# 下面循环保存图片中每个人脸的相关属性
for h in range(result['person_num']):
# 人脸属性名称
node_object = SubElement(node_root, 'object')
node_name = SubElement(node_object, 'name')
node_name.text = 'person'
# pose说明
node_pose = SubElement(node_object, 'pose')
node_pose.text = 'Unspecified'
# truncated
node_truncated = SubElement(node_object, 'truncated')
node_truncated.text = '0'
# difficult
node_difficult = SubElement(node_object, 'difficult')
node_difficult.text = '0'
# 百度人脸属性-face_probability属性
node_face_probability = SubElement(node_object, 'is_human')
node_face_probability.text = str(result['person_info'][h]['attributes']['is_human']['score'])
# 将矩形框转换为VOC数据集的形式
xmin = result['person_info'][h]['location']['left']
ymin = result['person_info'][h]['location']['top']
xmax = xmin + result['person_info'][h]['location']['width']
ymax = ymin + result['person_info'][h]['location']['height']
# 百度人脸属性-location属性
node_bndbox = SubElement(node_object, 'bndbox')
node_xmin = SubElement(node_bndbox, 'xmin')
node_xmin.text = str(xmin)
node_ymin = SubElement(node_bndbox, 'ymin')
node_ymin.text = str(ymin)
node_xmax = SubElement(node_bndbox, 'xmax')
node_xmax.text = str(xmax)
node_ymax = SubElement(node_bndbox, 'ymax')
node_ymax.text = str(ymax)
node_rotation = SubElement(node_bndbox, 'score')
node_rotation.text = str(result['person_info'][h]['location']['score'])
# 此前使用此代码有进行人脸属性数据预标注,当然也可仿照下面方法完善行人属性预标注。这里只输出目标框坐标等信息
# # 百度人脸属性-angle属性
# node_angle = SubElement(node_object, 'angle')
# node_yaw = SubElement(node_angle, 'yaw')
# node_yaw.text = str(result['result']['face_list'][h]['angle']['yaw'])
# node_pitch = SubElement(node_angle, 'pitch')
# node_pitch.text = str(result['result']['face_list'][h]['angle']['pitch'])
# node_roll = SubElement(node_angle, 'roll')
# node_roll.text = str(result['result']['face_list'][h]['angle']['roll'])
# # 百度人脸属性-face_type属性
# node_face_type = SubElement(node_object, 'face_type')
# node_type = SubElement(node_face_type, 'type')
# node_type.text = result['result']['face_list'][h]['face_type']['type']
# node_probability = SubElement(node_face_type, 'probability')
# node_probability.text = str(result['result']['face_list'][h]['face_type']['probability'])
# # 百度人脸属性-beauty属性
# node_beauty = SubElement(node_object, 'beauty')
# node_beauty.text = str(result['result']['face_list'][h]['beauty'])
# # 百度人脸属性-age属性
# node_age = SubElement(node_object, 'age')
# node_age.text = str(result['result']['face_list'][h]['age'])
# # 百度人脸属性-expression属性
# node_expression = SubElement(node_object, 'expression')
# node_expression_type = SubElement(node_expression, 'type')
# node_expression_type.text = result['result']['face_list'][h]['expression']['type']
# node_expression_prob = SubElement(node_expression, 'probability')
# node_expression_prob.text = str(result['result']['face_list'][h]['expression']['probability'])
# # 百度人脸属性-gender属性
# node_gender = SubElement(node_object, 'gender')
# node_gender_type = SubElement(node_gender, 'type')
# node_gender_type.text = result['result']['face_list'][h]['gender']['type']
# node_gender_prob = SubElement(node_gender, 'probability')
# node_gender_prob.text = str(result['result']['face_list'][h]['gender']['probability'])
# # 百度人脸属性-glasses属性
# node_glasses = SubElement(node_object, 'glasses')
# node_glasses_type = SubElement(node_glasses, 'type')
# node_glasses_type.text = result['result']['face_list'][h]['glasses']['type']
# node_glasses_prob = SubElement(node_glasses, 'probability')
# node_glasses_prob.text = str(result['result']['face_list'][h]['glasses']['probability'])
# # 百度人脸属性-emotion属性
# node_emotion = SubElement(node_object, 'emotion')
# node_emotion_type = SubElement(node_emotion, 'type')
# node_emotion_type.text = result['result']['face_list'][h]['emotion']['type']
# node_emotion_prob = SubElement(node_emotion, 'probability')
# node_emotion_prob.text = str(result['result']['face_list'][h]['emotion']['probability'])
# # 百度人脸属性-race属性
# node_race = SubElement(node_object, 'race')
# node_race_type = SubElement(node_race, 'type')
# node_race_type.text = result['result']['face_list'][h]['race']['type']
# node_race_prob = SubElement(node_race, 'probability')
# node_race_prob.text = str(result['result']['face_list'][h]['race']['probability'])
# # 百度人脸属性-eye_status属性
# node_eye_status = SubElement(node_object, 'eye_status')
# node_left_eye = SubElement(node_eye_status, 'left_eye')
# node_left_eye.text = str(result['result']['face_list'][h]['eye_status']['left_eye'])
# node_right_eye = SubElement(node_eye_status, 'right_eye')
# node_right_eye.text = str(result['result']['face_list'][h]['eye_status']['right_eye'])
# # 百度人脸属性-landmark属性
# node_landmark = SubElement(node_object, 'landmark')
# for kk in range(len(result['result']['face_list'][h]['landmark'])):
# node_landmark_x = SubElement(node_landmark,'x')
# node_landmark_x.text = str(result['result']['face_list'][h]['landmark'][kk]['x'])
# node_landmark_y = SubElement(node_landmark,'y')
# node_landmark_y.text = str(result['result']['face_list'][h]['landmark'][kk]['y'])
# # 百度人脸属性-landmark150属性
# node_landmark_150 = SubElement(node_object, 'landmark150')
# landmark150 = result['result']['face_list'][h]['landmark150']
# for key in landmark150:
# node_landmark_150_key = SubElement(node_landmark_150, key)
# node_landmark_150_key_x = SubElement(node_landmark_150_key, 'x')
# node_landmark_150_key_x.text = str(landmark150[key]['x'])
# node_landmark_150_key_y = SubElement(node_landmark_150_key, 'y')
# node_landmark_150_key_y.text = str(landmark150[key]['y'])
# # 百度人脸属性-quality属性
# node_quality = SubElement(node_object, 'quality')
# # 百度人脸属性-quality属性——blur
# node_quality_blur = SubElement(node_quality, 'blur')
# node_quality_blur.text = str(result['result']['face_list'][h]['quality']['blur'])
# # 百度人脸属性-quality属性——illumination
# node_quality_illumination = SubElement(node_quality, 'illumination')
# node_quality_illumination.text = str(result['result']['face_list'][h]['quality']['illumination'])
# # 百度人脸属性-quality属性——completeness
# node_quality_completeness = SubElement(node_quality, 'completeness')
# node_quality_completeness.text = str(result['result']['face_list'][h]['quality']['completeness'])
# # 百度人脸属性-quality属性——occlusion
# node_quality_occlusion = SubElement(node_quality, 'occlusion')
# # 百度人脸属性-quality属性——occlusion:eye
# node_quality_occlusion_left_eye = SubElement(node_quality_occlusion, 'left_eye')
# node_quality_occlusion_left_eye.text = str(result['result']['face_list'][h]['quality']['occlusion']['left_eye'])
# node_quality_occlusion_right_eye = SubElement(node_quality_occlusion, 'right_eye')
# node_quality_occlusion_right_eye.text = str(result['result']['face_list'][h]['quality']['occlusion']['right_eye'])
# # 百度人脸属性-quality属性——occlusion:nose
# node_quality_occlusion_nose = SubElement(node_quality_occlusion, 'nose')
# node_quality_occlusion_nose.text = str(result['result']['face_list'][h]['quality']['occlusion']['nose'])
# # 百度人脸属性-quality属性——occlusion:mouth
# node_quality_occlusion_mouth = SubElement(node_quality_occlusion, 'mouth')
# node_quality_occlusion_mouth.text = str(result['result']['face_list'][h]['quality']['occlusion']['mouth'])
# # 百度人脸属性-quality属性——occlusion:cheek
# node_quality_occlusion_left_cheek = SubElement(node_quality_occlusion, 'left_cheek')
# node_quality_occlusion_left_cheek.text = str(result['result']['face_list'][h]['quality']['occlusion']['left_cheek'])
# ode_quality_occlusion_right_cheek = SubElement(node_quality_occlusion, 'right_cheek')
# ode_quality_occlusion_right_cheek.text = str(result['result']['face_list'][h]['quality']['occlusion']['right_cheek'])
xml = tostring(node_root, pretty_print = True)
dom = parseString(xml)
print(dom)
# f = open(xml_name_new,'w')
# dom.writexml(f,indent='',addindent='\t',newl='\n',encoding='utf-8')
return dom
def ShowResult(result,ImagePath,ImgSAVEdir,ImageName):
Image = cv2.imread(ImagePath)
for h in range(result['person_num']):
# 将矩形框转换为VOC数据集的形式
xmin = result['person_info'][h]['location']['left']
ymin = result['person_info'][h]['location']['top']
xmax = xmin + result['person_info'][h]['location']['width']
ymax = ymin + result['person_info'][h]['location']['height']
# print(type(xmin),type(ymin),type(xmax),type(ymax))
cv2.rectangle(Image,(int(xmin),int(ymin)),(int(xmax),int(ymax)),(255,0,0),3)
# cv2.putText(Img, str(h), (int(xmin),int(ymin)),2, (0,255,0), 1)
print(xmin)
cv2.imshow("result",Image)
cv2.waitKey(50)
# saveFile = ImgSAVEdir + ImageName
# cv2.imwrite(saveFile,Image)
def prettyXml(element, indent, newline, level = 0):
if element: # 判断element是否有子元素
if element.text == None or element.text.isspace(): # 如果element的text没有内容
element.text = newline + indent * (level + 1)
else:
element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1)
#else: # 此处两行如果把注释去掉,Element的text也会另起一行
#element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
temp = list(element) # 将elemnt转成list
for subelement in temp:
if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
subelement.tail = newline + indent * (level + 1)
else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
subelement.tail = newline + indent * level
prettyXml(subelement, indent, newline, level = level + 1) # 对子元素进行递归操作
return element
def Process(DirPathRoot,Dir_WeWantToSave):
# 获取图片所在文件夹名和图片文件名和图片路径
# DirPathRoot = '../WIDER_test/Images/'
FileName,FileNameWithPath,FileDir = GetImgNameByEveryDir(DirPathRoot)
# 开始批量处理每个图片
# Dir_WeWantToSave = '../../WiderFaceDataset_ylc/'
for k in range(len(FileDir)):
'''--------------------------------------------------------------------------------
获取图片相关属性
--------------------------------------------------------------------------------'''
ImagePath = FileNameWithPath[k]
Image = cv2.imread(ImagePath)
Image_Property = Image.shape
ImgHeight = Image_Property[0]
ImgWidth = Image_Property[1]
ImgChannel = Image_Property[2]
'''--------------------------------------------------------------------------------
创建保存数据的相关文件夹
--------------------------------------------------------------------------------'''
ImgDir = FileDir[k]
WhereWeSave = Dir_WeWantToSave + ImgDir
if not os.path.exists(WhereWeSave):
os.makedirs(WhereWeSave)
with open(ImagePath,"rb") as f:
image = f.read()
'''
人体属性分析,若需要关键点分析,可用client.bodyAnalysis函数进行处理,
若想进行人流量统计,可食用client.bodyNum函数进行分析等等。然后对
输出的字典按自己需求选取相应数值即可。具体网址为:http://ai.baidu.com/docs#/BodyAnalysis-Python-SDK/top
'''
result = client.bodyAttr(image,options);
print("result = ",result)
# print("ImagePath = ",ImagePath)
if 'person_info' in result and result['person_info'] != None:
ShowResult(result,ImagePath,WhereWeSave,FileName[k])
'''--------------------------------------------------------------------------------
在目标保存文件夹内创建和原始处理文件夹同名的文件夹,并复制里面的图片的img文件夹中,
将处理得到的xml文件放入到与img同级的annotation文件中创建保存xml的文件夹
--------------------------------------------------------------------------------'''
# 创建保存xml的文件夹以及保存的文件名
xml_save_dir = WhereWeSave + '/' + 'annotation'
if not os.path.exists(xml_save_dir):
os.makedirs(xml_save_dir)
xml_name_new = xml_save_dir + "/" + FileName[k][:-4] + ".xml"
# 创建原始图片的复制文件所在文件夹
img_save_dir = WhereWeSave + '/' + 'img'
if not os.path.exists(img_save_dir):
os.makedirs(img_save_dir)
img_new_save_name_with_path = img_save_dir + '/' + FileName[k]
if os.path.exists(img_new_save_name_with_path) == False:
shutil.copyfile(ImagePath,img_new_save_name_with_path)
# 获取人脸属性的xml数据并保存
dom = SavePropertyToXml(result,FileName[k],FileNameWithPath[k],FileDir[k],ImgWidth,ImgHeight,ImgChannel,xml_name_new)
f = open(xml_name_new,'w')
dom.writexml(f,indent = '\t',newl = '\n', addindent = '\t',encoding='utf-8')
f.close()
#上面方法保存的xml中间可能会有空白行,但不影响使用。也可以执行下面语句进行美化
from xml.etree import ElementTree
tree = ElementTree.parse(xml_name_new) # 解析test.xml这个文件,该文件内容如上文
root = tree.getroot() # 得到根元素,Element类
root = prettyXml(root, '\t', '\n') # 执行美化方法
ElementTree.dump(root) # 打印美化后的结果(可以不显示)
tree = ET.ElementTree(root) # 转换为可保存的结构
tree.write(xml_name_new) # 保存美化后的结果
if __name__=='__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--ImgDir',type=str, default='./TestDir/')
parser.add_argument('--DirWeSave',type=str, default='./DirWeSave/')
args = parser.parse_args()
Process(args.ImgDir,args.DirWeSave)
# 代码调用方式:
# python BodyAtt.py --ImgDir ./TestDir/ --DirWeSave ./DirWeSave/