如何遍历充满图像的子目录并分别为每个图像分配功能?

问题描述

我正在研究人脸识别系统。我有一个充满子目录的文件夹,里面有图像。我想遍历子文件夹中的这些图像,并应用face_align函数(已创建),该函数负责人脸裁剪和对齐,并将对齐和裁剪后的图像保存在另一个具有与以前相同架构的文件夹中

例如:如果我有:带有原始原始图片的名为“ Thor”,“ Loki”和“ Odin”的子目录,我想遍历这些子目录并应用face_align函数自动创建另一个名为aligned face的文件夹,相同的子目录“ Thor”,“ Loki”和“ Odin”。但面部对齐且裁剪。

到目前为止,我已经尝试过:

#Now that we have defined the face alignmet and cropping,we walk through each subfolder and use the align function
for root,dirs,files in os.walk('<path to subdirectories that has face pictures>'):
    for fname in files:
        fpath = os.path.join(root,fname)
        with open(fpath,'rb') as f,open('<path to new folder>','w') as newfile:
            data = f.read()
            new_data = align_face(data) #Implementing align_face function 
            newfile.write(new_data)

但这似乎不起作用。它似乎很容易通过align_face函数运行,但是它不会将那些对齐的图像复制到新文件夹中。任何帮助表示赞赏。谢谢。

这是对齐面部功能

def align_face(imagePath):

    image = face_recognition.load_image_file(imagePath)

    face_locations = face_recognition.face_locations(image)

    face_landmarks = face_recognition.face_landmarks(image)

    if len(face_locations) == 0:
        print("Couldn't detect face for pid {} in path {}".format(Id,imagePath))

        return []

    if len(face_locations) > 1:
        return []

    else:
        (top,right,bottom,left) = face_locations[0]

        desiredWidth = (right - left)

        desiredHeight = (bottom - top)

        leftEyePts = face_landmarks[0]['left_eye']

        rightEyePts = face_landmarks[0]['right_eye']

        if len(leftEyePts) == 0 or len(rightEyePts) == 0:

            print("Couldn't detect both eyes for pid {} in path {}".format(Id,imagePath))
            return []


        else:

            leftEyeCenter = np.array(leftEyePts).mean(axis=0).astype("int")

            rightEyeCenter = np.array(rightEyePts).mean(axis=0).astype("int")

            leftEyeCenter = (leftEyeCenter[0],leftEyeCenter[1])

            rightEyeCenter = (rightEyeCenter[0],rightEyeCenter[1])

            dY = rightEyeCenter[1] - leftEyeCenter[1]

            dX = rightEyeCenter[0] - leftEyeCenter[0]
            
            angle = np.degrees(np.arctan2(dY,dX))

            desiredLeftEye=(0.35,0.35)

            desiredFaceWidth = desiredWidth

            desiredFaceHeight = desiredHeight

            desiredRightEyeX = 1.0 - desiredLeftEye[0]

            dist = np.sqrt((dX ** 2) + (dY ** 2))

            desireddist = (desiredRightEyeX - desiredLeftEye[0])
            
            desireddist *= desiredFaceWidth

            scale = desireddist / dist
            
            eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) // 2,(leftEyeCenter[1] + rightEyeCenter[1]) // 2)

            M = cv2.getRotationMatrix2D(eyesCenter,angle,scale)
            
            tX = desiredFaceWidth * 0.5

            tY = desiredFaceHeight * desiredLeftEye[1]

            M[0,2] += (tX - eyesCenter[0])

            M[1,2] += (tY - eyesCenter[1])
            
            (w,h) = (desiredFaceWidth,desiredFaceHeight)

            output = cv2.warpAffine(image,M,(w,h),flags=cv2.INTER_CUBIC)

            output = cv2.cvtColor(output,cv2.COLOR_BGR2RGB)

            print("images aligned")
            
            return output

解决方法

import os
from PIL import Image
import numpy as np

your_dir_path = '...' # String. The path of your directory containing all your subdirectories
new_dir_path = '...' # The path of your new directory with the same architecture as the previous one,but with cropped and aligned faces

for subfolder in next(os.walk(your_dir_path))[1] : # Gives the list of all subdirectories inside the parent directory
  os.makedirs(os.path.join(new_dir_path,subfolder)) # Creates the new subdirectory. Note that it will also create new_dir_path,so there's no need to add a line os.makedirs(new_dir_path)
  for file in os.listdir(os.path.join(your_dir_path,subfolder)) : # Gives the list of all files inside the 'subfolder' directory
    
    img = Image.open(os.path.join(your_dir_path,subfolder,file))
    #img = np.asarray(img) # If your align_face function works with numpy arrays
    new_img = align_face(img)
    #new_img = Image.fromarray(np.uint8(new_img)) # If your align_face function returns a numpy array
    new_img.save(os.path.join(new_dir_path,file)) 

如果文件夹已经存在,os.makedirs(os.path.join(new_dir_path,subfolder))将引发错误。在这种情况下,您可以删除此行(如果您已经创建了new_dir_path文件夹及其所有体系结构),或者在重新创建之前删除了现有文件夹:

from shutil import rmtree # deletes a folder

并将此行插入到先前的代码中:

if os.path.isdir(os.path.join(new_dir_path,subfolder)) :
  rmtree(os.path.join(new_dir_path,subfolder))

os.makedirs(os.path.join(new_dir_path,subfolder))
...
,

您可以尝试使用glob。 在使用glob和正则表达式的情况下,您可以找到所有图像(假设根目录是当前活动目录),遍历它们并将新创建的图像存储在目标文件夹中

import glob,os
from pathlib import Path

destination_dir_path = "bawfaw"
image_paths = glob.glob("*/*/*.jpg") #in case those are jpg images
for image_path in image_paths:
 destination_image_path = Path(os.path.join(destination_dir_path,image_path))
 destination_image_folder = destination_image_path.parent

 if os.path.exists(destination_image_folder) is False:
   destination_image_folder.mkdir(parents=True,exist_ok=True)
 with open(image_path,"rb") as image_file:
  # process the image as you want and store it at destination_image_path

代码未经测试,但我认为它提供了总体思路。