Skip to content

Instantly share code, notes, and snippets.

@smeschke
Last active April 6, 2024 21:17
Show Gist options
  • Save smeschke/e59a9f5a40f0b0ed73305d34695d916b to your computer and use it in GitHub Desktop.
Save smeschke/e59a9f5a40f0b0ed73305d34695d916b to your computer and use it in GitHub Desktop.
Detection of Head Nods using OpenCV in Python
import cv2
import numpy as np
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('/home/sm/Desktop/nodcontrol.avi',fourcc, 20.0, (640,480))
#dinstance function
def distance(x,y):
import math
return math.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2)
#capture source video
cap = cv2.VideoCapture(0)
#params for ShiTomasi corner detection
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# Parameters for lucas kanade optical flow
lk_params = dict( winSize = (15,15),
maxLevel = 2,
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
#path to face cascde
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
#function to get coordinates
def get_coords(p1):
try: return int(p1[0][0][0]), int(p1[0][0][1])
except: return int(p1[0][0]), int(p1[0][1])
#define font and text color
font = cv2.FONT_HERSHEY_SIMPLEX
#define movement threshodls
max_head_movement = 20
movement_threshold = 50
gesture_threshold = 175
#find the face in the image
face_found = False
frame_num = 0
while not face_found:
# Take first frame and find corners in it
frame_num += 1
ret, frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(frame_gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
face_found = True
cv2.imshow('image',frame)
out.write(frame)
cv2.waitKey(1)
face_center = x+w/2, y+h/3
p0 = np.array([[face_center]], np.float32)
gesture = False
x_movement = 0
y_movement = 0
gesture_show = 60 #number of frames a gesture is shown
while True:
ret,frame = cap.read()
old_gray = frame_gray.copy()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
cv2.circle(frame, get_coords(p1), 4, (0,0,255), -1)
cv2.circle(frame, get_coords(p0), 4, (255,0,0))
#get the xy coordinates for points p0 and p1
a,b = get_coords(p0), get_coords(p1)
x_movement += abs(a[0]-b[0])
y_movement += abs(a[1]-b[1])
text = 'x_movement: ' + str(x_movement)
if not gesture: cv2.putText(frame,text,(50,50), font, 0.8,(0,0,255),2)
text = 'y_movement: ' + str(y_movement)
if not gesture: cv2.putText(frame,text,(50,100), font, 0.8,(0,0,255),2)
if x_movement > gesture_threshold:
gesture = 'No'
if y_movement > gesture_threshold:
gesture = 'Yes'
if gesture and gesture_show > 0:
cv2.putText(frame,'Gesture Detected: ' + gesture,(50,50), font, 1.2,(0,0,255),3)
gesture_show -=1
if gesture_show == 0:
gesture = False
x_movement = 0
y_movement = 0
gesture_show = 60 #number of frames a gesture is shown
#print distance(get_coords(p0), get_coords(p1))
p0 = p1
cv2.imshow('image',frame)
out.write(frame)
cv2.waitKey(1)
cv2.destroyAllWindows()
cap.release()
@TRIPATHISOMYA
Copy link

I am getting error
[ERROR:0] global /io/opencv/modules/videoio/src/cap.cpp (392) open VIDEOIO(CV_IMAGES): raised OpenCV exception:

OpenCV(4.1.2) /io/opencv/modules/videoio/src/cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): /home/sm/Desktop/nodcontrol.avi in function 'icvExtractPattern'

VIDEOIO ERROR: V4L: can't find camera device
Traceback (most recent call last):
File "nods.py", line 49, in
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.1.2) /io/opencv/modules/imgproc/src/color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'

@smeschke
Copy link
Author

@TRIPATHISOMYA

You need to plug a webcam into your computer. If you don't want to use a webcam, you can change the path in line 13 to a video that is saved on your hard drive.

@TRIPATHISOMYA
Copy link

TRIPATHISOMYA commented Dec 23, 2019 via email

@DiAble19
Copy link

Excuse me, but i have a problem with code line 57th.
The output is " name 'x' is not defined". But sometime, it's still run oke.
Hope you answer. Thank you!

@smeschke
Copy link
Author

smeschke commented May 20, 2020

Excuse me, but i have a problem with code line 57th.
The output is " name 'x' is not defined". But sometime, it's still run oke.
Hope you answer. Thank you!

I have updated the code, it should work now. Before it looked for a face for 30 frames. If a face was not found in the first 30 frames, the code would crash. I changed the code, so that now it looks for a face until a face is found.

Once a face is found, the center of the face is found, and the tracker is initialized. Then the nod detection can begin.

@DiAble19
Copy link

Excuse me, but i have a problem with code line 57th.
The output is " name 'x' is not defined". But sometime, it's still run oke.
Hope you answer. Thank you!

I have updated the code, it should work now. Before it looked for a face for 30 frames. If a face was not found in the first 30 frames, the code would crash. I changed the code, so that now it looks for a face until a face is found.

Once a face is found, the center of the face is found, and the tracker is initialized. Then the nod detection can begin.

Thank you so much for your help !

@gbmamat
Copy link

gbmamat commented Jun 26, 2021

Dear @smeschke,

How to use your program with video input instead webcam?

@deanthebeandip
Copy link

Dear @smeschke,

How to use your program with video input instead webcam?

Instead of
cap = cv2.VideoCapture(0)
Just use
cap = cv2.VideoCapture("path/to/folder/video.mp4")

You'll also need to download the xml file:
haarcascade_frontalface_alt.xml

You can download it and move it into current directory

@amritbhat786
Copy link

Hi @smeschke, thanks for sharing this gist! Can you comment on the accuracy of this on different possibilities of the nod gesture (like from a stress test)? Also what is the minimum system configuration to run this code? Thanks!

@jhayush0502
Copy link

Hello Geeks,

Please anyone help me out in resolving this issue

[ERROR:0@0.425] global cap.cpp:597 cv::VideoWriter::open VIDEOIO(CV_IMAGES): raised OpenCV exception:

OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\videoio\src\cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): /home/sm/Desktop/nodcontrol.avi in function 'cv::icvExtractPattern'


[ERROR:0@3.320] global persistence.cpp:505 cv::FileStorage::Impl::open Can't open file: 'haarcascade_frontalface_alt.xml' in read mode
Traceback (most recent call last):
  File "D:\HMI\PythonBased\HeadNodding\NoddingDetection.py", line 50, in <module>
    faces = face_cascade.detectMultiScale(frame_gray, 1.3, 5)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\objdetect\src\cascadedetect.cpp:1689: error: (-215:Assertion failed) !empty() in function 'cv::CascadeClassifier::detectMultiScale'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment