programing

얼굴 감지 후 사진 자동 자르기

yoursource 2021. 1. 17. 12:25
반응형

얼굴 감지 후 사진 자동 자르기


내 사진에서 얼굴을 감지하고 감지 된 얼굴을 중앙에 배치하고 사진의 720 x 720 픽셀을자를 수있는 앱을 찾으려고합니다. 제가 그렇게 할 계획 인 수백 장의 사진을 편집하는 것은 시간이 많이 걸리고 세심한 작업입니다.

여기에 언급 된 python opencv를 사용하여 시도했지만 구식이라고 생각합니다. 나는 또한 이것을 사용해 보았지만 내 시스템에서 오류가 발생합니다. 또한 김프 용 얼굴 인식 플러그인을 사용해 보았지만 김프 2.6 용으로 설계되었지만 정기적으로 2.8을 사용하고 있습니다. 나는 또한 ultrahigh 블로그에 게시 된 작업을 시도했지만 매우 구식입니다 (우분투의 Precise 파생물을 사용하고 있기 때문에 블로그 게시물은 여전히 ​​Hardy 일 때 돌아 왔습니다). 또한 Phatch를 사용해 보았지만 얼굴 인식 기능이 없으므로 일부 잘린 사진은 얼굴이 바로 잘립니다.

나는 위의 모든 것을 시도했고 위의 어떤 것이 내가해야 할 일을하도록하기 위해 반나절을 낭비했다.

내가 가지고있는 약 800 장의 사진에 대한 목표를 달성하기위한 제안이 있습니까?

내 운영 체제는 Linux Mint 13 MATE입니다.

참고 : 링크를 2 개 더 추가하려고했지만 아직 평판이별로 없기 때문에 stackexchange에서 링크를 2 개 더 게시 할 수 없었습니다.


나는 다양한 소스에서 코드의 일부를 가져 와서 이것을 함께 꿰맬 수 있었다. 아직 진행중인 작업입니다. 또한 예제 이미지가 있습니까?

'''
Sources:
http://pythonpath.wordpress.com/2012/05/08/pil-to-opencv-image/
http://www.lucaamore.com/?p=638
'''

#Python 2.7.2
#Opencv 2.4.2
#PIL 1.1.7

import cv
import Image

def DetectFace(image, faceCascade):
    #modified from: http://www.lucaamore.com/?p=638

    min_size = (20,20)
    image_scale = 1
    haar_scale = 1.1
    min_neighbors = 3
    haar_flags = 0

    # Allocate the temporary images
    smallImage = cv.CreateImage(
            (
                cv.Round(image.width / image_scale),
                cv.Round(image.height / image_scale)
            ), 8 ,1)

    # Scale input image for faster processing
    cv.Resize(image, smallImage, cv.CV_INTER_LINEAR)

    # Equalize the histogram
    cv.EqualizeHist(smallImage, smallImage)

    # Detect the faces
    faces = cv.HaarDetectObjects(
            smallImage, faceCascade, cv.CreateMemStorage(0),
            haar_scale, min_neighbors, haar_flags, min_size
        )

    # If faces are found
    if faces:
        for ((x, y, w, h), n) in faces:
            # the input to cv.HaarDetectObjects was resized, so scale the
            # bounding box of each face and convert it to two CvPoints
            pt1 = (int(x * image_scale), int(y * image_scale))
            pt2 = (int((x + w) * image_scale), int((y + h) * image_scale))
            cv.Rectangle(image, pt1, pt2, cv.RGB(255, 0, 0), 5, 8, 0)

    return image

def pil2cvGrey(pil_im):
    #from: http://pythonpath.wordpress.com/2012/05/08/pil-to-opencv-image/
    pil_im = pil_im.convert('L')
    cv_im = cv.CreateImageHeader(pil_im.size, cv.IPL_DEPTH_8U, 1)
    cv.SetData(cv_im, pil_im.tostring(), pil_im.size[0]  )
    return cv_im

def cv2pil(cv_im):
    return Image.fromstring("L", cv.GetSize(cv_im), cv_im.tostring())


pil_im=Image.open('testPics/faces.jpg')
cv_im=pil2cv(pil_im)
#the haarcascade files tells opencv what to look for.
faceCascade = cv.Load('C:/Python27/Lib/site-packages/opencv/haarcascade_frontalface_default.xml')
face=DetectFace(cv_im,faceCascade)
img=cv2pil(face)
img.show()

