I want to control something in a tkinter window by the movement of the detected face from a openCV window. For tkinter window, here is my settings:
def run(width=300, height=300):
root = Tk()
def redrawAllWrapper(canvas, data):
canvas.delete(ALL)
redrawAll(canvas, data)
canvas.update()
def mousePressedWrapper(event, canvas, data):
mousePressed(event, data)
redrawAllWrapper(canvas, data)
def mouseMovedWrapper(event, canvas, data):
mouseMoved(event, data)
redrawAllWrapper(canvas, data)
def keyPressedWrapper(event, canvas, data):
keyPressed(event, data)
redrawAllWrapper(canvas, data)
def timerFiredWrapper(canvas, data):
timerFired(data)
redrawAllWrapper(canvas, data)
# pause, then call timerFired again
canvas.after(data.timerDelay, timerFiredWrapper, canvas, data)
# Set up data and call init
class Struct(object): pass
data = Struct()
data.width = width
data.height = height
data.timerDelay = 50 # milliseconds
init(data)
# create the root and the canvas
# root = Tk()
canvas = Canvas(root, width=data.width, height=data.height)
canvas.pack()
# set up events
root.bind("<B1-Motion>", lambda event: mouseMovedWrapper(event, canvas, data))
timerFiredWrapper(canvas, data)
root.bind("<Button-1>", lambda event:
mousePressedWrapper(event, canvas, data))
root.bind("<Key>", lambda event:
keyPressedWrapper(event, canvas, data))
# and launch the app
root.mainloop() # blocks until window is closed
print("bye!")
run(1000, 750)
About the openCV part is like this:
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eyeCascade = cv2.CascadeClassifier('haarcascade_eye.xml')
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),
flags=cv2.cv.CV_HAAR_SCALE_IMAGE)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
# cv2.imread('face2.jpg',1)
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# img = cv2.imread('face2.jpg',1)
# img = cv2.resize(img, (x,y), fx=0.1, fy=0.1)
# cv2.imshow('img', img)
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]
eyes = eyeCascade.detectMultiScale(roi_gray, 1.1, 2, minSize=(70, 70), flags=cv2.cv.CV_HAAR_SCALE_IMAGE)
for (x1, y1, w1, h1) in eyes:
cv2.rectangle(roi_color, (x1, y1), (x1+w1, y1+h1), (0, 0, 255), 2)
# Display the resulting frame
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()
So how can I achieve like that? Can anybody help me?
You can have the openCV script write the (x, y, w, h) to a file and the tkinter script read from that file, and then run both programs at one. Alternatively, you could run both in the same program, but display the openCV images using a tkinter canvas. I coded up the first one, it works for me.
Tkinter code
import Tkinter as tk
import time
import re
root = tk.Tk()
# Canvas to display the rectangle
w = tk.Canvas(root, width=640, height=480)
w.pack()
global rect
rect = None
def UpdateRectangle():
global rect
# Read the rectangle data
fid = open('rect.txt','r')
boundstr = fid.read()
fid.close()
tmp = tuple(int(v) for v in re.findall("[0-9]+", boundstr))
# Rearrange since bbox should be (x1, y1, x2, y2)
bbox = (tmp[0],tmp[1],tmp[0]+tmp[2],tmp[1]+tmp[3],)
# Delete old rectangle
if rect is not None:
w.delete(rect)
# Draw new one
rect = w.create_rectangle(bbox, fill='', outline='blue', width=2)
root.after(200, UpdateRectangle) # every 0.2 seconds...
UpdateRectangle()
root.mainloop()
OpenCV code
import cv2
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eyeCascade = cv2.CascadeClassifier('haarcascade_eye.xml')
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30),flags=cv2.CASCADE_SCALE_IMAGE)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
# cv2.imread('face2.jpg',1)
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# img = cv2.imread('face2.jpg',1)
# img = cv2.resize(img, (x,y), fx=0.1, fy=0.1)
# cv2.imshow('img', img)
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]
eyes = eyeCascade.detectMultiScale(roi_gray, 1.1, 2, minSize=(70, 70),flags=cv2.CASCADE_SCALE_IMAGE)
for (x1, y1, w1, h1) in eyes:
cv2.rectangle(roi_color, (x1, y1), (x1+w1, y1+h1), (0, 0, 255), 2)
# Write the rectangle data
fid = open('rect.txt','w')
rect = "%d %d %d %d" % (x, y, w, h)
fid.write(rect)
fid.close()
# Display the resulting frame
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()
See Read an image with OpenCV and display it with Tkinter ff you want to display and openCV image file in a Tkinter canvas. You can use the same root.after(command,delay) to make this canvas update as well.
Related
I have tried to use cv2.putText and it appears to show the position based on the the top right of the window and not the actual center of the image. It will probably be an obvious fix since I just started using opencv
import os
import numpy as np
font = cv2.FONT_HERSHEY_SIMPLEX
org = (50, 50)
fontScale = 1
color = (255, 0, 0)
radius = 3
thickness = 2
cascPath=os.path.dirname(cv2.__file__)+"/data/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
video_capture = cv2.VideoCapture(0)
while (True):
ret, frames = video_capture.read()
gray = cv2.cvtColor(frames, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (x, y, w, h) in faces:
cv2.rectangle(frames, (x, y), (x+w, y+h), (0, 255, 0), 2)
text = (x+w//2), (y+h//2)
cv2.circle(frames, (cx, cy), radius, (255, 0, 0), -1)
cv2.putText(frames, str(text), org, font, fontScale, color, thickness)
cv2.imshow('Video', frames)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
With the cv2.getTextSize() function, you can calculate the pixel size of the text you will put and subtract it from the text's position. In this way, the text will be right on the center.
text = (x+w//2), (y+h//2)
text_size,t = cv2.getTextSize(text=str(text), fontFace=cv2.FONT_HERSHEY_DUPLEX, fontScale=1, thickness=1)
text_size_x,text_size_y = text_size
text_pos = (x+w//2)-(text_size_x//2), (y+h//2)+(text_size_y//2)
Here is a working code
import os
import numpy as np
import cv2
font = cv2.FONT_HERSHEY_SIMPLEX
org = (50, 50)
fontScale = 1
color = (255, 0, 0)
radius = 3
thickness = 2
cascPath=os.path.dirname(cv2.__file__)+"/data/haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascPath)
video_capture = cv2.VideoCapture(0)
while (True):
ret, frames = video_capture.read()
gray = cv2.cvtColor(frames, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.CASCADE_SCALE_IMAGE
)
for (x, y, w, h) in faces:
cv2.rectangle(frames, (x, y), (x+w, y+h), (0, 255, 0), 2)
text = (x+w//2), (y+h//2)
text_size,t = cv2.getTextSize(text=str(text), fontFace=cv2.FONT_HERSHEY_DUPLEX, fontScale=1, thickness=1)
text_size_x,text_size_y = text_size
text_pos = (x+w//2)-(text_size_x//2), (y+h//2)+(text_size_y//2)
#cv2.circle(frames, (cx, cy), radius, (255, 0, 0), -1)
cv2.putText(frames, str(text), text_pos, font, fontScale, color, thickness)
cv2.imshow('Video', frames)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
I tried to use Haar cascades called haarcascade_profileface.xml and lbpcascade_profileface.xml together but the camera does not even open at all. How can I fix this issue where I want both haar cascades to work?
This is done on the raspberry pi and can also run on Linux and windows as well. Please explain as best as possible! Here is the code:
import numpy as np
import cv2
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(18,GPIO.OUT)
face_cascade = cv2.CascadeClassifier('Haarcascade_profileface.xml')
side_face_cascade = cv2.CascadeClassifier('lbpcascade_frontalface_improved.xml')
prevTime = 0
## This will get our web camera
cap = cv2.VideoCapture(0)
font = cv2.FONT_HERSHEY_SIMPLEX
while True:
retval, frame = cap.read()
if not retval:
break
_, img = cap.read() ## This gets each frame from the video, cap.read returns 2 variables flag - indicate frame is correct and 2nd is f
##img = cv2.imread('Z.png') Then we get our image we want to use
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # This method only works on gray skin images, so we have to convert the gray scale to rgb image
faces = face_cascade.detectMultiScale(gray, 1.1, 5) ## Next, we detect the faces
if len(faces) > 0:
print("[INFO] found {0} faces!".format(len(faces)))
GPIO.output(18,GPIO.HIGH)
else:
print("No face")
GPIO.output(18,GPIO.LOW)
curTime = time.time()
sec = curTime - prevTime
prevTime = curTime
fps = 1/(sec)
str = "FPS : %0.1f" % fps
for (x, y, w, h) in faces: ## We draw a rectangle around the faces so we can see it correctly
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0)) ## The faces will be a list of coordinates
cv2.putText(img, 'Myface', (x, y), font, fontScale=1, color=(255,70,120),thickness=2)
side_faces = side_face_cascade.detectMultiScale(gray, 1.1, 5)
for (ex, ey, ew, eh) in side_faces: ## We draw a rectangle around the faces so we can see it correctly
cv2.rectangle(img, (ex, ey), (ex+ew, ey+eh), (255, 0, 0)) ## The faces will be a list of coordinates
cv2.putText(img, 'Myface', (ex, ey), font, fontScale=1, color=(255,70,120),thickness=2)
cv2.putText(frame, 'Number of Faces Detected: ' + str, (0, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0))
cv2.imshow('img', img) ## Last we show the image
x = cv2.waitKey(30) & 0xff
if x==27:
break
## Press escape to exit the program
cap.release()
OpenCV actually provides a "side-face" detector. It is called 'haarcascade_profileface.xml'. You can do:
side_face_cascade = cv2.CascadeClassifier('haarcascade_profileface.xml')
side_faces = side_face_cascade.detectMultiScale(gray, 1.1, 5)
I am trying to detect the human body through OpenCV. The code throws no error. The camera also starts but it is unable to detect anything.
import cv2
classifier = cv2.CascadeClassifier(r'C:\Users\dhruv\Desktop\DataScience\haarcascade_fullbody.xml')
video_captured = cv2.VideoCapture(0)
while (True):
ret, frame = video_captured.read()
frame = cv2.resize(frame,(640,360))
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# pass the frame to the classifier
persons_detected = classifier.detectMultiScale(gray_frame)
# check if people were detected on the frame
for (x, y, w, h) in persons_detected:
cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Video footage', frame)
if (cv2.waitKey(1) & 0xFF == ord('q')):
break
#cv2.VideoCapture(0).release()
I highly suspect its an indentation error. The camera does start, but your code to draw the bounding boxes of the faces are outside of the loop. Just indent that code. In addition, you'll need to free the camera resource properly or the next time you run the code, the camera will not be able to capture frames properly. I've changed the release call so that it releases the grabbed resource.
import cv2
classifier = cv2.CascadeClassifier(r'C:\Users\dhruv\Desktop\DataScience\haarcascade_fullbody.xml')
video_captured = cv2.VideoCapture(0)
while True:
ret, frame = video_captured.read()
frame = cv2.resize(frame,(640,360))
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# pass the frame to the classifier
persons_detected = classifier.detectMultiScale(gray_frame)
# check if people were detected on the frame
for (x, y, w, h) in persons_detected:
cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Video footage', frame)
if (cv2.waitKey(1) & 0xFF == ord('q')):
break
video_captured.release() # Changed so that you're releasing the grabbed resource
I am detecting a face from the camera and draw a rectangle around it.
Code below:
face_cascade = cv2.CascadeClassifier('face_classifier.xml')
def detect(gray, frame):
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in stops: # For each detected face:
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
return frame
video_capture = cv2.VideoCapture(0)
while True:
_, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
canvas = detect(gray, frame)
cv2.imshow('Video', canvas)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
Are there any functions in OpenCV that can print text?
When it detects a face on the screen say "Hi"?
Thank you for your time.
Should have done this first before asking the question but after some Googling and trying out a few things, here is the solution:
face_cascade = cv2.CascadeClassifier('face_classifier.xml')
def detect(gray, frame):
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in stops: # For each detected face:
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
font = cv2.FONT_HERSHEY_COMPLEX_SMALL
cv2.putText(frame,'Hello There!',(x+w, h),font, 0.8,(255,0,0),2,cv2.LINE_AA)
return frame
video_capture = cv2.VideoCapture(0)
while True:
_, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
canvas = detect(gray, frame)
cv2.imshow('Video', canvas)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
This will add "Hello There!" to the top right corner of the detection frame rectangle.
I'm trying to create a aplication with opencv that overlaps a glass on me face. However, when the video appears the glasses have a black on the alpha layer. Here is my code:
video_capture = cv2.VideoCapture(0)
anterior = 0
glasses = cv2.imread('Glasses_1.png')
def put_glasses(glasses,fc,x,y,w,h):
face_width = w
face_height = h
glasses_width = int(face_width)
glasses_height = int(face_height*0.32857)
glasses = cv2.resize(glasses,(glasses_width,glasses_height))
for i in range(glasses_height):
for j in range(glasses_width):
for k in range(3):
if glasses[i][j][k]<235:
fc[y+i-int(-0.25*face_height)-1][x+j][k] = glasses[i][j][k]
return fc
while True:
if not video_capture.isOpened():
print('Unable to load camera.')
sleep(5)
pass
ret, frame = video_capture.read()
if ret is True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
else:
continue
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(40,40)
)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(frame,"Person Detected",(x,y),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),2)
frame = put_glasses(glasses, frame, x, y, w, h)
I will be very grateful if anyone could help.
You read the png in bgr format, not the bgra or unchanged format. Then I don't think your glass image in the program is shape of (h,w,4). You should read with flag cv2.IMREAD_UNCHANGED.
glasses = cv2.imread("xxx.png", cv2.IMREAD_UNCHANGED)
Maybe this link will help. How do I clear a white background in OpenCV with c++?
The bgra worm:
Blending: