Peter Ma
Published © LGPL

Walabot AI Deadbolt

Using AI to train face recognition through UP2 board, Intel Movidius NCS, and Walabot radar to add extra security.

ExpertFull instructions provided3 days8,671

Things used in this project

Story

Read more

Custom parts and enclosures

Up2 board for AI

Up2 board for AI

Schematics

Up2 Block Diagram

Up2 Block Diagram

Code

train lmdb

Python
Training LMDB for your face
import os
import glob
import random
import numpy as np

import cv2

import caffe
from caffe.proto import caffe_pb2
import lmdb

#Size of images
IMAGE_WIDTH = 227
IMAGE_HEIGHT = 227

def transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT):

    #Histogram Equalization
    img[:, :, 0] = cv2.equalizeHist(img[:, :, 0])
    img[:, :, 1] = cv2.equalizeHist(img[:, :, 1])
    img[:, :, 2] = cv2.equalizeHist(img[:, :, 2])

    #Image Resizing
    img = cv2.resize(img, (img_width, img_height), interpolation = cv2.INTER_CUBIC)

    return img


def make_datum(img, label):
    #image is numpy.ndarray format. BGR instead of RGB
    return caffe_pb2.Datum(
        channels=3,
        width=IMAGE_WIDTH,
        height=IMAGE_HEIGHT,
        label=label,
        data=np.rollaxis(img, 2).tostring())

train_lmdb = '/home/ubuntu/face_training/input/train_lmdb'
validation_lmdb = '/home/ubuntu/face_training/input/validation_lmdb'

os.system('rm -rf  ' + train_lmdb)
os.system('rm -rf  ' + validation_lmdb)


train_data = [img for img in glob.glob("../input/train/*jpg")]
test_data = [img for img in glob.glob("../input/test1/*jpg")]

#Shuffle train_data
random.shuffle(train_data)

print 'Creating train_lmdb'

in_db = lmdb.open(train_lmdb, map_size=int(1e12))
with in_db.begin(write=True) as in_txn:
    for in_idx, img_path in enumerate(train_data):
        if in_idx %  6 == 0:
            continue
        img = cv2.imread(img_path, cv2.IMREAD_COLOR)
        img = transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT)
        if '{your_name}' in img_path:
            label = 0
        else:
            label = 1
        datum = make_datum(img, label)
        in_txn.put('{:0>5d}'.format(in_idx), datum.SerializeToString())
        print '{:0>5d}'.format(in_idx) + ':' + img_path
in_db.close()


print '\nCreating validation_lmdb'

in_db = lmdb.open(validation_lmdb, map_size=int(1e12))
with in_db.begin(write=True) as in_txn:
    for in_idx, img_path in enumerate(train_data):
        if in_idx % 6 != 0:
            continue
        img = cv2.imread(img_path, cv2.IMREAD_COLOR)
        img = transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT)
        if '{your_name}' in img_path:
            label = 0
        else:
            label = 1
        datum = make_datum(img, label)
        in_txn.put('{:0>5d}'.format(in_idx), datum.SerializeToString())
        print '{:0>5d}'.format(in_idx) + ':' + img_path
in_db.close()

print '\nFinished processing all images'

Amazon Lamdba Code for Alexa

JavaScript
This is the code used in Amazon Lamdba for Alexa
'use strict';
var http = require('https'); 

exports.handler = function (event, context) {
    try {
        console.log("event.session.application.applicationId=" + event.session.application.applicationId);

        /**
         * Uncomment this if statement and populate with your skill's application ID to
         * prevent someone else from configuring a skill that sends requests to this function.
         */
		 
     if (event.session.application.applicationId !== "{Your Application Id}") {
         context.fail("Invalid Application ID");
      }

        if (event.session.new) {
            onSessionStarted({requestId: event.request.requestId}, event.session);
        }

        if (event.request.type === "LaunchRequest") {
            onLaunch(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === "IntentRequest") {
            onIntent(event.request,
                event.session,
                function callback(sessionAttributes, speechletResponse) {
                    context.succeed(buildResponse(sessionAttributes, speechletResponse));
                });
        } else if (event.request.type === "SessionEndedRequest") {
            onSessionEnded(event.request, event.session);
            context.succeed();
        }
    } catch (e) {
        context.fail("Exception: " + e);
    }
};

/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log("onSessionStarted requestId=" + sessionStartedRequest.requestId
        + ", sessionId=" + session.sessionId);

    // add any session init logic here
}

/**
 * Called when the user invokes the skill without specifying what they want.
 */
function onLaunch(launchRequest, session, callback) {
    console.log("onLaunch requestId=" + launchRequest.requestId
        + ", sessionId=" + session.sessionId);

    var cardTitle = "Welcome to AI Face Lock"
    var speechOutput = "Welcome to AI Face Lock"
    callback(session.attributes,
        buildSpeechletResponse(cardTitle, speechOutput, "", true));
}

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId
        + ", sessionId=" + session.sessionId);

    var intent = intentRequest.intent,
        intentName = intentRequest.intent.name;

    // dispatch custom intents to handlers here
    if (intentName == 'AILockIntent') {
        handleTrackRequest(intent, session, callback);
    }
    else {
        throw "Invalid intent";
    }
}

/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log("onSessionEnded requestId=" + sessionEndedRequest.requestId
        + ", sessionId=" + session.sessionId);

    // Add any cleanup logic here
}

function handleTrackRequest(intent, session, callback) {
    var url = "{Your own URL}/?AccountId=" + session.user.userId; //you can use your own
                http.get(url, function(res){ 
                    res.setEncoding('utf8');
                    res.on('data', function (chunk) {
                        console.log('BODY: ' + chunk);
                        var chunk = JSON.parse(chunk);
                        if(parseInt(chunk.faceid) == 0)
                        {
                            callback(session.attributes, buildSpeechletResponseWithoutCard("Face lock doesn't see Peter around", "", "true"));
                        }
                        else if (parseInt(chunk.distance) == 0 || parseInt(chunk.breahting) == 0)
                        {
                            callback(session.attributes, buildSpeechletResponseWithoutCard("Walabot is not detecting people's presence", "", "true"));
                        }
                        else
                        {   
                            var urlalexa = "{Your own URL}/alexa/?AccountId=" + session.user.userId; //you can use your own
                            http.get(urlalexa, function(res1){ 
                                res1.setEncoding('utf8');
                                res1.on('data', function (chunk1) {
                                    console.log('BODY: ' + chunk1);
                                })})
                            callback(session.attributes, buildSpeechletResponseWithoutCard("Unlocking deadbolt...", "", "true"));
                        }

                    })
                }).on('error', function (e) { 
                        callback(session.attributes, buildSpeechletResponseWithoutCard("There was a problem Connecting to your AI Lock", "", "true"));
                })
    //callback(session.attributes, buildSpeechletResponseWithoutCard("test", "", "true"));
}

// ------- Helper functions to build responses -------

function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
        card: {
            type: "Simple",
            title: title,
            content: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildSpeechletResponseWithoutCard(output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: "1.0",
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    };
}

Server Unlock Code

JavaScript
This is the code used by your node.js server
const express = require('express')
const path = require('path')
const PORT = process.env.PORT || 5000
var fs = require('fs');
var PubNub = require('pubnub')
var app = express()
var http = require("http");
setInterval(function() {
   http.get("{your own server}/test");
}, 300000);
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
        var accountId = req.query.accountId;
	fs.readFile(accountId
	    if (err){
	        console.log(err);
	    } else {
	    obj = JSON.parse(data); //now it an object
	    res.send(JSON.stringify(obj));
	}});	
})
app.get('/test', function (req, res) {
	/*
	fs.readFile(accountId
	    if (err){
	        console.log(err);
	    } else {
	    obj = JSON.parse(data); //now it an object
	    res.send(JSON.stringify(obj));
	}});*/
	res.send("200");
})
app.get('/input', function (req, res) 
{	var fs = require('fs');
	var faceid = req.query.faceid;
	var distance = req.query.distance;
	var breathing = req.query.breathing;
        var accountId = req.query.accountId;
	fs.readFile(accountId
	    if (err){
	        console.log(err);
	    } else {
	    obj = JSON.parse(data); //now it an object
	    obj.faceid += parseInt(faceid);
	    obj.distance += parseInt(distance); //add some data
	    obj.breathing += parseInt(breathing); //add some data
	    json = JSON.stringify(obj); //convert it back to json
	    fs.writeFile(accountId
	    fs.readFile('alexa"
		    if (err){
		        console.log(err);
		    } else {
		    obj = JSON.parse(data); //now it an object
		    json = JSON.stringify(obj); //convert it back to json
		    res.send(json) 
		}});
	}});
})
app.get('/alexa', function (req, res) 
{	var fs = require('fs');
        accountId = req.query.accountId;
	var alexa = 1;
	fs.readFile('alexa"
	    if (err){
	        console.log(err);
	    } else {
	    obj = JSON.parse(data); //now it an object
	    obj.alexa = 1;
	    json = JSON.stringify(obj); //convert it back to json
	    fs.writeFile('alexa.txt', json, 'utf8', null); // write it back
		setTimeout(function() {
			//Reset back to lock mode after 10 seconds, enough for client side to unlock
			var obj = new Object()
		    obj.alexa = 0;
			json = JSON.stringify(obj); //convert it back to json
	    	fs.writeFile('alexa"
		}, 10000);
	    res.send('success') 
	}});
})

app.get('/alexafalse', function (req, res) 
{	var fs = require('fs');
	var alexa = 1;
	fs.readFile('alexa.txt', 'utf8', function readFileCallback(err, data){
	    if (err){
	        console.log(err);
	    } else {
	    obj = JSON.parse(data); //now it an object
	    obj.alexa = 2;
	    json = JSON.stringify(obj); //convert it back to json
	    fs.writeFile('alexa.txt', json, 'utf8', null); // write it back
		setTimeout(function() {
			//Reset back to lock mode after 10 seconds, enough for client side to unlock
			var obj = new Object()
		    obj.alexa = 0;
			json = JSON.stringify(obj); //convert it back to json
	    	fs.writeFile('alexa.txt', json, 'utf8', null); // write it back
		}, 5000);
	    res.send('success') 
	}});
})

app.listen(PORT, () => console.log(`Listening on ${ PORT }`))

Arduino Lock Code

C/C++
This is part for Arduino to control the lock because the Grove shield on Up2 isn't outputting enough ampage for the relay.
const int ledPin =  7;      // the number of the LED pin
int incomingByte = 0;   // for incoming serial data


void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
}

void loop() {
          // send data only when you receive data:
        if (Serial.available() > 0) {
                // read the incoming byte:
                incomingByte = Serial.read();
           if(incomingByte == 48)
           {
            digitalWrite(ledPin, LOW);
           }
           else if(incomingByte == 49)
           {
            digitalWrite(ledPin, HIGH);
           }
                // say what you got:
                Serial.print("I received: ");
                Serial.println(incomingByte, DEC);
        }
}

Deadbolt testing code

Python
Deadbolt testing code connecting from Up2 to Arduino
import mraa
import time
import sys
mraa.addSubplatform(mraa.GROVEPI,"0")
# serial port
port = "/dev/ttyACM0"
data_on = "1"
data_off = "0"
# initialise UART
uart = mraa.Uart(port)
while True:
   uart.write(bytearray(data_on, 'utf-8'))
   print("on")
   time.sleep(3)
   uart.write(bytearray(data_off, 'utf-8'))
   print("off")
   time.sleep(3)

Walabot Breath Detection

Python
Using Walabot Breath Detection to add additional security for facial recognition
#!/usr/bin/env python3 
from __future__ import print_function # WalabotAPI works on both Python 2 an 3. 
from sys import platform 
from os import system 
from imp import load_source 
from os.path import join 
import time, random 
import math 
from collections import deque 
import urllib.request 
modulePath = join('/usr', 'share', 'walabot', 'python', 'WalabotAPI.py')      
wlbt = load_source('WalabotAPI', modulePath) 
wlbt.Init() 
start = time.time() 
class RealtimePlot: 
   def __init__(self, axes, max_entries =100): 
       self.axis_x = deque(maxlen=max_entries) 
       self.axis_y = deque(maxlen=max_entries) 
       self.axes = axes 
       self.max_entries = max_entries 
       self.lineplot, = axes.plot([], [], "ro-") 
       self.axes.set_autoscaley_on(True) 
   def add(self, x, y): 
       self.axis_x.append(x) 
       self.axis_y.append(y) 
       self.lineplot.set_data(self.axis_x, self.axis_y) 
       self.axes.set_xlim(self.axis_x[0], self.axis_x[-1] + 1e-15) 
       self.axes.set_ylim(0, 0.2) 
       self.axes.relim(); self.axes.autoscale_view() # rescale the y-axis 
   def animate(self, figure, callback, interval = 50): 
       import matplotlib.animation as animation 
       def wrapper(frame_index): 
           self.add(*callback(frame_index)) 
           self.axes.relim(); self.axes.autoscale_view() # rescale the y-axis 
           return self.lineplot 
       animation.FuncAnimation(figure, wrapper, interval=interval) 
def main(): 
   from matplotlib import pyplot as plt 
   # Walabot_SetArenaR - input parameters 
   minInCm, maxInCm, resInCm = 30, 150, 1 
   # Walabot_SetArenaTheta - input parameters 
   minIndegrees, maxIndegrees, resIndegrees = -4, 4, 2 
   # Walabot_SetArenaPhi - input parameters 
   minPhiInDegrees, maxPhiInDegrees, resPhiInDegrees = -4, 4, 2 
   # Configure Walabot database install location (for windows) 
   wlbt.SetSettingsFolder() 
   # 1) Connect : Establish communication with walabot. 
   wlbt.ConnectAny() 
   # 2) Configure: Set scan profile and arena 
   # Set Profile - to Sensor-Narrow. 
   wlbt.SetProfile(wlbt.PROF_SENSOR_NARROW) 
   # Setup arena - specify it by Cartesian coordinates. 
   wlbt.SetArenaR(minInCm, maxInCm, resInCm) 
   # Sets polar range and resolution of arena (parameters in degrees). 
   wlbt.SetArenaTheta(minIndegrees, maxIndegrees, resIndegrees) 
   # Sets azimuth range and resolution of arena.(parameters in degrees). 
   wlbt.SetArenaPhi(minPhiInDegrees, maxPhiInDegrees, resPhiInDegrees) 
   # Dynamic-imaging filter for the specific frequencies typical of breathing 
   wlbt.SetDynamicImageFilter(wlbt.FILTER_TYPE_DERIVATIVE) 
   # 3) Start: Start the system in preparation for scanning. 
   wlbt.Start() 
   fig, axes = plt.subplots() 
   display = RealtimePlot(axes) 
   display.animate(fig, lambda frame_index: (time.time() - start, random.random() * 100)) 
   #plt.show() 
   #fig, axes = plt.subplots() 
   #display = RealtimePlot(axes) 
   while True: 
       appStatus, calibrationProcess = wlbt.GetStatus() 
       # 5) Trigger: Scan(sense) according to profile and record signals 
       # to be available for processing and retrieval. 
       wlbt.Trigger() 
       # 6) Get action: retrieve the last completed triggered recording 
       energy = wlbt.GetImageEnergy() 
       display.add(time.time() - start, energy * 100) 
       #This is just for prototype purposes, we will gather the data in bulk and send them to the server in the future 
       plt.pause(0.001) 
if __name__ == "__main__": main()  

Raw Image NCS classifier

Python
Raw Image classifier on Movidius NCS
import os
import sys
import numpy
import ntpath
import argparse
import skimage.io
import skimage.transform
import mvnc.mvncapi as mvnc
# Number of top prodictions to print
NUM_PREDICTIONS		= 5
# Variable to store commandline arguments
ARGS                = None
# ---- Step 1: Open the enumerated device and get a handle to it -------------
def open_ncs_device():
   # Look for enumerated NCS device(s); quit program if none found.
   devices = mvnc.EnumerateDevices()
   if len( devices ) == 0:
       print( "No devices found" )
       quit()
   # Get a handle to the first enumerated device and open it
   device = mvnc.Device( devices[0] )
   device.OpenDevice()
   return device
# ---- Step 2: Load a graph file onto the NCS device -------------------------
def load_graph( device ):
   # Read the graph file into a buffer
   with open( ARGS.graph, mode='rb' ) as f:
       blob = f.read()
   # Load the graph buffer into the NCS
   graph = device.AllocateGraph( blob )
   return graph
# ---- Step 3: Pre-process the images ----------------------------------------
def pre_process_image():
   # Read & resize image [Image size is defined during training]
   img = skimage.io.imread( ARGS.image )
   img = skimage.transform.resize( img, ARGS.dim, preserve_range=True )
   # Convert RGB to BGR [skimage reads image in RGB, but Caffe uses BGR]
   if( ARGS.colormode == "BGR" ):
       img = img[:, :, ::-1]
   # Mean subtraction & scaling [A common technique used to center the data]
   img = img.astype( numpy.float16 )
   img = ( img - numpy.float16( ARGS.mean ) ) * ARGS.scale
   return img
# ---- Step 4: Read & print inference results from the NCS -------------------
def infer_image( graph, img ):
   # Load the labels file 
   labels =[ line.rstrip('\n') for line in 
                  open( ARGS.labels ) if line != 'classes\n'] 
   # The first inference takes an additional ~20ms due to memory 
   # initializations, so we make a 'dummy forward pass'.
   graph.LoadTensor( img, 'user object' )
   output, userobj = graph.GetResult()
   # Load the image as a half-precision floating point array
   graph.LoadTensor( img, 'user object' )
   # Get the results from NCS
   output, userobj = graph.GetResult()
   # Sort the indices of top predictions
   order = output.argsort()[::-1][:NUM_PREDICTIONS]
   # Get execution time
   inference_time = graph.GetGraphOption( mvnc.GraphOption.TIME_TAKEN )
   # Print the results
   print( "\n==============================================================" )
   print( "Top predictions for", ntpath.basename( ARGS.image ) )
   print( "Execution time: " + str( numpy.sum( inference_time ) ) + "ms" )
   print( "--------------------------------------------------------------" )
   for i in range( 0, NUM_PREDICTIONS ):
       print( "%3.1f%%\t" % (100.0 * output[ order[i] ] )
              + labels[ order[i] ] )
   print( "==============================================================" )
   # If a display is available, show the image on which inference was performed
   if 'DISPLAY' in os.environ:
       skimage.io.imshow( ARGS.image )
       skimage.io.show()
# ---- Step 5: Unload the graph and close the device -------------------------
def close_ncs_device( device, graph ):
   graph.DeallocateGraph()
   device.CloseDevice()
# ---- Main function (entry point for this script ) --------------------------
def main():
   device = open_ncs_device()
   graph = load_graph( device )
   img = pre_process_image()
   infer_image( graph, img )
   close_ncs_device( device, graph )
# ---- Define 'main' function as the entry point for this script -------------
if __name__ == '__main__':
   parser = argparse.ArgumentParser(
                        description="Image classifier using \
                        Intel® Movidius™ Neural Compute Stick." )
   parser.add_argument( '-g', '--graph', type=str,
                        default='/WalabotRawNet/graph',
                        help="Absolute path to the neural network graph file." )
   parser.add_argument( '-i', '--image', type=str,
                        default='raw.jpeg',
                        help="Absolute path to the image that needs to be inferred." )
   parser.add_argument( '-l', '--labels', type=str,
                        default='raw_classifies.txt',
                        help="Absolute path to labels file." )
   parser.add_argument( '-M', '--mean', type=float,
                        nargs='+',
                        default=[104.00698793, 116.66876762, 122.67891434],
                        help="',' delimited floating point values for image mean." )
   parser.add_argument( '-S', '--scale', type=float,
                        default=1,
                        help="Absolute path to labels file." )
   parser.add_argument( '-D', '--dim', type=int,
                        nargs='+',
                        default=[224, 224],
                        help="Image dimensions. ex. -D 224 224" )
   parser.add_argument( '-c', '--colormode', type=str,
                        default="BGR",
                        help="RGB vs BGR color sequence. TensorFlow = RGB, Caffe = BGR" )
   ARGS = parser.parse_args()
   main()