Google의 첫 페이지에서 테스트 (Googled "얼굴") : 여기에 이미지 설명 입력


최신 정보

이 코드는 원하는대로 정확하게 수행해야합니다. 궁금한 점이 있으면 알려주세요. 코드에 많은 주석을 포함하려고했습니다.

'''
Sources:
http://opencv.willowgarage.com/documentation/python/cookbook.html
http://www.lucaamore.com/?p=638
'''

#Python 2.7.2
#Opencv 2.4.2
#PIL 1.1.7

import cv #Opencv
import Image #Image from PIL
import glob
import os

def DetectFace(image, faceCascade, returnImage=False):
    # This function takes a grey scale cv image and finds
    # the patterns defined in the haarcascade function
    # modified from: http://www.lucaamore.com/?p=638

    #variables    
    min_size = (20,20)
    haar_scale = 1.1
    min_neighbors = 3
    haar_flags = 0

    # Equalize the histogram
    cv.EqualizeHist(image, image)

    # Detect the faces
    faces = cv.HaarDetectObjects(
            image, faceCascade, cv.CreateMemStorage(0),
            haar_scale, min_neighbors, haar_flags, min_size
        )

    # If faces are found
    if faces and returnImage:
        for ((x, y, w, h), n) in faces:
            # Convert bounding box to two CvPoints
            pt1 = (int(x), int(y))
            pt2 = (int(x + w), int(y + h))
            cv.Rectangle(image, pt1, pt2, cv.RGB(255, 0, 0), 5, 8, 0)

    if returnImage:
        return image
    else:
        return faces

def pil2cvGrey(pil_im):
    # Convert a PIL image to a greyscale cv image
    # from: http://pythonpath.wordpress.com/2012/05/08/pil-to-opencv-image/
    pil_im = pil_im.convert('L')
    cv_im = cv.CreateImageHeader(pil_im.size, cv.IPL_DEPTH_8U, 1)
    cv.SetData(cv_im, pil_im.tostring(), pil_im.size[0]  )
    return cv_im

def cv2pil(cv_im):
    # Convert the cv image to a PIL image
    return Image.fromstring("L", cv.GetSize(cv_im), cv_im.tostring())

def imgCrop(image, cropBox, boxScale=1):
    # Crop a PIL image with the provided box [x(left), y(upper), w(width), h(height)]

    # Calculate scale factors
    xDelta=max(cropBox[2]*(boxScale-1),0)
    yDelta=max(cropBox[3]*(boxScale-1),0)

    # Convert cv box to PIL box [left, upper, right, lower]
    PIL_box=[cropBox[0]-xDelta, cropBox[1]-yDelta, cropBox[0]+cropBox[2]+xDelta, cropBox[1]+cropBox[3]+yDelta]

    return image.crop(PIL_box)

def faceCrop(imagePattern,boxScale=1):
    # Select one of the haarcascade files:
    #   haarcascade_frontalface_alt.xml  <-- Best one?
    #   haarcascade_frontalface_alt2.xml
    #   haarcascade_frontalface_alt_tree.xml
    #   haarcascade_frontalface_default.xml
    #   haarcascade_profileface.xml
    faceCascade = cv.Load('haarcascade_frontalface_alt.xml')

    imgList=glob.glob(imagePattern)
    if len(imgList)<=0:
        print 'No Images Found'
        return

    for img in imgList:
        pil_im=Image.open(img)
        cv_im=pil2cvGrey(pil_im)
        faces=DetectFace(cv_im,faceCascade)
        if faces:
            n=1
            for face in faces:
                croppedImage=imgCrop(pil_im, face[0],boxScale=boxScale)
                fname,ext=os.path.splitext(img)
                croppedImage.save(fname+'_crop'+str(n)+ext)
                n+=1
        else:
            print 'No faces found:', img

def test(imageFilePath):
    pil_im=Image.open(imageFilePath)
    cv_im=pil2cvGrey(pil_im)
    # Select one of the haarcascade files:
    #   haarcascade_frontalface_alt.xml  <-- Best one?
    #   haarcascade_frontalface_alt2.xml
    #   haarcascade_frontalface_alt_tree.xml
    #   haarcascade_frontalface_default.xml
    #   haarcascade_profileface.xml
    faceCascade = cv.Load('haarcascade_frontalface_alt.xml')
    face_im=DetectFace(cv_im,faceCascade, returnImage=True)
    img=cv2pil(face_im)
    img.show()
    img.save('test.png')


