人脸数据清洗方法+代码汇总

  • 说明:

        这里对目前为止接触到的人脸数据集的清洗进行一个汇总。
        此文中把人脸数据集分为三种类型(本分类仅在此文中有效):
1.   野数据集
       这里的野数据集指的是从互联网上爬取出的原始人脸数据集,它的特点是:脏、乱、杂 。数据分布不均匀、尺寸不一、存在年龄跨度较大现象,图像格式命名错误且存在较多的冗余、杂质,但优点是类别数目大。使用前需要做深度清洗的工作。
       野数据集诸如目前收集的:Chinese-Face, Japanese-Face, Korean-Face数据集。
2.  常用开源数据集
       这里的常用开源数据集指的是业内公开常用的数据集,这种数据集由于其尺寸统一和pose较全的特点,可以直接作为训练集或者测试集来使用,但也存在较少的杂质与冗余人脸图像,需要做中度清洗。常用开源数据集有:CASIAWeb-Face, VGG2, MS1M, Asian-celeb等数据集。
3. 二次清洗数据集
      这里是指在常用开源数据集的基础上又进行了一次处理。主要是为了保证开源数据集的多样性与类别均衡性。但此类数据集仍然存在小部分的异类人脸图像以及类别分布不均的情况,需要稍作冗余与异类清洗即可。
      二次清洗数据集有:DeepGlint的两个数据集train-celebrity和train-msra。

        清洗原因

        数据清洗是数据准备的第一步,数据准备是人脸识别模型训练的首要步骤,也是给卷积神经网络提供比较干净的人脸图像数据进行学习并训练以便得到可用的、符合特定应用场景的、识别精度较高的人脸识别模型。
       由于爬取得到的人脸数据图像中都会存在噪声图像与无关图像,无论前期从互联网上爬取时工作做的如何疏而不漏,都不能保证最终获取的人脸数据一定符合训练的要求,而掺杂的‘脏’数据往往是影响人脸识别模型训练最终结果的关键。这就需要人工在得到原始数据后对数据完成清洗、增广、提高数据质量等工作。但随着数据量的增加,人工无法满足当下数据清洗的工作提供给后续的开发人员,为了节省时间和提高处理精度,于是编写了清洗工具便于更高效的处理。以下是对清洗过程的介绍。

        清洗思路:

      主要是通过人脸检测和识别算法检测并清洗同一个类别下的人脸照片中掺杂的噪声图像与无关图像,并在同一类别下的人脸图像中计算两两之间的人脸特征余弦距离,再根据余弦距离求其相似度去除冗余图像,即筛掉异类与冗余,同时保证数据的均衡性与多样性。

     各类数据集清洗方法介绍:

     在做人脸数据清洗之前需要对将要清洗的数据集进行评估,根据评估结果了解该数据集。包括其数据分布可视化以及数据质量评估两个步骤。根据数据分布可视化可以了解数据的分布情况,便于设置数据均衡阈值。根据数据质量评估结果,便于设置人脸质量清洗阈值。

      数据分布可视化采用Matplotlib来实现,在可视化之前,需要得到数据类别数目以及人脸图像数据量的csv文件,可以使用shell得到csv文件。

      csv文件生成代码:

#!/bin/bash
find ./ -type d |while read line
do
pwd=${PWD}
cd $line
echo -e "${line#*/},`ls | wc -l`"
cd $pwd
done

     数据分布可视化python代码:

asian_log = pd.read_csv("list2.csv")
plt.figure()
ax = plt.subplot(2,2,1)
ax.set_title("Distribution Curve")
Num = range(len(asian_log['name']))
ax.scatter(Num,asian_log['count'])
ax.set_xlabel('class')
ax.set_ylabel('class count')
#plt.legend(loc='upper left')
plt.legend(loc='upper right')
plt.show()

     野数据集的清洗方法:

    >>   针对于该类数据集建立便于处理的数据分布形式。 如下图所示,箭头表示包含关系,数据集下包含类别文件夹,每个类别下包括该类别的人脸图像。

                                                                                                         

 

整理函数如下:

