I made a program that detects faces using Haar-Like feature Cascade provided by OpenCV and automatically cuts them.
-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
** 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))
I will post it on Github.
https://github.com/himazin331/Face-Cropping The repository contains the data processing program Haar-Cascade
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.
** 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()
The prepared images are as follows. Tatsuya Okawa.
** 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.
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
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.
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 ...)
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.
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