[PYTHON] Let's cut the face from the image

Overview

I made a program that detects faces using Haar-Like feature Cascade provided by OpenCV and automatically cuts them.

environment

-Software- Windows 10 Home Anaconda3 64-bit(Python3.7) Spyder -Library- opencv-python 4.1.2.30 natsort 7.0.0 -Hardware- CPU: Intel core i9 9900K RAM: 16GB 3200MHz

reference

** Books ** OpenCV4 programming starting with Python Naohiro Kitayama (Author) ([Amazon Page](https://www.amazon.co.jp/Python%E3%81%A7%E5%A7%8B%E3%82%81%E3%82%8BOpenCV-4%E3%83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-% E5% 8C% 97% E5% B1% B1 -% E7% 9B% B4% E6% B4% 8B / dp / 4877834613))

program

I will post it on Github.

https://github.com/himazin331/Face-Cropping The repository contains the data processing program Haar-Cascade

Premise

A Cascade file with Haar-Like features is required for the operation of this program. This time I will use Haar-Cascade of OpenCV. Cascade is included in the repository, so you don't need to prepare it separately.

Source code

** Please note that the code is dirty ... **

face_cut.py


import cv2
import os
import argparse as arg
import sys
from natsort import natsorted

#Image processing
def face_cut(imgs_dir, result_out, img_size, label, HAAR_FILE):
    
    # Haar-Like Feature Cascade classifier reading
    cascade = cv2.CascadeClassifier(HAAR_FILE)
    
    #Data processing
    for img_name in natsorted(os.listdir(imgs_dir)):

        print("image data:{}".format(img_name))
        
        #jpg format only
        _, ext = os.path.splitext(img_name)
        if ext.lower() == '.jpg':
            
            img_path = os.path.join(imgs_dir, img_name) #Combine file paths
            img = cv2.imread(img_path)  #Data read
            
            img_g = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) #Convert to grayscale
            face = cascade.detectMultiScale(img_g)  #Detect face
    
            #If no face is detected
            if len(face) == 0:
                
                print("Face not found.")
                
            else:
                
                for x,y,w,h in face:

                    #Cut out the face
                    face_cut = img_g[y:y+h, x:x+w] 
                    #resize
                    face_img = cv2.resize(face_cut, (img_size, img_size))
        
                    #Save
                    result_img_name = '\data' + str(label) + '.jpg'
                    cv2.imwrite(os.path.join(result_out + result_img_name), face_img)
                    label += 1
            
                print("Processing success!!")
                
        else:
            print("Unsupported file extension")
    
def main():
    
    #Command line option creation
    parser = arg.ArgumentParser(description='Face image cropping')
    parser.add_argument('--imgs_dir', '-d', type=str, default=None,
                        help='Image folder path(Error if not specified)')
    parser.add_argument('--out', '-o', type=str, 
                        default=os.path.dirname(os.path.abspath(__file__))+'/result_crop'.replace('/', os.sep),
                        help='Data storage destination after processing(Default value=./reslut_crop)')
    parser.add_argument('--img_size', '-s', type=int, default=32,
                        help='resize(N for NxN,Default value=32)')
    parser.add_argument('--label', '-l', type=int, default=1,
                        help='dataN.Initial value of N in jpg(Default value=1)')
    parser.add_argument('--haar_file', '-c', type=str, default=os.path.dirname(os.path.abspath(__file__))+'/haar_cascade.xml'.replace('/', os.sep),
                        help='haar-Cascade path specification(Default value=./haar_cascade.xml)')
    args = parser.parse_args()

    #When the image folder is not specified->exception
    if args.imgs_dir == None:
        print("\nException: Cropping target is not specified.\n")
        sys.exit()
    #When specifying an image folder that does not exist->exception
    if os.path.exists(args.imgs_dir) != True:
        print("\nException: {} does not exist.\n".format(args.imgs_dir))
        sys.exit()     
    #When Cascade that does not exist is specified->exception
    if os.path.exists(args.haar_file) != True:
        print("\nException: {} does not exist.\n".format(args.haar_file))
        sys.exit()

    #Setting information output
    print("=== Setting information ===")
    print("# Images folder: {}".format(os.path.abspath(args.imgs_dir)))
    print("# Output folder: {}".format(args.out))
    print("# Images size: {}".format(args.img_size))
    print("# Start index: {}".format(args.label))
    print("# Haar-cascade: {}".format(args.haar_file))
    print("===========================\n")

    #Create output folder(Do not create if the folder exists)
    os.makedirs(args.out, exist_ok=True)
    
    #processing
    face_cut(args.imgs_dir, args.out, args.img_size, args.label, args.haar_file)
    print("")
    
if __name__ == '__main__':
    main()

Execution result

The prepared images are as follows. Tatsuya Okawa. image.png

image.png

** If "Face not found." Is output, it means that the face could not be detected, in other words, it could not be recognized as a face **. In this example, the bottom two could not be recognized as faces. image.png

Both have their faces tilted. There is no problem if it is tilted to some extent, but it seems that it is useless if it is tilted at an angle like the image. If you really want to cut out the face, you need to perform affine transformation on the image.

Other than these two, like this image.png

It has been grayscaled and only the face has been cut out and resized. It doesn't matter if you wear glasses. (Wearing sunglasses and masks may be difficult ...)

command python face_cut.py -d <image folder> (-o <destination> -s <resize> -l <index> -c <cascade>)

The save destination of the processed image data is ./result_crop by default. The Haar-cascade specification is ./haar_cascade.xml by default. In addition, the resizing is 32x32px and the index is 1 by default.

Description

Use the face_cut function to grayscale, cut and resize the face.

First, load Haar-cascade, which is used to detect and cut faces.

    # Haar-Like Feature Cascade classifier reading
    cascade = cv2.CascadeClassifier(HAAR_FILE)

HAAR_FILE is the Haar-cascade path specified by the command option.

The processing below loads the image, grayscales it, and detects the face.

    #Data processing
    for img_name in natsorted(os.listdir(imgs_dir)):

        print("image data:{}".format(img_name))
        
        #jpg format only
        _, ext = os.path.splitext(img_name)
        if ext.lower() == '.jpg':
            
            img_path = os.path.join(imgs_dir, img_name) #Combine file paths
            img = cv2.imread(img_path)  #Data read
            
            img_g = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) #Convert to grayscale
            face = cascade.detectMultiScale(img_g)  #Detect face

