Python Opencv draw rectangle from smaller frame - python

I am currently working on a face detection algorithm using MTCNN.
With the below code, I am able to show the frame containing my face:
`def run_detection(fast_mtcnn):
frames = []
frames_processed = 0
faces_detected = 0
batch_size = 60
start = time.time()
cap = cv2.VideoCapture(0)
while True:
__, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frames.append(frame)
faces = fast_mtcnn(frames)
frames_processed += len(frames)
faces_detected += len(faces)
frames = []
if len(faces) > 0:
for face in faces:
cv2.imshow('frame',face)
print(
f'Frames per second: {frames_processed / (time.time() - start):.3f},',
f'faces detected: {faces_detected}\r',
end=''
)
if cv2.waitKey(1) &0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()`
FYI, the cv2.imshow('frame',face) is just for me to put some value there as I would like to get its bouding box.
Which looks something like this(please forgive my silly looking face):
enter image description here
This I just to show that it is detecting the face and its taking out the frames relating to my face.
What my challenge is, is how to take the smaller frame face (containing my face) and get the edge coordinates of it to draw a bounding box for each person in the frame.
What I tried is the following:
cv2.rectangle(frame,
(face[0], face[1]),
(face[0]+face[2], face[1] + face[3]),
(0,155,255),
2)
Which i assume is completely wrong.

The solution will depend on how the points are returned by the face detection system which can vary depending on the library you use.
In this case the detected face contains the following information
x, y, w, h = face where x and y is a point, w is the width of the bounding box, and h is the height.
Hence you can draw a rectangle of the face as follows:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

Related

Face Detection - Open CV can't find the face

I am learning the OpenCV. Here is my code:
import cv2
face_patterns = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
sample_image = cv2.imread('1.jpg')
gray = cv2.cvtColor(sample_image,cv2.COLOR_RGB2GRAY)
faces = face_patterns.detectMultiScale(gray,1.3,5)
print(len(faces))
for (x, y, w, h) in faces:
cv2.rectangle(sample_image, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.imwrite('result.jpg', sample_image)
If I use the picture A, I could get a lot of faces, if I use the picture B, I get none.
I changed argument in detectMultiScale(gray,1.3,5) many times, it still doesn't work.
Picture A
Picture A Result
Picture B no face
I see this more as a problem of Cv2 module itself. There are better models than HAAR CASCADES for detecting faces. face_recognition library is also very useful to detect and recognize face. It uses hog as default model. You can also use cnn for better accuracy but the detection process will be slow.
Find more here.
import cv2
import face_recognition as fr
sample_image = fr.load_image_file("1.jpg")
unknown_face_loc = fr.face_locations(sample_image, model="hog")
print(len(unknown_face_loc)) #detected face count
for faceloc in unknown_face_loc:
y1, x2, y2, x1 = faceloc
cv2.rectangle(sample_image, (x1, y1), (x2, y2), (0, 0, 255), 2)
sample_image = sample_image[:, :, ::-1] #converting bgr image to rbg
cv2.imwrite("result.jpg", sample_image)
Instead of -
faces = face_patterns.detectMultiScale(gray,1.3,5)
Try Using -
faces = face_patterns.detectMultiScale(blackandwhite,1.3,5)
If the problem occurs even after this check out my code for face detection.
It uses hog as default model. You can also use cnn for better accuracy but the detection process will be slow.
cascade_classifier = cv2.CascadeClassifier('haarcascades/haarcascade_eye.xml')
cap = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, 0)
detections = cascade_classifier.detectMultiScale(gray,scaleFactor=1.3,minNeighbors=5)
if(len(detections) > 0):
(x,y,w,h) = detections[0]
frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
# for (x,y,w,h) in detections:
# frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()```

Face Recognition using python in fisheye camera

