S Andrew
S Andrew

Reputation: 7208

How to remove false face detection in python OpenCV

I am doing face detection using python opencv. For this I am using caffe model. Below is the code:

import numpy as np
import imutils
import cv2

protoPath = "<path_to_file>\\deploy.prototxt"
modelPath = "<path_to_file>\\res10_300x300_ssd_iter_140000.caffemodel"
detector = cv2.dnn.readNetFromCaffe(protoPath, modelPath)

image = cv2.imread('test.jpg')
image = imutils.resize(image, width=600)

(h, w) = image.shape[:2]

imageBlob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0), swapRB=False, crop=False)

detector.setInput(imageBlob)
detections = detector.forward()

if len(detections) > 0:
    i = np.argmax(detections[0, 0, :, 2])
    confidence = detections[0, 0, i, 2]

    if confidence > 0.5:
        box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
        (startX, startY, endX, endY) = box.astype("int")

        cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2)

cv2.imshow("Image", image)
cv2.waitKey(0)

Above code is working perfectly fine for almost all images. For example below:

enter image description here

As you can see the face is detected with confidence of 96%. But there are many cases for which the code is detecting false faces as well like below:

enter image description here

Above face is detected but also has false detections and the shocking part is that confidence in both the detections was more than 90%

Whenever I have these type of false detections, I use some online face detector to quickly verify, like this one and the results looks good:

enter image description here

and because of this I sometime feels weather the model I am using for face detection is good enough or not.

Can anyone please help me here and please tell me what I am doing wrong due to which its giving false detections and how can I remove these false detections. Please help. Thanks

EDIT:

Even after doing Non-maximum suppression, its not seems to be working:

def non_max_suppression_fast(self, boxes, overlapThresh):
    try:
        self.dummy = ''
        if len(boxes) == 0:
            return []

        if boxes.dtype.kind == "i":
            boxes = boxes.astype("float")

        pick = []

        x1 = boxes[:, 0]
        y1 = boxes[:, 1]
        x2 = boxes[:, 2]
        y2 = boxes[:, 3]

        area = (x2 - x1 + 1) * (y2 - y1 + 1)
        idxs = np.argsort(y2)

        while len(idxs) > 0:
            last = len(idxs) - 1
            i = idxs[last]
            pick.append(i)

            xx1 = np.maximum(x1[i], x1[idxs[:last]])
            yy1 = np.maximum(y1[i], y1[idxs[:last]])
            xx2 = np.minimum(x2[i], x2[idxs[:last]])
            yy2 = np.minimum(y2[i], y2[idxs[:last]])

            w = np.maximum(0, xx2 - xx1 + 1)
            h = np.maximum(0, yy2 - yy1 + 1)

            overlap = (w * h) / area[idxs[:last]]

            idxs = np.delete(idxs, np.concatenate(([last],
                                                   np.where(overlap > overlapThresh)[0])))

        return boxes[pick].astype("int")
    except Exception as e:
        print("Exception occurred in non_max_suppression : {}".format(e))

###
SOME CODE
###

rects = []
for i in range(0, detections.shape[2]):

    confidence = detections[0, 0, i, 2]

    if confidence > 0.5:
        box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
        (startX, startY, endX, endY) = box.astype("int")

        rects.append(box)

boundingboxes = np.array(rects)
boundingboxes = boundingboxes.astype(int)
rects = non_max_suppression_fast(boundingboxes, 0.3)

boundingBoxes before passing it to non_max_suppression_fast is [[311 280 644 719], [131 114 419 475]] and after suppressions its still the same rects = [[311 280 644 719], [131 114 419 475]]

Upvotes: 0

Views: 1518

Answers (1)

S Andrew
S Andrew

Reputation: 7208

I have resolved this. Although the approach I have used has given me 99% accuracy but I am not sure if the approach is correct or not.

So whenever I get false detections in face images just like below:

enter image description here

In the above image, we can see that the 2nd bounding box which bottom right corner is quite bigger than the actual height and width of the image. Thus I have put a simple check that if bounding box is greater that height/width of the image, ignore it. Below is the code:

res = check_false_detections(h, w, startX, startY, endX, endY)
if not res:
    print("Got false detection")
    continue

and here is the code for check_false_detections:

def check_false_detections(ih, iw, fsx, fsy, fex, fey):
    if ih > iw:
        if fsx > ih:
            return False
        elif fsy > ih:
            return False
        elif fex > ih:
            return False
        elif fey > ih:
            return False
        else:
            return True
    else:
        if fsx > iw:
            return False
        elif fsy > iw:
            return False
        elif fex > iw:
            return False
        elif fey > iw:
            return False
        else:
            return True

This is working fine for my use case. I have tested with more than 150 images. It might not work for anyone else but its worth a try.

Thanks

Upvotes: 1

Related Questions