# Test the algorithm on an image
#test('testPics/faces.jpg')

# Crop all jpegs in a folder. Note: the code uses glob which follows unix shell rules.
# Use the boxScale to scale the cropping area. 1=opencv box, 2=2x the width and height
faceCrop('testPics/*.jpg',boxScale=1)

위의 이미지를 사용하여이 코드는 59 개의 얼굴 중 52 개를 추출하여 다음과 같은 잘린 파일을 생성합니다. 여기에 이미지 설명 입력여기에 이미지 설명 입력여기에 이미지 설명 입력여기에 이미지 설명 입력여기에 이미지 설명 입력여기에 이미지 설명 입력여기에 이미지 설명 입력여기에 이미지 설명 입력


사용 가능한 또 다른 옵션은 기계 학습 접근 방식을 기반으로하는 dlib 입니다.

import dlib
import Image
from skimage import io
import matplotlib.pyplot as plt


def detect_faces(image):

    # Create a face detector
    face_detector = dlib.get_frontal_face_detector()

    # Run detector and get bounding boxes of the faces on image.
    detected_faces = face_detector(image, 1)
    face_frames = [(x.left(), x.top(),
                    x.right(), x.bottom()) for x in detected_faces]

    return face_frames

# Load image
img_path = 'test.jpg'
image = io.imread(img_path)

# Detect faces
detected_faces = detect_faces(image)

# Crop faces and plot
for n, face_rect in enumerate(detected_faces):
    face = Image.fromarray(image).crop(face_rect)
    plt.subplot(1, len(detected_faces), n+1)
    plt.axis('off')
    plt.imshow(face)

여기에 이미지 설명 입력 여기에 이미지 설명 입력


얼굴 감지

https://github.com/wavexx/facedetect 는 멋진 Python OpenCV CLI 래퍼이며 ImageMagick을 사용하여 해당 예제를 README에 추가 했습니다.