I wanted to create an application where it detects the face in fisheye camera but i have no idea how to compress it to fisheye camera but it detects the faces in the normal webcam i tired different ways like editing the points in the face and i couldn't even print the points in my face below are the source code
import face_recognition
import cv2
import numpy as np
import dlib
# This is a demo of running face recognition on live video from your webcam. It's a little more complicated than the
# other example, but it includes some basic performance tweaks to make things run a lot faster:
# 1. Process each video frame at 1/4 resolution (though still display it at full resolution)
# 2. Only detect faces in every other frame of video.
# PLEASE NOTE: This example requires OpenCV (the `cv2` library) to be installed only to read from your webcam.
# OpenCV is *not* required to use the face_recognition library. It's only required if you want to run this
# specific demo. If you have trouble installing it, try any of the other demos that don't require it instead.
# Get a reference to webcam #0 (the default one)
video_capture = cv2.VideoCapture(0)
# Load a sample picture and learn how to recognize it.
obama_image = face_recognition.load_image_file("obama.jpg")
obama_face_encoding = face_recognition.face_encodings(obama_image)[0]
# Load a second sample picture and learn how to recognize it.
biden_image = face_recognition.load_image_file("biden.jpg")
biden_face_encoding = face_recognition.face_encodings(biden_image)[0]
# Load a Third sample picture and learn how to recognize it.
Logesh_image = face_recognition.load_image_file("Upside Logesh.jpg")
Logesh_face_encoding = face_recognition.face_encodings(Logesh_image)[0]
# Create arrays of known face encodings and their names
known_face_encodings = [
obama_face_encoding,
biden_face_encoding,
Logesh_face_encoding
]
known_face_names = [
"Barack Obama",
"Joe Biden",
"Logesh"
]
# Initialize some variables
face_locations = []
face_encodings = []
face_names = []
face_position = []
process_this_frame = True
face_landmarks = []
while True:
# Grab a single frame of video
ret, frame = video_capture.read()
#Postion Frame
Direction_frame = cv2.resize(frame, (50, 50), fx=1.50, fy=1.50)
# 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]
# 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_position = face_recognition.face_landmarks(rgb_small_frame, face_locations)
face_position = face_recognition.face_landmarks(rgb_small_frame, face_locations)
face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
face_landmarks = face_recognition.face_landmarks(rgb_small_frame, face_locations)
face_names = []
for face_encoding in face_encodings:
# See if the face is a match for the known face(s)
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"
# # If a match was found in known_face_encodings, just use the first one.
# if True in matches:
# first_match_index = matches.index(True)
# name = known_face_names[first_match_index]
# Or instead, use the known face with the smallest distance to the new face
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = known_face_names[best_match_index]
face_names.append(name)
process_this_frame = not process_this_frame
def rect_to_bb(rect):
# take a bounding predicted by dlib and convert it
# to the format (x, y, w, h) as we would normally do
# with OpenCV
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
# return a tuple of (x, y, w, h)
return x, y, w, h
# 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 - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 10, bottom - 6), font, 1.0, (255, 255, 255), 1)
# Movement of a person
if right < 448:
Right_Command = "You are in the right side"
cv2.putText(frame, Right_Command, (left - 100, bottom - 300), font, 1.0, (255, 255, 255), 1)
if left > 928:
Left_Command = "You are in the left side"
cv2.putText(frame, Left_Command, (left - 100, bottom - 300), font, 1.0, (255, 255, 255), 1)
# Display the resulting image
cv2.imshow('Video', frame)
# Hit 'q' on the keyboard to quit!
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap = cv2.VideoCapture(0)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
while True:
_, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray)
for face in faces:
x1 = face.left()
y1 = face.top()
x2 = face.right()
y2 = face.bottom()
#cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 3)
landmarks = predictor(gray, face)
for n in range(0, 68):
x = landmarks.part(n).x
y = landmarks.part(n).y
cv2.circle(frame, (x, y), 4, (255, 0, 0), -1)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1)
if key == 27:
break
# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()
You could remove the fisheye distortion and try face recognition afterwards, I don't know how fast that is though. You can do it in OpenCV, first you'll need to find out the camera's optical parameters with cv2.fisheye.calibrate() and then remove the distortion. This answer gives a brief tutorial.

Understanding how to deploy python code to pop up balloons