# ==== End of file =========================================================== 

Getting the raw image

Python
Getting the raw image from Walabot Radar and save it to raw.jpeg
from __future__ import print_function, division
import WalabotAPI as wlbt
import io
from PIL import Image
try:  # for Python 2
   import Tkinter as tk
except ImportError:  # for Python 3
   import tkinter as tk
try:  # for Python 2
   range = xrange
except NameError:
   pass
COLORS = [
   "000083", "000087", "00008B", "00008F", "000093", "000097", "00009B",
   "00009F", "0000A3", "0000A7", "0000AB", "0000AF", "0000B3", "0000B7",
   "0000BB", "0000BF", "0000C3", "0000C7", "0000CB", "0000CF", "0000D3",
   "0000D7", "0000DB", "0000DF", "0000E3", "0000E7", "0000EB", "0000EF",
   "0000F3", "0000F7", "0000FB", "0000FF", "0003FF", "0007FF", "000BFF",
   "000FFF", "0013FF", "0017FF", "001BFF", "001FFF", "0023FF", "0027FF",
   "002BFF", "002FFF", "0033FF", "0037FF", "003BFF", "003FFF", "0043FF",
   "0047FF", "004BFF", "004FFF", "0053FF", "0057FF", "005BFF", "005FFF",
   "0063FF", "0067FF", "006BFF", "006FFF", "0073FF", "0077FF", "007BFF",
   "007FFF", "0083FF", "0087FF", "008BFF", "008FFF", "0093FF", "0097FF",
   "009BFF", "009FFF", "00A3FF", "00A7FF", "00ABFF", "00AFFF", "00B3FF",
   "00B7FF", "00BBFF", "00BFFF", "00C3FF", "00C7FF", "00CBFF", "00CFFF",
   "00D3FF", "00D7FF", "00DBFF", "00DFFF", "00E3FF", "00E7FF", "00EBFF",
   "00EFFF", "00F3FF", "00F7FF", "00FBFF", "00FFFF", "03FFFB", "07FFF7",
   "0BFFF3", "0FFFEF", "13FFEB", "17FFE7", "1BFFE3", "1FFFDF", "23FFDB",
   "27FFD7", "2BFFD3", "2FFFCF", "33FFCB", "37FFC7", "3BFFC3", "3FFFBF",
   "43FFBB", "47FFB7", "4BFFB3", "4FFFAF", "53FFAB", "57FFA7", "5BFFA3",
   "5FFF9F", "63FF9B", "67FF97", "6BFF93", "6FFF8F", "73FF8B", "77FF87",
   "7BFF83", "7FFF7F", "83FF7B", "87FF77", "8BFF73", "8FFF6F", "93FF6B",
   "97FF67", "9BFF63", "9FFF5F", "A3FF5B", "A7FF57", "ABFF53", "AFFF4F",
   "B3FF4B", "B7FF47", "BBFF43", "BFFF3F", "C3FF3B", "C7FF37", "CBFF33",
   "CFFF2F", "D3FF2B", "D7FF27", "DBFF23", "DFFF1F", "E3FF1B", "E7FF17",
   "EBFF13", "EFFF0F", "F3FF0B", "F7FF07", "FBFF03", "FFFF00", "FFFB00",
   "FFF700", "FFF300", "FFEF00", "FFEB00", "FFE700", "FFE300", "FFDF00",
   "FFDB00", "FFD700", "FFD300", "FFCF00", "FFCB00", "FFC700", "FFC300",
   "FFBF00", "FFBB00", "FFB700", "FFB300", "FFAF00", "FFAB00", "FFA700",
   "FFA300", "FF9F00", "FF9B00", "FF9700", "FF9300", "FF8F00", "FF8B00",
   "FF8700", "FF8300", "FF7F00", "FF7B00", "FF7700", "FF7300", "FF6F00",
   "FF6B00", "FF6700", "FF6300", "FF5F00", "FF5B00", "FF5700", "FF5300",
   "FF4F00", "FF4B00", "FF4700", "FF4300", "FF3F00", "FF3B00", "FF3700",
   "FF3300", "FF2F00", "FF2B00", "FF2700", "FF2300", "FF1F00", "FF1B00",
   "FF1700", "FF1300", "FF0F00", "FF0B00", "FF0700", "FF0300", "FF0000",
   "FB0000", "F70000", "F30000", "EF0000", "EB0000", "E70000", "E30000",
   "DF0000", "DB0000", "D70000", "D30000", "CF0000", "CB0000", "C70000",
   "C30000", "BF0000", "BB0000", "B70000", "B30000", "AF0000", "AB0000",
   "A70000", "A30000", "9F0000", "9B0000", "970000", "930000", "8F0000",
   "8B0000", "870000", "830000", "7F0000"]
