I'm trying to write a program that detects my eyes and then just keeps them and blackens the rest of the video.
so I just have the coordinates of eyes and I want to keep these sub-matrices
and make the rest of the matrix to zero.
import numpy as np
import cv2
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
cap = cv2.VideoCapture(0)
while(True):
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
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:
# how to keep this : img[y+ey:y+ey+eh,x+ex:x+ex+ew] ????
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),4)
cv2.imshow('img',img)
k = cv2.waitKey(30) & 0xff
if k==ord('q'):
break
cap.release()
cv2.destroyAllWindows()
generally, how can we do this fast and simple?
I think it's hard to think about how to keep parts of the matrix and zero the rest, simply because "the rest" is a rather irregular shape.
Since you can easily process rectangular sub-matrices using a Region of Interest, you can create a zero matrix of the same size as your initial matrix, compute ROIs for the regions you want to keep, and assign them to ROIs at identical positions in the zero matrix.
See OpenCV C++, getting Region Of Interest (ROI) using cv::Mat for details on how to get the ROIs.
Related
This code works corectly , But it's a very slow .
I changed the cv2.waitKey(1) number. But it still didn't change much
import cv2
import numpy as np
facexml = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
eyexml = cv2.CascadeClassifier("haarcascade_eye.xml")
cap = cv2.VideoCapture("my_video.avi")
while True:
_,frame = cap.read()
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
faces = facexml.detectMultiScale(gray)
for (x,y,w,h) in faces:
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]
eyes = eyexml.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,0,255),1)
cv2.imshow("window",frame)
if cv2.waitKey(1) & 0XFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
Simply a Harris cascade classifier is an old and slow algorithm for fast online face recognition in video. Try to read an OpenCV manual on Cascade Classifier and reduce the number of scales by setting equal maxSize and minSize or set larger scaleFactor to decrease total amount of images computed from original image by resizing.
I have code that detects a face. All I want to do is save the detected face as a jpg
Here is the code for my program:
import numpy as np
import cv2
detector= cv2.CascadeClassifier('haarcascade_fullbody.xml')
cap = cv2.VideoCapture(0)
while(True):
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = detector.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
cv2.imshow('frame',img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
How do I save the detected face? Please help!
detectMultiScale method returns a list where each elements contains the coordinates and width and height of each face that is detected.
So you can use cv2.imwrite and array slicing:
count = 0
for (x,y,w,h) in faces:
face = img[y:y+h, x:x+w] #slice the face from the image
cv2.imwrite(str(count)+'.jpg', face) #save the image
count+=1
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
I'm trying to record the distance travelled by an object (in this instance, part of a face as detected by a haar cascade) from a video file. So far, I have a rectangle drawn to the section of the face that I wish to record x/y travel data for, but have been unable to find info on exactly how to store info on how far/which way the face has travelled in 2 dimensions. My code is below:
import cv2
import numpy as py
from matplotlib import pyplot as plt
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture("resources/video/EXAMPLE.mp4")
while True:
ret, img = cap.read()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 9)
for (x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w, int(y+h/3)), (255,0,0), 2)
cv2.imshow('img',img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cap.destroyAllWindows()
Any info/pointers as far as how I can record movement data would be appreciated!
If you simply want to store the coordinates, you can add the (x,y) tuple to a list
If you're tracking just one face you could use object tracking
If you want to track multiple faces you can check out the multitracker.
So I decided to get started learning Open CV and Python together!
My first project is to detect moving objects on a relatively still background and then detect their average color to sort them. There are at least 10 objects to detect and I am processing a colored video.
So far I managed to remove the background, identify the contours (optionally get the center of each contour) but now I am struggling getting the average or mean color inside of each contour. There are some topics about this kind of question but most of them are written in C. Apparently I could use cv.mean() but I can't get a working mask to feed in this function. I guess it's not so difficult but I am stuck there... Cheers!
import numpy as np
import cv2
video_path = 'test.h264'
cap = cv2.VideoCapture(video_path)
fgbg = cv2.createBackgroundSubtractorMOG2()
while (cap.isOpened):
ret, frame = cap.read()
if ret==True:
fgmask = fgbg.apply(frame)
(contours, hierarchy) = cv2.findContours(fgmask, cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for c in contours:
if cv2.contourArea(c) > 2000:
cv2.drawContours(frame, c, -1, (255,0,0), 3)
cv2.imshow('foreground and background',fgmask)
cv2.imshow('rgb',frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
You can create a mask by first creating a new image with the same dimensions as your input image and pixel values set to zero.
You then draw the contour(s) onto this image with pixel value 255. The resulting image can be used as a mask.
mask = np.zeros(frame.shape, np.uint8)
cv2.drawContours(mask, c, -1, 255, -1)
mask can then be used as a parameter to cv.mean like
mean = cv.mean(frame, mask=mask)
Just one word of caution, the mean of RGB colors does not always make sense. Maybe try converting to HSV color space and solely use the H channel for detecting the color of your objects.
Solution on an image
1) find contour (in this case rectangle, contour that is not rectangle is much harder to make)
2) find coordiantes of contour
3) cut the image from contour
4) sum individual channels and divide them by number of pixels in it ( or with mean function)
import numpy as np
import cv2
img = cv2.imread('my_image.jpg',1)
cp = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(cp,150,255,0)
cv2.imshow('img',thresh)
cv2.waitKey(0)
im2,contours,hierarchy = cv2.findContours(thresh.astype(np.uint8), 1, 2)
cnts = contours
for cnt in cnts:
if cv2.contourArea(cnt) >800: # filter small contours
x,y,w,h = cv2.boundingRect(cnt) # offsets - with this you get 'mask'
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow('cutted contour',img[y:y+h,x:x+w])
print('Average color (BGR): ',np.array(cv2.mean(img[y:y+h,x:x+w])).astype(np.uint8))
cv2.waitKey(0)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
To remove noise, you can just take center of the contour, and take smaller rectangle to examin.
For non rectangular contour, look at cv2.fillPoly function -> Cropping non rectangular contours. But its a bit slow algorithm (but nothing limiting)
If you are interested in non rectangular contour, you will have to be careful about doing mean, because you will need mask and the mask/background is always rectangular so you will be doing mean on something you dont want
I am trying to do some face detection here and using the standard cascades, which can be found here, the following code should draw rectangles over eyes and the face, either the cascades aren't working at all or something's wrong with my code that's supposed to draw over the frame. Also would it be possible to grab the video feed and not have it inverted?
import numpy as np
import cv2
face_cascade = cv2.CascadeClassifier(r'A:\scripts\opencvstuff\haarcascade_frontalcatface.xml')
eye_cascade = cv2.CascadeClassifier(r'A:\scripts\opencvstuff\haarcascade_eye.xml')
cap = cv2.VideoCapture(0)
while 1:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.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:
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
cv2.imshow('img',img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
I was able to get the code to work by changing the Face model from haarcascade_frontalcatface.xml to haarcascade_frontalface_default. Seems dumb but yeah that worked.