def fileset(path):
    if os.path.isdir(path):
    lists = os.listdir(path)
    #print(lists)
    for i in lists:
        #print(i)
        path = path + '/' + i
        if os.path.isfile(image_path):
            save_name = image_path.split('/')[7]
            save_path = image_file_dir + '/' + save_name
            print(image_path)
            #print(image_path == save_path)
            save_image = save_path + '/' + i
            print(save_image)
            if image_path != save_image :
                shutil.move(image_path, save_path)
            if image_path == save_image:
                print('This image already exists!')

>>   删除空文件夹以及将图像信息为空的进行删除

def delete_empty_dir(path):
    if os.path.isdir(path):
    lists = os.listdir(path)
    for item in lists:
       if item!='System Volume Information':
           delete_empty_dir(os.path.join(path, item))
       if not os.listdir(path):
           os.rmdir(path)
           print('移除空目录:' + path)
def delete_empty_image(path):
    if os.path.isdir(path):
        lists1 = os.listdir(path)
        for i in lists1:
            image_path = path + '/' + i
            print(image_path)
            save_name = image_path.split('/')[7]
            print(save_name)
            save_path = image_file_dir + '/' + save_name + '/'
            #print(save_path)
            if os.path.isdir(image_path):
                lists2 = os.listdir(image_path)
                L1 = len(lists2)
                print(L1)
                for j in range(L1):
                    print(j)
                    img_name = lists2[j]
                    print(img_name)
                    with open(save_path + '{}'.format(str(img_name)),'rb') as fp:
                        data = fp.read()
                    if(len(data) != 0):
                        pass
                    else:
                        os.remove(save_path + '{}'.format(str(img_name)))

>>   图片格式校验,是将非法命名格式的图像进行纠正。

def format_convert(path):
    if os.path.isdir(path):
       file_lists = os.listdir(path)
       print('file_lists:',file_lists)
       for i in file_lists:
           print('i:',i)
           image_path = path + '/' + i
           print('file_path:',image_path)
           if os.path.isdir(image_path):
              print('pass')
                  pass
           elif os.path.isfile(image_path):
               print('Judging image format type:')
               true_type = imghdr.what(image_path)
               print(true_type,image_path)
               image_type = image_path.split('.')[1]
               image_name = image_path.split('.')[0]
               print('image_type:',image_type)
               if image_type == true_type:
                   print('The image format type is right!\n',image_path)
                   pass
               elif true_type == None:
                   print('This is not a image!\n','Delete:',image_path)
                   os.remove(image_path)
               else:
                   print('The image format type is wrong!\n','Do:')
                   old_image_name = image_path
                   new_image_name = image_name + '.' + true_type
                   newName = image_path.replace(old_image_name,new_image_name)
                   print(image_path,'---->',newName)
                   os.rename(os.path.join(i, image_path),os.path.join(i,newName))
                   print('Done.')

 

 数量均衡化处理

说明:
    清洗工作基于caffe平台使用了人脸检测模型MTCNN以及a、b、c三种人脸识别模型,人脸识别模型的选取可以根据训练或测试所使用的图像尺寸大小来选择。
    a) caffe face          图像尺寸为:112*96
    b) face net             图像尺寸为:160*160
    c) insight face       图像尺寸为:112*112


 以上步骤主要针对于野数据集清洗的第一步,下面是所有类型的数据集需要操作的步骤。

>>   删除异类人脸图像,洗掉脏数据:

def List_ordering(distances,class_face_num):
    ordering_lists=[]
    k=range(len(distances))
    for i in k:
        if distances[i][0]<0.5:
        ordering_lists+=[distances[i]]
    return ordering_lists

if __name__ == "__main__":
    # face_model = './facenet_model/myfacenet.prototxt' ####160*160    ###几个人脸识别模型的切换
    # face_weights = './facenet_model/myfacenet.caffemodel'
    # face_model = './caffe_caffemodel/face_deploy.prototxt'###112*96
    # face_weights = './caffe_caffemodel/face_model.caffemodel'
    face_model = './insight_caffemodel/model.prototxt' ###112*112
    face_weights = './insight_caffemodel/face_model.caffemodel'
    net = caffe.Net(face_model, face_weights, caffe.TEST)
    transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
    transformer.set_transpose('data', (2, 0, 1))
    file_lists = os.listdir(image_file_dir)
    class_num_lists = []
    for dir in file_lists:
        path = image_file_dir + '/' + dir
        class_face_num, faces_lists, image_name_lists, names_lists, image_files_lists,class_features_lists=Get_faces(path,net)
        print('image_name_lists:', image_name_lists)
        distances=Distance_calculation(class_features_lists)
        orig_mean_num = pd.DataFrame(columns=None, data=distances)
        orig_mean_num.to_csv(path_or_buf=path + '/orig_test10.csv', encoding='gbk')
        # print('len(distances:)',len(distances))
        ordering_lists=List_ordering(distances,class_face_num)
        # print('ordering_lists:', ordering_lists)
        mean_num = pd.DataFrame(columns=None, data=ordering_lists)
        mean_num.to_csv(path_or_buf=path + '/test10.csv', encoding='gbk')