APP_X, APP_Y = 50, 50  # location of top-left corner of window
CANVAS_LENGTH = 650  # in pixels
class RawImageApp(tk.Frame):
   """ Main app class.
   """
   def __init__(self, master):
       """ Init the GUI components and the Walabot API.
       """
       tk.Frame.__init__(self, master)
       self.canvasPanel = CanvasPanel(self)
       self.wlbtPanel = WalabotPanel(self)
       self.ctrlPanel = ControlPanel(self)
       self.canvasPanel.pack(side=tk.RIGHT, anchor=tk.NE)
       self.wlbtPanel.pack(side=tk.TOP, anchor=tk.W, fill=tk.BOTH, pady=10)
       self.ctrlPanel.pack(side=tk.TOP, anchor=tk.W, fill=tk.BOTH, pady=10)
       self.wlbt = Walabot()
   def initAppLoop(self):
       if self.wlbt.isConnected():
           self.ctrlPanel.statusVar.set('STATUS_CONNECTED')
           self.update_idletasks()
           params = self.wlbtPanel.getParams()
           self.wlbt.setParams(*params)
           self.wlbtPanel.setParams(*self.wlbt.getArenaParams())
           if not params[4]:  # equals: if not mtiMode
               self.ctrlPanel.statusVar.set('STATUS_CALIBRATING')
               self.update_idletasks()
               self.wlbt.calibrate()
           self.lenOfPhi, self.lenOfR = self.wlbt.getRawImageSliceDimensions()
           self.canvasPanel.setGrid(self.lenOfPhi, self.lenOfR)
           self.wlbtPanel.changeEntriesState('disabled')
           self.loop()
       else:
           self.ctrlPanel.statusVar.set('STATUS_DISCONNECTED')
   def loop(self):
       self.ctrlPanel.statusVar.set('STATUS_SCANNING')
       rawImage = self.wlbt.triggerAndGetRawImageSlice()
       self.canvasPanel.update(rawImage, self.lenOfPhi, self.lenOfR)
       self.ctrlPanel.fpsVar.set(self.wlbt.getFps())
       self.cyclesId = self.after_idle(self.loop)
class WalabotPanel(tk.LabelFrame):
   class WalabotParameter(tk.Frame):
       """ The frame that sets each Walabot parameter line.
       """
       def __init__(self, master, varVal, minVal, maxVal, defaultVal):
           """ Init the Labels (parameter name, min/max value) and entry.
           """
           tk.Frame.__init__(self, master)
           tk.Label(self, text=varVal).pack(side=tk.LEFT, padx=(0, 5), pady=1)
           self.minVal, self.maxVal = minVal, maxVal
           self.var = tk.StringVar()
           self.var.set(defaultVal)
           self.entry = tk.Entry(self, width=7, textvariable=self.var)
           self.entry.pack(side=tk.LEFT)
           self.var.trace("w", lambda a, b, c, var=self.var: self.validate())
           txt = "[{}, {}]".format(minVal, maxVal)
           tk.Label(self, text=txt).pack(side=tk.LEFT, padx=(5, 20), pady=1)
       def validate(self):
           """ Checks that the entered value is a valid number and between
               the min/max values. Change the font color of the value to red
               if False, else to black (normal).
           """
           num = self.var.get()
           try:
               num = float(num)
               if num < self.minVal or num > self.maxVal:
                   self.entry.config(fg='#'+COLORS[235])
                   return
               self.entry.config(fg='gray1')
           except ValueError:
               self.entry.config(fg='#'+COLORS[235])
               return
       def get(self):
           """ Returns the entry value as a float.
           """
           return float(self.var.get())
       def set(self, value):
           """ Sets the entry value according to a given one.
           """
           self.var.set(value)
       def changeState(self, state):
           """ Change the entry state according to a given one.
           """
           self.entry.configure(state=state)
   class WalabotParameterMTI(tk.Frame):
       """ The frame that control the Walabot MTI parameter line.
       """
       def __init__(self, master):
           """ Init the MTI line (label, radiobuttons).
           """
           tk.Frame.__init__(self, master)
           tk.Label(self, text="MTI      ").pack(side=tk.LEFT)
           self.mtiVar = tk.IntVar()
           self.mtiVar.set(0)
           self.true = tk.Radiobutton(
               self, text="True", variable=self.mtiVar, value=2)
           self.false = tk.Radiobutton(
               self, text="False", variable=self.mtiVar, value=0)
           self.true.pack(side=tk.LEFT)
           self.false.pack(side=tk.LEFT)
       def get(self):
           """ Returns the value of the pressed radiobutton.
           """
           return self.mtiVar.get()
       def set(self, value):
           """ Sets the pressed radiobutton according to a given value.
           """
           self.mtiVar.set(value)
       def changeState(self, state):
           """ Change the state of the radiobuttons according to a given one.
           """
           self.true.configure(state=state)
           self.false.configure(state=state)
   def __init__(self, master):
       tk.LabelFrame.__init__(self, master, text='Walabot Configuration')
       self.rMin = self.WalabotParameter(self, 'R     Min', 1, 1000, 10.0)
       self.rMax = self.WalabotParameter(self, 'R     Max', 1, 1000, 100.0)
       self.rRes = self.WalabotParameter(self, 'R     Res', 0.1, 10, 2.0)
       self.tMin = self.WalabotParameter(self, 'Theta Min', -90, 90, -20.0)
       self.tMax = self.WalabotParameter(self, 'Theta Max', -90, 90, 20.0)
       self.tRes = self.WalabotParameter(self, 'Theta Res', 0.1, 10, 10.0)
       self.pMin = self.WalabotParameter(self, 'Phi   Min', -90, 90, -45.0)
       self.pMax = self.WalabotParameter(self, 'Phi   Max', -90, 90, 45.0)
       self.pRes = self.WalabotParameter(self, 'Phi   Res', 0.1, 10, 2.0)
       self.thld = self.WalabotParameter(self, 'Threshold', 0.1, 100, 15.0)
       self.mti = self.WalabotParameterMTI(self)
       self.parameters = (
           self.rMin, self.rMax, self.rRes, self.tMin, self.tMax, self.tRes,
           self.pMin, self.pMax, self.pRes, self.thld, self.mti)
       for param in self.parameters:
           param.pack(anchor=tk.W)
   def getParams(self):
       rParams = (self.rMin.get(), self.rMax.get(), self.rRes.get())
       tParams = (self.tMin.get(), self.tMax.get(), self.tRes.get())
       pParams = (self.pMin.get(), self.pMax.get(), self.pRes.get())
       thldParam, mtiParam = self.thld.get(), self.mti.get()
       return rParams, tParams, pParams, thldParam, mtiParam
   def setParams(self, rParams, thetaParams, phiParams, threshold):
       self.rMin.set(rParams[0])
       self.rMax.set(rParams[1])
       self.rRes.set(rParams[2])
       self.tMin.set(thetaParams[0])
       self.tMax.set(thetaParams[1])
       self.tRes.set(thetaParams[2])
       self.pMin.set(phiParams[0])
       self.pMax.set(phiParams[1])
       self.pRes.set(phiParams[2])
       self.thld.set(threshold)
   def changeEntriesState(self, state):
       for param in self.parameters:
           param.changeState(state)