for file in path/to/pictures/*.jpg; do
  name=$(basename "$file")
  i=0
  facedetect "$file" | while read x y w h; do
    convert "$file" -crop ${w}x${h}+${x}+${y} "path/to/faces/${name%.*}_${i}.${name##*.}"
    i=$(($i+1))
  done
done

수천 개의 (레이블이없는) Facebook 프로필 사진으로 Ubuntu 16.04에서 테스트되었습니다. https://github.com/cirosantilli/art/tree/d4352a46064d156591817c4eae5199f5ac8f23be/facebook


이것은 더 많은 (컴퓨터) 기술에 초점을 맞춘 교환 중 하나에 더 나은 질문이 될 수 있습니다.

즉, jquery 얼굴 감지 스크립트 와 같은 것을 살펴 보셨습니까? 당신이 얼마나 잘 알고 있는지는 모르겠지만 OS에 독립적 인 옵션 중 하나입니다.

이 솔루션 도 유망 보이지만 Windows가 필요합니다.


위의 코드는 작동하지만 이것은 OpenCV를 사용하는 최근 구현입니다. 최신으로 위를 실행할 수 없었고 (다양한 곳에서) 작동하는 것을 발견했습니다.

import cv2
import os

def facecrop(image):
    facedata = "haarcascade_frontalface_alt.xml"
    cascade = cv2.CascadeClassifier(facedata)

    img = cv2.imread(image)

    minisize = (img.shape[1],img.shape[0])
    miniframe = cv2.resize(img, minisize)

    faces = cascade.detectMultiScale(miniframe)

   for f in faces:
        x, y, w, h = [ v for v in f ]
        cv2.rectangle(img, (x,y), (x+w,y+h), (255,255,255))

        sub_face = img[y:y+h, x:x+w]
        fname, ext = os.path.splitext(image)
        cv2.imwrite(fname+"_cropped_"+ext, sub_face)



    return



facecrop("1.jpg")

Autocrop 은 나를 위해 꽤 잘 작동했습니다. 그것만큼 쉽습니다 autocrop -i pics -o crop -w 400 -H 400. readme 파일에서 사용법을 얻을 수 있습니다.

usage: [-h] [-o OUTPUT] [-i INPUT] [-w WIDTH] [-H HEIGHT] [-v]

Automatically crops faces from batches of pictures

optional arguments:
  -h, --help            Show this help message and exit
  -o, --output, -p, --path
            Folder where cropped images will be placed.
            Default: current working directory
  -i, --input
            Folder where images to crop are located.
            Default: current working directory
  -w, --width
            Width of cropped files in px. Default=500
  -H, --height
            Height of cropped files in px. Default=500
  -v, --version         Show program's version number and exit

파이썬 패키지 'face_recognition''opencv-python'을 사용하여 "Face-Recognition-with-Own-Data-Set"응용 프로그램을 개발했습니다 .

소스 코드 및 설치 가이드는 GitHub- Face-Recognition-with-Own-Data-Set에 있습니다.

또는 소스 실행-

import face_recognition
import cv2
import numpy as np

import os
'''
    Get current working director and create a Data directory to store the faces
'''
currentDirectory = os.getcwd()
dirName = os.path.join(currentDirectory, 'Data')
print(dirName)
if not os.path.exists(dirName):
    try:
        os.makedirs(dirName)
    except:
        raise OSError("Can't create destination directory (%s)!" % (dirName))
'''
    For the given path, get the List of all files in the directory tree 
'''
def getListOfFiles(dirName):
    # create a list of file and sub directories
    # names in the given directory
    listOfFile = os.listdir(dirName)
    allFiles = list()
    # Iterate over all the entries
    for entry in listOfFile:
        # Create full path
        fullPath = os.path.join(dirName, entry)
        # If entry is a directory then get the list of files in this directory
        if os.path.isdir(fullPath):
            allFiles = allFiles + getListOfFiles(fullPath)
        else:
            allFiles.append(fullPath)

    return allFiles

def knownFaceEncoding(listOfFiles):
    known_face_encodings=list()
    known_face_names=list()
    for file_name in listOfFiles:
        # print(file_name)
        if(file_name.lower().endswith(('.png', '.jpg', '.jpeg'))):
            known_image = face_recognition.load_image_file(file_name)
            # known_face_locations = face_recognition.face_locations(known_image)
            # known_face_encoding = face_recognition.face_encodings(known_image,known_face_locations)
            face_encods = face_recognition.face_encodings(known_image)
            if face_encods:
                known_face_encoding = face_encods[0]
                known_face_encodings.append(known_face_encoding)
                known_face_names.append(os.path.basename(file_name[0:-4]))
    return known_face_encodings, known_face_names


# Get the list of all files in directory tree at given path
listOfFiles = getListOfFiles(dirName)
known_face_encodings, known_face_names = knownFaceEncoding(listOfFiles)

video_capture = cv2.VideoCapture(0)
cv2.namedWindow("Video", flags= cv2.WINDOW_NORMAL)
# cv2.namedWindow("Video")

cv2.resizeWindow('Video', 1024,640)
cv2.moveWindow('Video', 20,20)


# Initialize some variables
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True


while True:
    # Grab a single frame of video
    ret, frame = video_capture.read()
    # print(ret)
    # Resize frame of video to 1/4 size for faster face recognition processing
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
    # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)
    rgb_small_frame = small_frame[:, :, ::-1]


    k = cv2.waitKey(1)
    # Hit 'c' on capture the image!
    # Hit 'q' on the keyboard to quit!
    if k == ord('q'):
        break
    elif k== ord('c'):
        face_loc = face_recognition.face_locations(rgb_small_frame)
        if face_loc:
            print("Enter Name -")
            name = input()
            img_name = "{}/{}.png".format(dirName,name)
            (top, right, bottom, left)= face_loc[0]
            top *= 4
            right *= 4
            bottom *= 4
            left *= 4
            cv2.imwrite(img_name, frame[top - 5 :bottom + 5,left -5 :right + 5])
            listOfFiles = getListOfFiles(dirName)
            known_face_encodings, known_face_names = knownFaceEncoding(listOfFiles)

    # Only process every other frame of video to save time
    if process_this_frame:
        # Find all the faces and face encodings in the current frame of video
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
        # print(face_locations)

        face_names = []

        for face_encoding,face_location in zip(face_encodings,face_locations):
            # See if the face is a match for the known face(s)
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding, tolerance= 0.55)
            name = "Unknown"
            distance = 0

            # use the known face with the smallest distance to the new face
            face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
            #print(face_distances)
            if len(face_distances) > 0:
                best_match_index = np.argmin(face_distances)
                if matches[best_match_index]:
                    name = known_face_names[best_match_index]
                    # distance = face_distances[best_match_index]
            #print(face_distances[best_match_index])
            # string_value = '{} {:.3f}'.format(name, distance)
            face_names.append(name)


    process_this_frame = not process_this_frame


    # Display the results
    for (top, right, bottom, left), name in zip(face_locations, face_names):
        # Scale back up face locations since the frame we detected in was scaled to 1/4 size
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # Draw a box around the face
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

        # Draw a label with a name below the face
        cv2.rectangle(frame, (left, bottom + 46), (right, bottom+11), (0, 0, 155), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom +40), font, 1.0, (255, 255, 255), 1)

    # Display the resulting image
    cv2.imshow('Video', frame)

# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()

이 디렉토리가 존재하지 않더라도 현재 위치에 'Data'디렉토리를 생성합니다.

When a face is marked with a rectangle, press 'c' to capture the image and in the command prompt, it will ask for the name of the face. Put the name of the image and enter. You can find this image in the 'Data' directory.


I used this shell command:

for f in *.jpg;do PYTHONPATH=/usr/local/lib/python2.7/site-packages python -c 'import cv2;import sys;rects=cv2.CascadeClassifier("/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml").detectMultiScale(cv2.cvtColor(cv2.imread(sys.argv[1]),cv2.COLOR_BGR2GRAY),1.3,5);print("\n".join([" ".join([str(item) for item in row])for row in rects]))' $f|while read x y w h;do convert $f -gravity NorthWest -crop ${w}x$h+$x+$y ${f%jpg}-$x-$y.png;done;done

You can install opencv and imagemagick on OS X with brew install opencv imagemagick.


Just adding to @Israel Abebe's version. If you add a counter before image extension the algorithm will give all the faces detected. Attaching the code, same as Israel Abebe's. Just adding a counter and accepting the cascade file as an argument. The algorithm works beautifully! Thanks @Israel Abebe for this!

import cv2
import os
import sys

def facecrop(image):
facedata = sys.argv[1]
cascade = cv2.CascadeClassifier(facedata)

img = cv2.imread(image)

minisize = (img.shape[1],img.shape[0])
miniframe = cv2.resize(img, minisize)

faces = cascade.detectMultiScale(miniframe)
counter = 0
for f in faces:
    x, y, w, h = [ v for v in f ]
    cv2.rectangle(img, (x,y), (x+w,y+h), (255,255,255))

    sub_face = img[y:y+h, x:x+w]
    fname, ext = os.path.splitext(image)
    cv2.imwrite(fname+"_cropped_"+str(counter)+ext, sub_face)
    counter += 1
return

facecrop("Face_detect_1.jpg")

PS: Adding as answer. Was not able to add comment because of points issue.


Detect face and then crop and save the cropped image into folder ..

import numpy as np
import cv2 as cv
face_cascade = cv.CascadeClassifier('./haarcascade_frontalface_default.xml')
#eye_cascade = cv.CascadeClassifier('haarcascade_eye.xml')
img = cv.imread('./face/nancy-Copy1.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
    cv.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    roi_gray = gray[y:y+h, x:x+w]
    roi_color = img[y:y+h, x:x+w]
    #eyes = eye_cascade.detectMultiScale(roi_gray)
    #for (ex,ey,ew,eh) in eyes:
     #   cv.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
    sub_face = img[y:y+h, x:x+w]
    face_file_name = "face/" + str(y) + ".jpg"
    plt.imsave(face_file_name, sub_face)
plt.imshow(sub_face)



최선의 선택은 Google Vision API라고 생각합니다. 업데이트되고 기계 학습을 사용하며 시간이 지남에 따라 향상됩니다.

예제에 대한 문서를 확인할 수 있습니다. https://cloud.google.com/vision/docs/other-features

참조 URL : https://stackoverflow.com/questions/13211745/detect-face-then-autocrop-pictures

반응형