>>   保证数据均衡性,这里有两种数据均衡的方法:

  1.  先设置图像数量阈值进行数据划分,再裁出满足人脸质量阈值的人脸。
  2.  直接使用人脸检测算法和人脸识别算法并设置均衡阈值,得到最终均衡后的人脸数据集。

第一种方法比较容易处理,方便调试,但操作流程较为麻烦,第二种方法速度太慢,但流程简单,是直接出结果。

第一种方法介绍:

>>   按图像数量阈值进行数据划分:

if DB_FLAG == 'Celebrity':
   file_lists=os.listdir(image_file_dir)
   class_num_lists = []
   total_class_num=len(file_lists)
   for dir in file_lists:
       path=image_file_dir+'/'+dir
       class_count+=1
       progress = (class_count / total_class_num) * 100
       print('This DS has been processed by %.2f%%' % progress)
       class_face_num,faces_lists,image_name_lists,names_lists,image_files_lists=Get_faces(path)
       print('class_face_num1:', class_face_num)
       print('class_count:', class_count)
       #print('faces_lists:',faces_lists)
       class_num_lists += [class_face_num]
       if class_face_num >= 10:  ##设置图像数量阈值进行选取类别,并另存为
          print('Save this file directly!')
          for i in range(class_face_num):
              image_file_path = image_files_lists[i]
              name = image_file_path.split('/')[8]
              names = image_file_path.split('/')[9]
              save_to_file = './celebrity10++_aligned_112*112/' + name + '/'  ##新建文件夹将选取出的类别图像得以保存
              print(save_to_file)
              mkdir(save_to_file)
              # for j in range(len(faces_lists)):
              cv2.imwrite(save_to_file + '%s' % names, faces_lists[i])
          del i
       elif class_face_num==0:
           print('This file has no faces!')
       else:
           pass
   #print('class_num_lists:', class_num_lists)
   del dir,total_class_num,file_lists

>>   设置人脸图像质量阈值和图像尺寸,裁出符合条件的人脸

def generate_celebrity_db_aligned():
    mtcnn_model_path = "./mtcnn/model"
    detect_threshhold = 0.90
    quality = 0
    multi_faces = False
    caffe.set_mode_gpu()
    image_files = []
    names = []
    image_files, names = utility.get_imagefiles_from_dir(db_image_file_dir,True)
    print(len(image_files))
    print(image_files[0:10])
    facedetector = utility.initFaceDetector(mtcnn_model_path)
    minsize = facedetector[0]
    PNet = facedetector[1]
    RNet = facedetector[2]
    ONet = facedetector[3]
    threshold = facedetector[4]
    factor = facedetector[5]
    faces = []
    for j in range(len(image_files)):
    im_file = image_files[j]
    im = cv2.imread(im_file)
    faces = utility.crop_and_align(im, minsize, PNet, RNet, ONet, threshold, factor, detect_threshhold, quality, multi_faces) 
    if len(faces) == 1:
        save_to_file = './db_aligned_test/' + names[j] + '/'
        utility.mkdir(save_to_file)
        save_branch2 = im_file.split('_')[1]
        cv2.imwrite(save_to_file + names[j] + save_branch2, faces[0])
    elif len(faces) == 0:
        print('cannot found face in file %s' % im_file)
    elif len(faces) > 1:
        print('too many faces in file %s' % im_file)
    if j % 50 == 0:
        print('processed %d pics' % j)

第二种方法介绍:

>>   直接输出处理结果