I'm a newbie in programming and I need to write code to detect balloon on the fixed background using numpy and openCV in live video and to return the centre of the object [balloon].
Sorry about the ignorance of the questions.
Since I'm new, I had troubles with thinking about the logic of doing it, I don't have the resources to "teach the machine" and creating cascade XML to detect balloons so I thought about 1 possible solution :
Using cv2.createBackgroundSubtractorMOG2() to detect motion with the same background and once there is some object [balloon], count all the white pixels in the live video and return the centre of it, with the right threshold amount of white pixels.
The problem is, I don't know how to get the value of the pixel from 0-255 to know if it's white or black and shows the video at the same time, I think that there is a much easier way that I couldn't find guides for it.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while(1):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
img_arr = np.array(fgmask)
cv2.imshow('frame',fgmask)
for i in fgmask:
for j in i:
print(fgmask)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
I'm getting fray video on the output and lots of values that I don't know how to understand them on the output.
I would use
changes = (fgmask>200).sum()
to compare all pixels with almost white value (>200) and count these pixels.
And then I can compare result with some value to treat it as move.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, frame = cap.read()
if frame is None:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
#changes = sum(sum(fgmask>200))
changes = (fgmask>200).sum()
is_moving = (changes > 10000)
print(changes, is_moving)
cv2.imshow('frame', fgmask)
k = cv2.waitKey(10) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
print() needs some time to display text so printing all pixels (many times in loop) can slow down program. So I skip this. I don't have to know values of all pixels.
EDIT: Using answer in how to detect region of large # of white pixels using opencv? and add code which can find white regions and draw rectangle. Program opens two window - one with grayscale fgmask and other with RGB frame and they can be hidden one behind another. You have to move one window to see another.
EDIT: I added code which use cv2.contourArea(cnt) and (x,y,w,h) = cv2.boundingRect(cnt) to create list with items (area,x,y,w,h) for all counturs and then get max(items) to get contour with the biggest area. And then it use (x + w//2, y + h//2) as center for red circle.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
ret, frame = cap.read()
if frame is None:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
#changes = sum(sum(fgmask>200))
changes = (fgmask>200).sum() #
is_moving = (changes > 10000)
print(changes, is_moving)
items = []
contours, hier = cv2.findContours(fgmask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if 200 < area:
(x,y,w,h) = cv2.boundingRect(cnt)
cv2.rectangle(fgmask, (x,y),(x+w,y+h),255, 2)
cv2.rectangle(frame, (x,y),(x+w,y+h),(0,255,0), 2)
items.append( (area, x, y, w, h) )
if items:
main_item = max(items)
area, x, y, w, h = main_item
if w > h:
r = w//2
else:
r = h//2
cv2.circle(frame, (x+w//2, y+h//2), r, (0,0,255), 2)
cv2.imshow('fgmask', fgmask)
cv2.imshow('frame', frame)
k = cv2.waitKey(10) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
cap.release()

How to create a counter in face detection?

As you can see in the code below, it only detects the faces with haar cascade, I would like to know how I show the webcam how many people are currently detected.
For example, show in the corner of the webcam X people detected.
from __future__ import print_function
import cv2
cap = cv2.VideoCapture(0)
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
while (cap.isOpened()):
ret,frame = cap.read()
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5,
flags=cv2.CASCADE_SCALE_IMAGE,minSize=(50, 50), maxSize=None)
if len(faces) > 0:
print("detected person!")
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x - 10, y - 20), (x + w + 10, y + h + 10), (0, 255, 0), 2)
roi_gray = frame[y-15:y + h+10, x-10:x + w+10]
cv2.imshow("imagem", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
I suspect everything shown in the code works just fine.
If so, you already know how many faces are detected with len(faces). You now only need to add this info into the video.
For this, I suggest you use the cv::putText function : https://docs.opencv.org/3.1.0/d6/d6e/group__imgproc__draw.html#ga5126f47f883d730f633d74f07456c576
You will then be able to add this on each frames that are read.
Side note: This might just be because of copy-pasting your code here, but pay attention to your indentation.
Simply displaying the count of len(faces) may not solve the purpose,as you can have instances wherein there are multiple bounding boxes drawn over the same face.Therefore, I would suggest you to perform Non Maximal Suppression(NMS) on the result of your detections, followed by incrementing a counter for each time one calls the NMS operation. The final count of the counter will give you a better and more accurate result.

Updating an OpenCV tracker with a bounding box in python

I am using an OpenCV tracker to perform face tracking in videos, together with a face detector every few frames. If a face is detected by the face detector, I would like to update the tracker with the "detected" bounding box. I see that there is an option to enter a Rect in the C++ implementation but for some reason not in the python implementation as written in the opencv documentation. This is also an option when using dlib's correlation_tracker.
Currently, I can only initialize the tracker with a bounding box, but not update it with one in Python. if my tracker has drifted off the initial face it was tracking, I can't "bring it back" even if I know where the face is now (using my face detector). Is there a way to do this in python (e.g. should I kill the current tracker and init another with detected bounding box)?
I was looking for the very same thing and I found myself the solution to the problem by re-creating tracker each time successful detection occur. Please check following code. If something is not clear, feel free to ask for details:
import cv2 as cv
cap = cv.VideoCapture(0)
face_front_cascade = cv.CascadeClassifier("haarcascade_frontalface_alt.xml")
tracker = cv.TrackerKCF_create()
bbox = ()
while True:
ret,frame = cap.read()
#press S to capture the face
if cv.waitKey(20) & 0xFF == ord("s"):
frame_gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
face = face_front_cascade.detectMultiScale(frame_gray, scaleFactor=1.5, minNeighbors=3)
for (x, y, w, h) in face:
colour = (0,0,255)
stroke = 20
cv.rectangle(frame,(x,y),(x+w,y+h), colour, stroke)
bbox = (x,y,w,h)
tracker = cv.TrackerKCF_create() #overwrite old tracker
#trace face and draw box around it
if bbox:
tracker.init(frame, bbox)
ret, bbox = tracker.update(frame)
if ret:
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv.rectangle(frame, p1, p2, (255, 0, 0), 2, 1)
#show result
cv.imshow("frame",frame)
#press ESC to exit
if cv.waitKey(20) & 0xFF ==27:
break
cap.release()
cv.destroyAllWindows()

Categories