This time, only ** JPEG files are targeted **, ʻIf ext.lower () =='.jpg':to'.png'or'.bmp'`, you can process the file.

Convert an RGB image to a grayscale image with cv2.cvtColor (). After that, use cascade.detectMultiScale () to detect the face using Haar-cascade.

            img_g = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) #Convert to grayscale
            face = cascade.detectMultiScale(img_g)  #Detect face

cascade.detectMultiScale () returns ** the x and y coordinates, width and height of the detected location ** when a face is detected. If the face is not detected, nothing will be returned.

            #If no face is detected
            if len(face) == 0:
                
                print("Face not found.")
                
            else:
                
                for x,y,w,h in face:

                    #Cut out the face
                    face_cut = img_g[y:y+h, x:x+w] 
                    #resize
                    face_img = cv2.resize(face_cut, (img_size, img_size))
        
                    #Save
                    result_img_name = '\data' + str(label) + '.jpg'
                    cv2.imwrite(os.path.join(result_out + result_img_name), face_img)
                    label += 1
            
                print("Processing success!!")
                
        else:
            print("Unsupported file extension")

In the process below, the face part is cut out based on the returned information.

                    #Cut out the face
                    face_cut = img_g[y:y+h, x:x+w] 

It looks like the figure below. (It's hard to see ...) image.png

After cutting, resize to the specified size with cv2.resize () and save.

that's all. I don't think it is necessary to explain the main function, so I will omit it.

in conclusion

I used data scraping and this program to collect training data. Unless you are particular about it, you can use it enough.

However, as mentioned in Execution result There are limits. In the case of profile, Haar-cascade dedicated to profile is also included, so you may want to use that. In addition, ** data cleansing ** (elimination of images with non-face cuts) ** is required because there are some false positives **.

Recommended Posts

Let's cut the face from the image
Let's search from the procession
Remove the frame from the image
Let's guess the development status of the city from the satellite image.
I tried to cut out a still image from the video
Cut out A4 print in the image
Face detection from multiple image files with openCV, cut out and save
Download the image from the text file containing the URL
Let's apply the brand image color to the matplotlib colormap!
I tried to detect the iris from the camera image
Identify the name from the flower image with keras (tensorflow)
Extracted text from image
Let's add it to the environment variable from the command ~
I want to cut out only the face from a person image with Python and save it ~ Face detection and trimming with face_recognition ~
Save the input video from the capture board as an image
I tried face recognition from the video (OpenCV: python version)
Dot according to the image
Let's turn the air gacha
I tweeted from the terminal!
Cut the PyTorch calculation graph
Outline the face using Dlib (1)
The image is a slug
Do a search by image from the camera roll using Pythonista3
[Python] Try to graph from the image of Ring Fit [OCR]
Let's touch Google's Vision API from Python for the time being