有的时候人脸检测的需求没办法用市面上现成的训练结果,人脸更细致的分类就需要自己手动标记了,但是找到人脸位置自动生成标记文件还是交给电脑做就可以了,只要人工复核一遍就可以了。
主要情况:
- 使用yolov3做这件事
- 分类人脸更细致的情况
- 做PascalVOC格式xml标注数据
- 28W原始数据,手动标注不知道要标到猴年马月
一、过滤完全检测不到人脸的
# -*- coding: utf-8 -*-
import requests
import cv2
import os
import shutil
def get_face_location(file_path ,file_name):
import base64
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=你的AK&client_secret=你的SK'
header={'Content-Type': 'application/json; charset=UTF-8'}
response1=requests.post(url=host,headers=header)#<class 'requests.models.Response'>
json1 = response1.json()#<class 'dict'>
access_token=json1['access_token']
filepath=file_path+file_name
f = open(r'%s' % filepath, 'rb')
pic = base64.b64encode(f.read())
f.close()
base64=str(pic,'utf-8')
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"
params = {"image":base64,"image_type":"BASE64","face_field":"faceshape,facetype,beauty,"}
header={'Content-Type': 'application/json'}
request_url = request_url + "?access_token=" + access_token
response1=requests.post(url=request_url,data=params,headers=header)#<class 'requests.models.Response'>
json1 = response1.json()#<class 'dict'>
# print(json1)
if(json1["error_code"]==222202):
print("Not found face. Move to NoFace floder")
pass
# print(json1["result"]["face_list"][0]["location"])
if(json1["error_code"]==0):
print("Processing image :",file_name)
img = cv2.imread(filepath)
h,w,_ = img.shape
left = int(json1["result"]["face_list"][0]["location"]["left"])
top = int(json1["result"]["face_list"][0]["location"]["top"])
width = int(json1["result"]["face_list"][0]["location"]["width"])
height = int(json1["result"]["face_list"][0]["location"]["height"])
#
if(left<0):
left=0
if(top<0):
top=0
if(left+width>w):
width = w-left
if(top+height>h):
height=h-top
print(left,top,width,height,w,h)
pass
# cv2.rectangle(img,(left,top),(left+width,top+height),(0,255,0),5)
# cv2.imwrite("res.jpg",img)
pre_list = "30001-40000"
lists = ["30001-31000","31001-32000","32001-33000","33001-34000","34001-35000","35001-36000","36001-37000","37001-38000","38001-39000","39001-40000"]
for aaaa in lists:
bbbb = aaaa
path = "/media/nvidia/WD-2T/RawData/"+pre_list+"/"+aaaa+"/"
dirs = os.listdir(path)
pass
lens = len(dirs)
i=1
for file in dirs:
print("["+str(i)+"/"+str(lens)+"]")
get_face_location(path,file)
i=i+1
部分关键逻辑代码由于保密原因已经被我换成pass了,其实就是分拣的处理过程。
这一步会自动检测人脸和非人脸,你拿到他的检测结果以后可以把它分别移动到不同的文件夹下面准备下一步操作
二、自动标注
# -*- coding: utf-8 -*-
import requests
import cv2
import os
import shutil
import sys
def gen(file_path,file_name,write_xml_file_path,label_set):
filepath=file_path+file_name
import base64
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=你的AK&client_secret=你的SK'
header={'Content-Type': 'application/json; charset=UTF-8'}
response1=requests.post(url=host,headers=header)#<class 'requests.models.Response'>
json1 = response1.json()#<class 'dict'>
access_token=json1['access_token']
f = open(r'%s' % filepath, 'rb')
pic = base64.b64encode(f.read())
f.close()
base64=str(pic,'utf-8')
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"
params = {"image":base64,"image_type":"BASE64","face_field":"faceshape,facetype,beauty,"}
header={'Content-Type': 'application/json'}
request_url = request_url + "?access_token=" + access_token
response1=requests.post(url=request_url,data=params,headers=header)#<class 'requests.models.Response'>
json1 = response1.json()#<class 'dict'>
# print(json1)
# if(json1["error_code"]==222202):
# print("Not found face. Move to NoFace floder")
# shutil.move(file_path+file_name, "3/"+file_name)
# # print(json1["result"]["face_list"][0]["location"])
if(json1["error_code"]==0):
print("Processing image :",file_name)
img = cv2.imread(filepath)
h,w,_ = img.shape
left = int(json1["result"]["face_list"][0]["location"]["left"])
top = int(json1["result"]["face_list"][0]["location"]["top"])
width = int(json1["result"]["face_list"][0]["location"]["width"])
height = int(json1["result"]["face_list"][0]["location"]["height"])
#
if(left<0):
left=0
if(top<0):
top=0
if(left+width>w):
width = w-left
if(top+height>h):
height=h-top
print(left,top,width,height,w,h)
res_str = ""
part1 = "<annotation><folder>jiaobaba</folder><filename>"
part2 = "</filename><path>"
part3 = "</path><source><database>Unknown</database></source><size><width>"
part4 = "</width><height>"
part5 = "</height><depth>"
part6 = "</depth></size><segmented>0</segmented>"
t1 = "<object><name>"
t2 = "</name><pose>Unspecified</pose><truncated>1</truncated><difficult>0</difficult><bndbox><xmin>"
t3 = "</xmin><ymin>"
t4 = "</ymin><xmax>"
t5 = "</xmax><ymax>"
t6 = "</ymax></bndbox></object>"
res_str = part1+file_name+part2+file_path+file_name+part3+str(w)+part4+str(h)+part5+str("3")+part6
tmp_v3 = ""
tmp_v3 = tmp_v3 + t1+label_set+t2+str(left)+t3+str(top)+t4+str(left+width)+t5+str(top+height)+t6
res_str = res_str + tmp_v3 + "</annotation>"
every_line_xml_path = write_xml_file_path+file_name.split(".")[0]+".xml"
file_xml = open(every_line_xml_path,'w')
file_xml.write(res_str)
file_xml.close()
pre_list = "20001-30000"
lists = ["20001-21000" ,"21001-22000" ,"22001-23000","23001-24000","24001-25000","25001-26000","26001-27000","27001-28000","28001-29000","29001-30000"]
for aaaas in lists:
aaaa = "/media/nvidia/WD-2T/RawData/"+pre_list+"/"+aaaas+"/"
floder_path = aaaa+"normal"+"/"
write_xml_file_path = floder_path
dirs = os.listdir(floder_path)
lens = len(dirs)
i = 1
for file in dirs:
print("["+str(i)+"/"+str(lens)+"]")
gen(floder_path,file,floder_path,"normal_label")
i = i + 1
print("done.")
其中有几点需要注意:
- 用到的接口还是上面那个,他会返回人脸坐标的位置,x,y,w,h,但是是那种溢出图片尺寸的坐标,需要手动修正到图片范围内
- xml标注文件的本质就是一个字符串,只不过是里面的内容需要换成变量的形式
- 我们仿照xml标注的内容把我们自己的值给换进去然后写出来就行了
- 上一步分文件夹的原因就是到这一步的时候会把一个文件夹内的图片label都给写死,减少因为标记错误需要修改的文件数量
- 最后使用labelimg复查一遍就可以了
补充:
- labelimg有些东西其实不是特别方便,比如更改标签的快捷键是Ctrl+E,比如预定义的类别
- 快捷键可以直接在源码里面改,我直接改成了E,方便的不得了
- 预定义类别全删了,改成自己的爽歪歪
- 哦,我说的是Ubuntu下面的labelimg,Windows的好像被打包成exe了改不了
三、最后
百度这个接口需要到百度云计算里面创建应用的,这样你就有了AK和SK,就是一串随机码了。
目前单线程和双线程是免费的,但是不知道为啥双线程我用的时候有问题~
免费的哎,就算是收费的也不贵,人像分割那个接口简直白菜价
百度打钱!