用MTCNN算法替换openCV人脸检测

时间:2020-08-10 02:51:58

标签: opencv face-detection cnn

我正在使用openCV进行面部检测。有时,openCV会导致面部检测问题。函数名称是

def detectFace(img_path):
img = functions.detectFace(img_path)[0] #detectFace returns (1, 224, 224, 3)
return img[:, :, ::-1] #bgr to rgb

我想要以上MTCNN算法的输出

detectFace功能代码

def detectFace(img, target_size=(224, 224), grayscale = False, enforce_detection = True):

img_path = ""
img = "/media/khawar/HDD_Khawar/Projects/" + img
print(img)
#-----------------------

exact_image = False
if type(img).__module__ == np.__name__:
    exact_image = True

base64_img = False
if len(img) > 11 and img[0:11] == "data:image/":
    base64_img = True

#-----------------------

opencv_path = get_opencv_path()
face_detector_path = opencv_path+"haarcascade_frontalface_default.xml"
eye_detector_path = opencv_path+"haarcascade_eye.xml"

if os.path.isfile(face_detector_path) != True:
    raise ValueError("Confirm that opencv is installed on your environment! Expected path ",face_detector_path," violated.")

#--------------------------------

face_detector = cv2.CascadeClassifier(face_detector_path)
eye_detector = cv2.CascadeClassifier(eye_detector_path)

if base64_img == True:
    img = loadBase64Img(img)
    
elif exact_image != True: #image path passed as input
    
    if os.path.isfile(img) != True:
        raise ValueError("Confirm that ",img," exists")
    
    img = cv2.imread(img)

img_raw = img.copy()

#--------------------------------

faces = []

try:
    faces = face_detector.detectMultiScale(img, 1.3, 5)
except:
    pass

#print("found faces in ",image_path," is ",len(faces))

if len(faces) > 0:
    print(faces[0])
    x,y,w,h = faces[0]
    detected_face = img[int(y):int(y+h), int(x):int(x+w)]
    detected_face_gray = cv2.cvtColor(detected_face, cv2.COLOR_BGR2GRAY)
    
    #---------------------------
    #face alignment
    
    eyes = eye_detector.detectMultiScale(detected_face_gray)
    
    if len(eyes) >= 2:
        #find the largest 2 eye
        base_eyes = eyes[:, 2]
        
        items = []
        for i in range(0, len(base_eyes)):
            item = (base_eyes[i], i)
            items.append(item)
        
        df = pd.DataFrame(items, columns = ["length", "idx"]).sort_values(by=['length'], ascending=False)
        
        eyes = eyes[df.idx.values[0:2]]
        
        #-----------------------
        #decide left and right eye
        
        eye_1 = eyes[0]; eye_2 = eyes[1]
        
        if eye_1[0] < eye_2[0]:
            left_eye = eye_1
            right_eye = eye_2
        else:
            left_eye = eye_2
            right_eye = eye_1
        
        #-----------------------
        #find center of eyes
        
        left_eye_center = (int(left_eye[0] + (left_eye[2] / 2)), int(left_eye[1] + (left_eye[3] / 2)))
        left_eye_x = left_eye_center[0]; left_eye_y = left_eye_center[1]
        
        right_eye_center = (int(right_eye[0] + (right_eye[2]/2)), int(right_eye[1] + (right_eye[3]/2)))
        right_eye_x = right_eye_center[0]; right_eye_y = right_eye_center[1]
        
        #-----------------------
        #find rotation direction
            
        if left_eye_y > right_eye_y:
            point_3rd = (right_eye_x, left_eye_y)
            direction = -1 #rotate same direction to clock
        else:
            point_3rd = (left_eye_x, right_eye_y)
            direction = 1 #rotate inverse direction of clock
        
        #-----------------------
        #find length of triangle edges
        
        a = distance(left_eye_center, point_3rd)
        b = distance(right_eye_center, point_3rd)
        c = distance(right_eye_center, left_eye_center)
        
        #-----------------------
        #apply cosine rule
        
        if b != 0 and c != 0: #this multiplication causes division by zero in cos_a calculation
        
            cos_a = (b*b + c*c - a*a)/(2*b*c)
            angle = np.arccos(cos_a) #angle in radian
            angle = (angle * 180) / math.pi #radian to degree
            
            #-----------------------
            #rotate base image
            
            if direction == -1:
                angle = 90 - angle
            
            img = Image.fromarray(img_raw)
            img = np.array(img.rotate(direction * angle))
            
            #you recover the base image and face detection disappeared. apply again.
            faces = face_detector.detectMultiScale(img, 1.3, 5)
            if len(faces) > 0:
                x,y,w,h = faces[0]
                detected_face = img[int(y):int(y+h), int(x):int(x+w)]
        
        #-----------------------
    
    #face alignment block end
    #---------------------------
    
    #face alignment block needs colorful images. that's why, converting to gray scale logic moved to here.
    if grayscale == True:
        detected_face = cv2.cvtColor(detected_face, cv2.COLOR_BGR2GRAY)
    
    detected_face = cv2.resize(detected_face, target_size)
    
    img_pixels = image.img_to_array(detected_face)
    img_pixels = np.expand_dims(img_pixels, axis = 0)
    
    #normalize input in [0, 1]
    img_pixels /= 255
    
    return img_pixels
    
