Here is the code I used to detect hands in front of a static background. I used this one to control the generated music in this project. I might post a tutorial later.
Actually, this code can detect any object that is not in the background. Also, you can learn how to control a Jevois module with commands and how to pass information to serial.
import libjevois as jevois
import cv2
import numpy as np
class dynamic_stat(object):
def __init__(self, init=None, gamma=0.9):
self.value = init
self.gamma = 0.9
def update(self, v):
if self.value is None:
self.value = v
else:
self.value = self.gamma * self.value + \
(1-self.gamma) * v
return self.value
class gr2:
def __init__(self):
# A simple frame counter used to demonstrate sendSerial():
self.frame = 0
# Instantiate a JeVois Timer to measure our processing framerate:
self.timer = jevois.Timer("canny", 100, jevois.LOG_INFO)
self.threshold = 200
self.blur_r = 15
self.bg = None
self.blur_function = cv2.blur
self.pos = (0, 0)
# def process(self, inframe):
# jevois.LFATAL("process no usb not implemented")
def _contour(self, img):
drawing = np.zeros(img.shape, np.uint8)
try:
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(
grey, (35, 35), 2)
# thresholdin: Otsu's Binarization method
_, thresh1 = cv2.threshold(blurred, 127, 255,
cv2.THRESH_OTSU)
# find contour with max area
_, contours, _ = \
cv2.findContours(thresh1.copy(),
cv2.RETR_TREE,
cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=lambda x: cv2.contourArea(x))
(x, y), radius = cv2.minEnclosingCircle(cnt)
hull = cv2.convexHull(cnt)
self.pos = (int(x), int(y))
# drawing contours
drawing[:, :, :] = thresh1[:, :, None]
cv2.drawContours(drawing, [cnt], 0, (0, 255, 0), 0)
cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 0)
cv2.circle(drawing, self.pos, int(radius),
(255, 0, 0), 2)
except:
pass
return drawing
def process(self, inframe, outframe):
img = inframe.getCvBGR()
height, width, chans = img.shape
# self.timer.start()
if self.bg is None:
self.bg = self.blur_function(
img.copy(), (self.blur_r, self.blur_r), 2)
diff = self.blur_function(
img.copy(), (self.blur_r, self.blur_r), 2)-self.bg
diff = (diff**2).sum(2)
cut = img*(diff > self.threshold)[:, :, None]
drawing = self._contour(cut.copy())
# fps = self.timer.stop()
# cv2.putText(cut, fps, (0, 0),
# cv2.FONT_HERSHEY_SIMPLEX, 2,
# (255, 0, 0))
# cv2.putText(cut, str(self.pos), (0, 0),
# cv2.FONT_HERSHEY_SIMPLEX, 2,
# (255, 0, 0))
display = np.hstack([img, cut, drawing])
outframe.sendCvBGR(display)
self.frame += 1
def parseSerial(self, str):
print("parseserial received command [{}]".format(str))
if str == "hello":
return self.hello()
if str == "reset":
self.bg = None
return "Reset background"
if str.startswith('blur'):
r = int(str[4:])
self.blur = r
return "set blur radius to", self.blur
if str.startswith('threshold'):
r = int(str[9:])
self.threshold = r
return "set threshold to", self.threshold
if str == 'fetch':
# Send a string over serial (e.g., to an Arduino).
# Remember to tell the JeVois Engine to display those messages,
s = "{}|{}".format(self.pos[0], self.pos[1])
# jevois.sendSerial(s)
return s
return "ERR: Unsupported command"
def supportedCommands(self):
# use \n seperator if your module supports several commands
return '''
hello - print hello using python
reset - reset the background
blurN - set the blur radius to (N, N)
thresholdN - set threshold to N
fetch - get position
'''
def hello(self):
return("Hello from python!")