Using Jevois to detect hands

Posted on March 13, 2018

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!")

 

None