else:
    
    if (exact_image == True) or (enforce_detection != True):
        
        if grayscale == True:
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img = cv2.resize(img, target_size)
        img_pixels = image.img_to_array(img)
        img_pixels = np.expand_dims(img_pixels, axis = 0)
        img_pixels /= 255
        return img_pixels
    else:
        print(img)
        raise ValueError("Face could not be detected. Please confirm that the picture is a face photo or consider to set enforce_detection param to False.")

2 个答案:

答案 0 :(得分:0)

尝试一下。

import mtcnn
import matplotlib.pyplot as plt
# load image from file
filename = "glediston-bastos-ZtmmR9D_2tA-unsplash.jpg"
pixels = plt.imread(filename)
print("Shape of image/array:",pixels.shape)
imgplot = plt.imshow(pixels)
plt.show()


# draw an image with detected objects
def draw_facebox(filename, result_list):
# load the image
data = plt.imread(filename)
# plot the image
plt.imshow(data)
# get the context for drawing boxes
ax = plt.gca()
# plot each box
for result in result_list:
# get coordinates
x, y, width, height = result['box']
# create the shape
rect = plt.Rectangle((x, y), width, height, fill=False, color='green')
# draw the box
ax.add_patch(rect)
# show the plot
plt.show()
# filename = 'test1.jpg' # filename is defined above, otherwise uncomment
# load image from file
# pixels = plt.imread(filename) # defined above, otherwise uncomment
# detector is defined above, otherwise uncomment
#detector = mtcnn.MTCNN()
# detect faces in the image
faces = detector.detect_faces(pixels)
# display faces on the original image
draw_facebox(filename, faces)
# draw the dots
for key, value in result['keypoints'].items():
# create and draw dot
dot = plt.Circle(value, radius=20, color='orange')
ax.add_patch(dot)

答案 1 :(得分:0)

您正在使用deepface中的detectFace函数吗?目前,它包装了opencv,ssd,dlib和mtcnn来检测和对齐人脸。

def detectFace(img_path):
   backends = ['opencv', 'ssd', 'dlib', 'mtcnn']
   img = functions.detectFace(img_path, detector_backend = backends[3])[0]  #detectFace returns (1, 224, 224, 3)
   return img[:, :, ::-1] #bgr to rgb

现在检测出detectFace函数的结果并与mtcnn对齐。

此外,您还可以通过mtcnn后端运行人脸识别。

from deepface import DeepFace
obj = DeepFace.verify("img1.jpg", "img2.jpg", detector_backend = 'mtcnn')