class ControlPanel(tk.LabelFrame):
   """ This class is designed to control the control area of the app.
   """
   def __init__(self, master):
       """ Initialize the buttons and the data labels.
       """
       tk.LabelFrame.__init__(self, master, text='Control Panel')
       self.buttonsFrame = tk.Frame(self)
       self.runButton, self.stopButton = self.setButtons(self.buttonsFrame)
       self.statusFrame = tk.Frame(self)
       self.statusVar = self.setVar(self.statusFrame, 'APP_STATUS', '')
       self.errorFrame = tk.Frame(self)
       self.errorVar = self.setVar(self.errorFrame, 'EXCEPTION', '')
       self.fpsFrame = tk.Frame(self)
       self.fpsVar = self.setVar(self.fpsFrame, 'FRAME_RATE', 'N/A')
       self.buttonsFrame.grid(row=0, column=0, sticky=tk.W)
       self.statusFrame.grid(row=1, columnspan=2, sticky=tk.W)
       self.errorFrame.grid(row=2, columnspan=2, sticky=tk.W)
       self.fpsFrame.grid(row=3, columnspan=2, sticky=tk.W)
   def setButtons(self, frame):
       """ Initialize the 'Start' and 'Stop' buttons.
       """
       runButton = tk.Button(frame, text='Start', command=self.start)
       stopButton = tk.Button(frame, text='Stop', command=self.stop)
       runButton.grid(row=0, column=0)
       stopButton.grid(row=0, column=1)
       return runButton, stopButton
   def setVar(self, frame, varText, default):
       """ Initialize the data frames.
       """
       strVar = tk.StringVar()
       strVar.set(default)
       tk.Label(frame, text=(varText).ljust(12)).grid(row=0, column=0)
       tk.Label(frame, textvariable=strVar).grid(row=0, column=1)
       return strVar
   def start(self):
       """ Applied when 'Start' button is pressed. Starts the Walabot and
           the app cycles.
       """
       self.master.initAppLoop()
   def stop(self):
       """ Applied when 'Stop' button in pressed. Stops the Walabot and the
           app cycles.
       """
       if hasattr(self.master, 'cyclesId'):
           self.master.after_cancel(self.master.cyclesId)
           self.master.wlbtPanel.changeEntriesState('normal')
           self.master.canvasPanel.reset()
           self.statusVar.set('STATUS_IDLE')
class CanvasPanel(tk.LabelFrame):
   """ This class is designed to control the canvas area of the app.
   """
   def __init__(self, master):
       """ Initialize the label-frame and canvas.
       """
       tk.LabelFrame.__init__(self, master, text='Raw Image Slice: R / Phi')
       self.canvas = tk.Canvas(
           self, width=CANVAS_LENGTH, height=CANVAS_LENGTH)
       self.canvas.pack()
       self.canvas.configure(background='#'+COLORS[0])
   def setGrid(self, sizeX, sizeY):
       """ Set the canvas components (rectangles), given the size of the axes.
           Arguments:
               sizeX       Number of cells in Phi axis.
               sizeY       Number of cells in R axis.
       """
       recHeight, recWidth = CANVAS_LENGTH/sizeX, CANVAS_LENGTH/sizeY
       self.cells = [[
           self.canvas.create_rectangle(
               recWidth*col, recHeight*row,
               recWidth*(col+1), recHeight*(row+1),
               width=0)
           for col in range(sizeY)] for row in range(sizeX)]
   def update(self, rawImage, lenOfPhi, lenOfR):
       """ Updates the canvas cells colors acorrding to a given rawImage
           matrix and it's dimensions.
           Arguments:
               rawImage    A 2D matrix contains the current rawImage slice.
               lenOfPhi    Number of cells in Phi axis.
               lenOfR      Number of cells in R axis.
       """
       for i in range(lenOfPhi):
           for j in range(lenOfR):
               self.canvas.itemconfigure(
                   self.cells[lenOfPhi-i-1][j],
                   fill='#'+COLORS[rawImage[i][j]])
       ps = self.canvas.postscripot(colormode = 'color')
       im = Image.open(io.Bytes.IO(ps.encode('utf-8)))
       im.save('raw.jpg')
   def reset(self):
       """ Deletes all the canvas components (colored rectangles).
       """
       self.canvas.delete('all')
class Walabot:
   """ Control the Walabot using the Walabot API.
   """
   def __init__(self):
       """ Init the Walabot API.
       """
       self.wlbt = wlbt
       self.wlbt.Init()
       self.wlbt.SetSettingsFolder()
   def isConnected(self):
       """ Try to connect the Walabot device. Return True/False accordingly.
       """
       try:
           self.wlbt.ConnectAny()
       except self.wlbt.WalabotError as err:
           if err.code == 19:  # "WALABOT_INSTRUMENT_NOT_FOUND"
               return False
           else:
               raise err
       return True
   def setParams(self, r, theta, phi, threshold, mti):
       """ Set the arena Parameters according given ones.
       """
       self.wlbt.SetProfile(self.wlbt.PROF_SENSOR)
       self.wlbt.SetArenaR(*r)
       self.wlbt.SetArenaTheta(*theta)
       self.wlbt.SetArenaPhi(*phi)
       self.wlbt.SetThreshold(threshold)
       self.wlbt.SetDynamicImageFilter(mti)
       self.wlbt.Start()
   def getArenaParams(self):
       """ Returns the Walabot parameters from the Walabot SDK.
           Returns:
               params      rParams, thetaParams, phiParams, threshold as
                           given from the Walabot SDK.
       """
       rParams = self.wlbt.GetArenaR()
       thetaParams = self.wlbt.GetArenaTheta()
       phiParams = self.wlbt.GetArenaPhi()
       threshold = self.wlbt.GetThreshold()
       return rParams, thetaParams, phiParams, threshold
   def calibrate(self):
       """ Calibrates the Walabot.
       """
       self.wlbt.StartCalibration()
       while self.wlbt.GetStatus()[0] == self.wlbt.STATUS_CALIBRATING:
           self.wlbt.Trigger()
   def getRawImageSliceDimensions(self):
       """ Returns the dimensions of the rawImage 2D list given from the
           Walabot SDK.
           Returns:
               lenOfPhi    Num of cells in Phi axis.
               lenOfR      Num of cells in Theta axis.
       """
       return self.wlbt.GetRawImageSlice()[1:3]
   def triggerAndGetRawImageSlice(self):
       """ Returns the rawImage given from the Walabot SDK.
           Returns:
               rawImage    A rawImage list as described in the Walabot docs.
       """
       self.wlbt.Trigger()
       return self.wlbt.GetRawImageSlice()[0]
   def getFps(self):
       """ Returns the Walabot current fps as given from the Walabot SDK.
           Returns:
               fpsVar      Number of frames per seconds.
       """
       return int(self.wlbt.GetAdvancedParameter('FrameRate'))
def rawImage():
   """ Main app function. Init the main app class, configure the window
       and start the mainloop.
   """
   root = tk.Tk()
   root.title('Walabot - Raw Image Slice Example')
   RawImageApp(root).pack(side=tk.TOP, fill=tk.BOTH, expand=True)
   root.geometry("+{}+{}".format(APP_X, APP_Y))  # set window location
   root.update()
   root.minsize(width=root.winfo_reqwidth(), height=root.winfo_reqheight())
   root.mainloop()
if __name__ == '__main__':
   rawImage()

AI Face Lock Project Repo

Repo includes entire project, the client side with Movidius NCS

Credits

Peter Ma

Peter Ma

49 projects • 393 followers
Prototype Hacker, Hackathon Goer, World Traveler, Ecological balancer, integrationist, technologist, futurist.
Thanks to Wan Jun and Shin Ae Hong.

Comments