if DB_FLAG == 'Celebrity':
   file_lists=os.listdir(image_file_dir)
   class_num_lists = []
   total_class_num=len(file_lists)
   for dir in file_lists:
       path=image_file_dir+'/'+dir
       class_count+=1
       progress = (class_count / total_class_num) * 100
       print('This DS has been processed by %.2f%%' % progress)
       class_face_num,faces_lists,image_name_lists,names_lists,image_files_lists=Get_faces(path)
       print('class_face_num1:', class_face_num)
       print('class_count:', class_count)
       #print('faces_lists:',faces_lists)
       class_num_lists += [class_face_num]
       if class_face_num >= 10:
           pass
       elif class_face_num ==0:
           print('This file has no faces!')
       elif class_face_num < 10:
           print('Save this file directly!')
           print('class_face_num:',class_face_num)
           for i in range(class_face_num):
           # print('####################################################################')
           image_file_path = image_files_lists[i]
           name = image_file_path.split('/')[8]
           names = image_file_path.split('/')[9]
           save_to_file = './celebrity_val_aligned_112*112/' + name + '/'
           print('save_to_file:',save_to_file)
           mkdir(save_to_file)
           # for j in range(len(faces_lists)):
           cv2.imwrite(save_to_file + '%s' % names, faces_lists[i])
           # del i
           save_class_count1+=1
           print('save_class_count1:',save_class_count1)
       if save_class_count1==7500:
           print('full!')
           break
           # print('class_num_lists:', class_num_lists)
   del dir,total_class_num,file_lists

 

保证数据多样性

如果不单为了保证数据的均衡性,还保留其数据的多样性,那么还需做以下操作:

注:保留其多样性的代码只完成了一部分,思路连同代码一并给出。

思路: 利用神经网络的全连接层FC输出得到的人脸特征feature,通过计算单个类别下的人脸图像两两之间的余弦距离,在保证相同类别的前提下判断其距离大小,距离越大,认为其人脸差异性越大,距离越小,则相反,此种方法不仅可以保留其数据的多样性,同时还过滤掉了冗余的图像,且方法得以验证。

余弦距离计算的代码实现:

def dist(a,b):
    score = np.dot(a,b)/(np.linalg.norm(a)*np.linalg.norm(b))
    distance = 1 - score
    return distance

人脸特征提取的代码实现:

def extract_feature_512(net,transformer,img):
     # img read from cv2.imread
     img = (img - 127.5) / 128
     net.blobs['data'].data[...] = transformer.preprocess('data',img) #将图片载入到blob中
     net.forward()
     feature = np.float64(net.blobs['fc5'].data[0])
     return feature

同一类别下,计算两两距离的代码实现:

def Distance_calculation(class_features_lists):
    distances=[]
    k = range(len(class_features_lists))
    for i in k:
        # print('i:',i)
        K = range(i + 1, len(class_features_lists))
        for j in K:
        # print('j:',j)
        distance=dist(class_features_lists[i],class_features_lists[j])
        # print('distance:',distance)
        if distance:
            distances += [[distance,[i,j]]]
    orig_mean_num = pd.DataFrame(columns=None, data=distances)
    orig_mean_num.to_csv('./orig_test10.csv', encoding='gbk')
    return distances
  • 6
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
yolov5人脸口罩识别代码是一种用于检测人脸和口罩的计算机视觉模型。该模型基于PyTorch框架实现,主要由Python编写。它使用了最新的目标检测算法,能够快速准确地识别图像中的人脸,并判断是否佩戴口罩。 该代码的主要实现步骤包括数据准备、模型构建、训练和测试。首先需要准备包含带有人脸和口罩的图像数据集,然后通过数据预处理和数据增强方式对图像进行处理,以便更好地适应模型的训练需求。接下来,通过yolov5的模型结构和参数设置,构建用于目标检测的神经网络模型。然后将准备好的数据输入到模型中,进行训练和优化,以提高模型的准确性和鲁棒性。最后,通过将训练好的模型应用于新的图像数据集,进行测试和评估模型的性能。 该代码的核心部分是yolov5模型的网络结构和损失函数的设计,其中包括主干网络、特征提取层、检测层等。此外,代码还包括了模型的训练和测试过程的实现,包括数据加载、模型优化、评估指标的计算等。通过运行该代码,可以实现对图像中人脸和口罩的快速准确识别,为口罩检测等场景提供了一种有效的解决方案。 总的来说,yolov5人脸口罩识别代码是一种基于最新目标检测算法的实现,它通过PyTorch框架提供了一个高效准确的人脸口罩检测模型,为相关应用领域提供了有力的支持。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值