OpenCV Home Assistant

Hi,

I decided to make a tutorial to include OpenCV with HA.
My work is based on this website : http://www.tundra-it.com/fr/raspberry-pi-reconocimiento-facial/ (thanks to the author)

To begin you need to install these modules and dependencies
sudo apt-get install build-essential cmake pkg-config python-dev libgtk2.0-dev libgtk2.0 zlib1g-dev libpng-dev libjpeg-dev libtiff-dev libjasper-dev libavcodec-dev swig unzip vim sudo apt-get install python-numpy python-opencv sudo apt-get install python-pip sudo apt-get install python-dev sudo pip install picamera sudo pip install rpio sudo apt-get install v4l2ucp v4l-utils libv4l-dev

No need to compile OpenCV. (sudo apt-get install opencv)

so, after that you need to get the sources and data
mkdir /home/pi/recoFacial cd /home/pi/recoFacial wget http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip unzip att_faces.zip wget http://www.bujarra.com/wp-content/uploads/2016/08/haarcascade_frontalface_alt.zip unzip haarcascade_frontalface_alt.zip

There is 2 scripts, i modified them to be more adapted to HA.
The first script is capture.py

size = 4
fn_haar = 'haarcascade_frontalface_alt.xml'
fn_dir = 'person'
fn_name = sys.argv[1]
path = os.path.join(fn_dir, fn_name)
if not os.path.isdir(path):
    os.mkdir(path)
(im_width, im_height) = (112, 92)
haar_cascade = cv2.CascadeClassifier(fn_haar)
webcam = cv2.VideoCapture(0)

count = 0
while count < 100:
    (rval, im) = webcam.read()
    im = cv2.flip(im, 1, 0)
    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    mini = cv2.resize(gray, (gray.shape[1] / size, gray.shape[0] / size))
    faces = haar_cascade.detectMultiScale(mini)
    faces = sorted(faces, key=lambda x: x[3])
    if faces:
        face_i = faces[0]
        (x, y, w, h) = [v * size for v in face_i]
        face = gray[y:y + h, x:x + w]
        face_resize = cv2.resize(face, (im_width, im_height))
        pin=sorted([int(n[:n.find('.')]) for n in os.listdir(path)
               if n[0]!='.' ]+[0])[-1] + 1
        cv2.imwrite('%s/%s.png' % (path, pin), face_resize)
        cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 3)
        cv2.putText(im, fn_name, (x - 10, y - 10), cv2.FONT_HERSHEY_PLAIN,
            1,(0, 255, 0))
        count += 1
    cv2.imshow('OpenCV', im)
    key = cv2.waitKey(10)
    if key == 27:
        break

You need to create a directory “person”.
Every person which will be create, will appear in it.

Now you can create a first person like that:
python capture.py nameperson

(eg : python capture.py johndoe)

The script will take 100 photos to learn your face (the number can be changed).

I need to take me another time to success, with a another name (and glasses).
It’s strange but if i had only one person, the recognition script was bugged…

Finally the second script reco.py

size = 4
fn_haar = 'haarcascade_frontalface_alt.xml'
fn_dir = 'person'
print('...Preparing...')
(images, lables, names, id) = ([], [], {}, 0)
for (subdirs, dirs, files) in os.walk(fn_dir):
    for subdir in dirs:
        names[id] = subdir
        subjectpath = os.path.join(fn_dir, subdir)
        for filename in os.listdir(subjectpath):
            path = subjectpath + '/' + filename
            lable = id
            images.append(cv2.imread(path, 0))
            lables.append(int(lable))
        id += 1
(im_width, im_height) = (112, 92)
(images, lables) = [numpy.array(lis) for lis in [images, lables]]
model = cv2.createFisherFaceRecognizer()
model.train(images, lables)
haar_cascade = cv2.CascadeClassifier(fn_haar)
webcam = cv2.VideoCapture(0)
while True:
    (rval, frame) = webcam.read()
    frame=cv2.flip(frame,1,0)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    mini = cv2.resize(gray, (gray.shape[1] / size, gray.shape[0] / size))
    faces = haar_cascade.detectMultiScale(mini)
    for i in range(len(faces)):
        face_i = faces[i]
        (x, y, w, h) = [v * size for v in face_i]
        face = gray[y:y + h, x:x + w]
        face_resize = cv2.resize(face, (im_width, im_height))
        prediction = model.predict(face_resize)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
        if prediction[1] < 500:
          cv2.putText(frame,
          '%s - %.0f' % (names[prediction[0]],prediction[1]),
          (x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
          cara = '%s' % (names[prediction[0]])
          if cara == "johndoe":
            cv2.imwrite ("detection.jpg",frame)
          elif cara == "autre":
            # Do nothing
          else:
             cv2.putText(frame,
                  'Inconnu',
                   (x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
             #Load Webcam with 
             cv2.imshow('OpenCV', frame)
             key = cv2.waitKey(10)
   
             if key == 27:
               break

you could to give execution rights to the scripts.
chmod +x reco.py capture.py

And execute reco.py

to operate with HA, you can write file like that :slight_smile:

file.open ("detection.txt",w)
(...)
        if prediction[1] < 500:
          cv2.putText(frame,
          '%s - %.0f' % (names[prediction[0]],prediction[1]),
          (x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
          cara = '%s' % (names[prediction[0]])
          if cara == "johndoe":
            cv2.imwrite ("detection.jpg",frame)
            file.write ("johndoe")
          elif cara == "autre":
            # Do nothing
          else:
             cv2.putText(frame,
                  'Inconnu',
                   (x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
             #Load Webcam with 
             file.write ("nobody")
             cv2.imshow('OpenCV', frame)
             key = cv2.waitKey(10)
             if key == 27:
               break
        file.close()

And a sensor from HA which do that :slight_smile:
cat detection.txt

And an automation which execute order when sensor state become “johndoe” from “nobody”

That works fine, but on raspberry 3 it’s too slow, i’ll try to install that on a real server to test performance soon…

8 Likes

Thanks for sharing. But what does it do exactly? Face detection or face recognition?

1 Like

Face recognition of course :wink:

for me face detection is useless, perhaps to count the number of person ^^

I decided to implement that because the Microsoft solution is not good for me (number call limited to API, need an external provider…)

That’s great. I’m looking for alternatives to Microsoft too. Don’t feel comfortable relying too much on services in the cloud.

However you mentioned that it’s too slow on Raspberry Pi 3. Is it possible to install this on my more powerful Synology NAS but maintain the HA in my Pi?

1 Like

Yes,

I bought a DELL T20 (Xeon 4 cores), installed ESXi, and created some VM.
I have now a VM DSM 6.0 Synology with many docker containers on it :stuck_out_tongue: and 2 VM ubuntu 64bits.

  • The first VM Ubuntu runs Home Assistant
  • The second VM Ubuntu will run OpenCV and (perhaps Motion which run now on a RPI2).

With a samba mount between VM HA and VM OpenCV, HA is able to read the generated file by OpenCV.

1 Like

Actually not that obvious to most of us - it might be a good idea to include a quick paragraph about what it does and a link to the OpenCV site. Also, since that links in French, it might be a good idea to note that and state that the site has translations as well.

Thanks for sharing this!

I see. But your steps are too advance for me. So which step goes to the powerful server and which one goes to the Raspberry Pi that runs HA?

Hi @rpitera

Yes i am agrre with you.
I mixed some tutorials to aim my goal, and some tutorial…

I have no time to develop a Home assistant component with that … sadly, but perhaps someone (with python skill could develop that … this is my secret wish :stuck_out_tongue: )

I will try to test that, on a powerful server to validate this POC.

and after i’ll get you a feedback to explain the different step.

2 Likes

You never know; a lot of times someone will look at a project here and say, “Wow I could really use that, maybe I should do X and Y and make this into a pull request!”

It’s always nice, no matter at what level, that you shared what you found and I appreciate it!

@masterkenobi

To me, OpenCV with vision compute must to be on a powerful server.
All the solution that i briefly described must be on the powerful server.

This solution create a file txt
file.open (“detection.txt”,w)
file.write (“johndoe”)

the file must be visible to HA server (with samba share).

So HA will have just a sensor to read file generated :stuck_out_tongue:

I guess this is a sensor component that is yet to exist.

Yes an example could be

- platform: command_line name: facedetect command: "cat /home/pi/.homeassistant/www/partage/presence.txt"

with a samba_share named partage :stuck_out_tongue:

I have made a custom sensor for image classification here: https://github.com/Danielhiversen/home-assistant_config/blob/master/custom_components/binary_sensor/ml.py

It uses sklearn and KNeighborsClassifier, but it could easily be changed to use OpenCV or something else.

2 Likes

Hi,

So i try to finalize this project … it’s not so easy …
I can’t use my webcam with ESXi, i get some errors …

So i think the best solution will be to use stream video produced by webcam themselves…

I got this code :

import urllib 
import numpy as np

stream=open('http://webcam_ip:port/webcam.mjpeg','rb')
bytes=''
while True:
    bytes+=stream.read(1024)
    a = bytes.find('\xff\xd8')
    b = bytes.find('\xff\xd9')
    if a!=-1 and b!=-1:
        jpg = bytes[a:b+2]
        bytes= bytes[b+2:]
        i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),cv2.CV_LOAD_IMAGE_COLOR)
        cv2.imshow('i',i)
        if cv2.waitKey(1) ==27:
            exit(0)

The goal will be to combine the 2 codes, to use a stream from a webcam.

I’ll continue to search a solution as soon as i have some time :stuck_out_tongue:

I have a problem in my recognize python script, HA polls the state of sensors (via the file created), but the file change too quickly… i try to add a scan_interval: 1 for the sensor but sadly it’s not operational for now…

This is an example with the detected snapshot on HA

If someone is motivated …

Ok i success to do that working :slight_smile:

So the good script reco.py (to recognize people) is

import cv2, sys, numpy, os, time
size = 4
fn_haar = 'haarcascade_frontalface_alt.xml'
fn_dir = '/home/pi/face/person/'
print('Preparation...')
(images, lables, names, id) = ([], [], {}, 0)
for (subdirs, dirs, files) in os.walk(fn_dir):
    for subdir in dirs:
        names[id] = subdir
        subjectpath = os.path.join(fn_dir, subdir)
        for filename in os.listdir(subjectpath):
            path = subjectpath + '/' + filename
            lable = id
            images.append(cv2.imread(path, 0))
            lables.append(int(lable))
        id += 1
(im_width, im_height) = (112, 92)
(images, lables) = [numpy.array(lis) for lis in [images, lables]]
model = cv2.createFisherFaceRecognizer()
model.train(images, lables)
haar_cascade = cv2.CascadeClassifier(fn_haar)
webcam = cv2.VideoCapture(0)
print("-_Ready_-")
while True:
    (rval, frame) = webcam.read()
    frame=cv2.flip(frame,1,0)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    mini = cv2.resize(gray, (gray.shape[1] / size, gray.shape[0] / size))
    faces = haar_cascade.detectMultiScale(mini)
    file = open("presence.txt","w")
    for i in range(len(faces)):
        face_i = faces[i]
        (x, y, w, h) = [v * size for v in face_i]
        face = gray[y:y + h, x:x + w]
        face_resize = cv2.resize(face, (im_width, im_height))
        prediction = model.predict(face_resize)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
        if prediction[1] < 500:
          cara = '%s' % (names[prediction[0]])
          if cara == "arnaud":
            cv2.putText(frame,"Arnaud",(x+10, y+10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
            cv2.imwrite("facecam.jpg",frame)
            file.write("arnaud")
            file.close()
            time.sleep (4)
          elif cara == "arno":
            cv2.putText(frame,"Arnaud",(x+10, y+10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
            cv2.imwrite("facecam.jpg",frame)
            file.write("arnaud")
            file.close()
            time.sleep (4)
          else:
            cv2.putText(frame,"Inconnu",(x+10, y+10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
            cv2.imwrite("facecam.jpg",frame)
            file.write("inconnu")
            #file.close()
            time.sleep(4)
            key = cv2.waitKey(10)
            if key == 27:
              break
        else:
          file.write("rien")
          key = cv2.waitKey(10)
          if key == 27:
            break
          file.close()

    key = cv2.waitKey(10)
    if key == 27:
      break
    file.close()

In polling the file presence.txt Ha detect me and lights my room on :smile:
I have always a problem for the case inconnu (unknown) …
but in this state you could add many people
to do that

python capture.py jessicaalba

in duplicating this part in the script

          elif cara == "jessicaalba":
            cv2.putText(frame,"Jessica Alba",(x+10, y+10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
            cv2.imwrite("facecam.jpg",frame)
            file.write("jessica alba")
            file.close()
            time.sleep (4)

the value “jessicaalba” corresponding to the name used with the capture.py

This POC works on a RPI3 so it’s enough to detect someone.

The solution works but it’s not completly fonctionnal … i can’t recognize unknown people, and it’s a little bit slow …
I begin to do some research with OpenFace, i think it’s more efficient … if someone knows that, i’m open to listen :slight_smile:

OpenFace is a free implementation from the google’s Facial compute vision(Google photos, …).

I have tried home_surveillance which is based on openface last month. It is somewhat accurate but not accurate enough to use in any real automations. It detects features and shadows as people. My placing of the camera may have contributed.

I don’t know this solution.
I’ll try it.

thanks for idea …

Can anyone here explain how the file format for open cv works, I am new and trying to work my way to extablish face recognition.

Thanks…

do you know if the OPENCV integration can detect more than 1 classifier ?
… i’ve sucesful intealled the OPENCV in my HASSIO, and it detects face (few false positives) , full body (not always detecting positives) and upperbody (several positives that are not posite).
My raspeberry PI 3b is collecting the images from 2 old mobiles cameras with streaming service, but it just detects one classifier and not 2 at the same time (face + upperbody)

is this a bug or a bad implementation ?

my YAML:


image_processing:
  - platform: opencv
    source:
      - entity_id: camera.cctv
      - entity_id: camera.cctv2
    classifier:
      corpo: ./Opencv/haarcascade_fullbody.xml
      cara: ./Opencv/haarcascade_frontalface_default.xml
      upperbody: ./Opencv/haarcascade_upperbody.xml