How to Build your own Amazon Ring Security System in an Afternoon
Tags: react, reactnative, machinelearning, security
Published: 2019-08-08 19:50:19

In this tutorial, we are going to explore one of the most cutting edge technologies in machine learning AI…computer vision! To showcase its capabilities, this step-by-step article will walk you through building your very own desktop security system with a facial recognition machine learning algorithm.

With a simple webcam, your program will be able to recognize the faces of people you choose to allow into the system. It will trigger a text, email, and snapshot image alert system, if any unrecognized faces appear in front of your webcam. We’ll also use Cloudinary and PubNub to build a React Native application that can receive a snapshot image of an “intruder’s” face. It will also allow a user to be added to the system if you desire.

![](https://thepracticaldev.s3.amazonaws.com/i/f7fn2ywml21pye294kml.gif)

<h2>What is Computer Vision?</h2>

Computer Vision is a specific field in artificial intelligence that deals with training machine learning models to understand and interpret the visual world. By learning from images and frames from cameras and videos, a computer vision AI can accurately classify the objects it sees and subsequently perform reactionary tasks just like we humans do.

![](https://thepracticaldev.s3.amazonaws.com/i/iv8q69rtde1h4vfu4ihl.gif)

<a href="https://towardsdatascience.com/how-to-do-everything-in-computer-vision-2b442c469928" target="_blank" rel="noopener noreferrer">Source</a> Accessed 7/31/19

<h2>Python Code for Your FaceTracking Alert System</h2>

Before jumping into the code, be sure you sign up for a free PubNub account so we don’t run into any issues later.

To start building the project from scratch, create your project’s directory using your computer’s command line app:

<pre class="EnlighterJSRAW" data-enlighter-language="null">mkdir faceTrackingApp
cd faceTrackingApp</pre>

Then create a new Python file called <strong>facetracker.py</strong>.
<h2>Libraries and Dependencies for Computer Vision<h2>
<h3>OpenCV and face_recognition</h3>
First, let's import some machine learning libraries for our app's face tracking capabilities. The main libraries we are going to use are OpenCV and face_recognition.
<pre class="EnlighterJSRAW" data-enlighter-language="null">import face_recognition # Machine Learning Library for Face Recognition
import cv2 # OpenCV
import numpy as np # Handling data
import time
import os,sys</pre>
<a href="https://opencv.org/" target="_blank" rel="noopener noreferrer">OpenCV</a> is the most popular machine learning library for realtime Computer Vision. <span style="font-weight: 400;">The library has useful tools such as webcam control as well as models to train a face tracking app from scratch.</span>

However, our project will primarily use <a href="https://github.com/ageitgey/face_recognition" target="_blank" rel="noopener noreferrer">ageitgey's face_recognition python library</a> as it already comes with a face recognition model out of the box, making it extremely quick and easy to use.
<h3>PubNub</h3>
Next, we're going to setup PubNub as our Data Stream Network to handle all of the data between our Python script and mobile application.

After you've retrieved your free <a href="https://dashboard.pubnub.com/signup" target="_blank" rel="noopener noreferrer">PubNub API keys</a>, install the <a href="https://www.pubnub.com/docs/python/pubnub-python-sdk" target="_blank" rel="noopener noreferrer">PubNub Python SDK</a>.
<pre class="EnlighterJSRAW" data-enlighter-language="null">pip install 'pubnub&gt;=4.1.4'</pre>
Then, import the library in your python file,
<pre class="EnlighterJSRAW" data-enlighter-language="null">from pubnub.callbacks import SubscribeCallback
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.enums import PNOperationType, PNStatusCategory</pre>
and configure a PubNub instance with your API keys.
<pre class="EnlighterJSRAW" data-enlighter-language="null"># PubNub Config
pnconfig = PNConfiguration()
pnconfig.subscribe_key = "YOUR_SUBSCRIBE_KEY"
pnconfig.publish_key = "YOUR_PUBLISH_KEY"
pnconfig.ssl = False
pubnub = PubNub(pnconfig)</pre>
<h3>Cloudinary</h3>
Lastly, we will setup <a href="https://cloudinary.com/" target="_blank" rel="noopener noreferrer">Cloudinary</a> as our Content Delivery Network to store images of intruders' faces. This will work beautifully with PubNub as our python script can upload the image to Cloudinary, get the URL from the response, then PubNub will send that URL to our Client app to render.

First, <a href="https://cloudinary.com/users/register/free" target="_blank" rel="noopener noreferrer">sign up for a free Cloudinary account</a> and then install the Cloudinary Python SDK with:
<pre class="EnlighterJSRAW" data-enlighter-language="null">pip install cloudinary</pre>
Setup the <code>CLOUDINARY_URL</code> environment variable by copying it from the <a href="https://cloudinary.com/console" rel="nofollow">Management Console</a>.

Using zsh/bash/sh:
<pre class="EnlighterJSRAW" data-enlighter-language="null">export CLOUDINARY_URL=cloudinary://API-Key:API-Secret@Cloud-name</pre>
Import the library in your Python script,
<pre class="EnlighterJSRAW" data-enlighter-language="null">from cloudinary.api import delete_resources_by_tag, resources_by_tag
from cloudinary.uploader import upload
from cloudinary.utils import cloudinary_url</pre>
and configure a Cloudinary instance.
<pre class="EnlighterJSRAW" data-enlighter-language="null"># Cloudinary Config
os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '.'))
if os.path.exists('settings.py'):
    exec(open('settings.py').read())
DEFAULT_TAG = "python_sample_basic"</pre>
<h2>Machine Learning Face Tracking Algorithm</h2>
Before we begin building our face recognition machine learning model, we'll need to declare some global variables:
<pre class="EnlighterJSRAW" data-enlighter-language="null"># Setup some Global Variables
video_capture = cv2.VideoCapture(0) # Webcam instance
known_face_names = [] # Names of faces
known_face_encodings = [] # Encodings of Faces
count = 0 # Counter for Number of Unknown Users
flag = 0 # Flag for Setting/Unsetting "Intruder Mode"</pre>

[NOTE: We create a count variable for the unknown users because we are going to dynamically save the user's snapshot image in a file path.] 

We're  going to append the count to the file name like an ID tag. In order to find this snapshot image later, we need to pull up that user's count variable, so we can find the image in the file path.

<span style="font-weight: 400;">To start training our face recognizer model, we’ll begin with two sample images of faces. You will need two images of two different people's faces in your project directory.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null"># Load a sample picture and learn how to recognize it.
sample_face_1 = face_recognition.load_image_file("sample_1.jpeg")
sample_face_1_encoding = face_recognition.face_encodings(sample_face_1)[0]

# Load a second sample picture and learn how to recognize it.
sample_face_2 = face_recognition.load_image_file("17.png")
sample_face_2_encoding = face_recognition.face_encodings(sample_face_2)[0]

# Create arrays of known face encodings and their names
known_face_encodings = [
    sample_face_1_encoding,
    sample_face_2_encoding
]

# Create Names for Sample Face encodings
known_face_names = [
    "sample_1",
    "sample_2"
]

# Initialize some variables
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True</pre>
Next, we will declare a while loop that will run continuously for the duration of the app. The loop will be responsible for the main functions of our app:
<ul>
 	<li>Turning on and displaying the webcam feed</li>
 	<li>Tracking faces that appear in front of the webcam and drawing a red box around the face in realtime</li>
 	<li>Displaying a name below a known user's face and "Unknown" for a face that has not been added to the database</li>
 	<li>Calling a series of Alerts and Functions to handle when an "Unknown" face appears on screen</li>
</ul>

<pre class="EnlighterJSRAW">while(True):
    
    video_capture = cv2.VideoCapture(0)
    # Grab a single frame of video
    ret, frame = video_capture.read()

    # Resize frame of video to 1/4 size for faster face recognition processing
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)

    # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)
    rgb_small_frame = small_frame[:, :, ::-1]

    # Only process every other frame of video to save time
    if process_this_frame:
        # Find all the faces and face encodings in the current frame of video
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)

        face_names = []
        for face_encoding in face_encodings:
            # See if the face is a match for the known face(s)
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            name = "Unknown"

            # # If a match was found in known_face_encodings, just use the first one.
            # if True in matches:
            #     first_match_index = matches.index(True)
            #     name = known_face_names[first_match_index]

            # Or instead, use the known face with the smallest distance to the new face
            face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
            best_match_index = np.argmin(face_distances)
            if matches[best_match_index]:
                name = known_face_names[best_match_index]

            face_names.append(name)

            #---------------------See next section for this code block's explanation---------------------#

            ## Set Unknown User Flag and Send Alerts
            #global flag
            #if(name=='Unknown' and flag==0):
            #    flag = 1
            #    Alert()
            #
            #--------------------------------------------------------------------------------------------#

    process_this_frame = not process_this_frame

    # Display the results
    for (top, right, bottom, left), name in zip(face_locations, face_names):
        # Scale back up face locations since the frame we detected in was scaled to 1/4 size
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # Draw a box around the face
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

        # Draw a label with a name below the face
        cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

    # Display the resulting image
    cv2.imshow('Video', frame)

    # Hit 'q' on the keyboard to quit!
    if cv2.waitKey(10) &amp; 0xFF == ord('q'):
        break

# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()</pre>

<h2>Sending Alerts</h2>
We shall take care of the case when an unregistered face appears in front of our webcam. We want our program to trigger an alert system the moment it sees an "Unknown" face. Luckily, all we need to do is add a few lines of code to our main while loop at the end of the <strong><em>for face_encoding in face_encodings:</em></strong> loop.
<pre class="EnlighterJSRAW" data-enlighter-language="null"># Set Unknown User Flag and Send Alerts
global flag
if(name=='Unknown' and flag==0):
    flag = 1 # Stop repeated calls of Alerts until after the Unknown User is dealt with
    Alert() # Trigger Alert System</pre>
When the alert is triggered, we can then define a function to take a snapshot of the unknown user's face, call a function to upload the snapshot to Cloudinary, and finally call our Text/Email alert function.
<pre class="EnlighterJSRAW" data-enlighter-language="null">def Alert():
    global count
    video_capture = cv2.VideoCapture(0) # Create Open CV Webcam Instance
    path = './' # Specify where you want the snapshot to be stored
    name = 'Unknown_User' + str(count) # Append User ID to File Path

    # Wait for 3 seconds
    print('Taking picture in 3')
    time.sleep(1)
    print('Taking picture in 2')
    time.sleep(1)
    print('Taking picture in 1')
    time.sleep(1)

    # Take Picture
    ret, frame = video_capture.read()

    # Grayscale Image to save memory space
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Save Image in File Path
    status = cv2.imwrite('% s/% s.jpg' % (path, name),gray)
    print('Unknown User Saved to Database', status)

    # Upload Snapshot to Cloudinary 
    upload_files('% s/% s.jpg' % (path,name))
    
    # Send Out Email and Text Alerts
    sendAlerts()</pre>

[NOTE: We grayscale the image because the face recognizer doesn't need color to determine facial features. We also store the snapshot image locally so we can add the face to the recognizer if the client wants to add the user later.]                                                     
                                                                 
                                                         
When defining our <strong>upload_files()</strong> function, we're passing in the snapshot's file path so Cloudinary knows where to upload the file from. We then get the response URL of where the image lives in the cloud. We send this url along with a user ID (count of Unknown user) over PubNub to our client application. The client application can then render the image of the snapshot from the Cloudinary URL.
<pre class="EnlighterJSRAW" data-enlighter-language="null">def upload_files(msg):
    global count # Make global changes to count
    response = upload(msg, tags=DEFAULT_TAG) # Upload Image to Cloudinary
    url, options = cloudinary_url( 
        response['public_id'],
        format=response['format'],
        width=200,
        height=150,
        crop="fill"
    )
    dictionary = {"url": url, "ID": count}
    pubnub.publish().channel('global').message(dictionary).pn_async(publish_callback)
    count+=1 # Increment Unknown User Count</pre>
<span style="font-weight: 400;">In order to publish with PubNub, we need to define a publish callback.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null">def publish_callback(result, status):
    pass
    # Handle PNPublishResult and PNStatus</pre>
&nbsp;

To setup your Text and Email alerts, you'll need to sign up for a <a href="https://www.clicksend.com/us/" target="_blank" rel="noopener noreferrer">free ClickSend account</a> as well as a <a href="https://sendgrid.com/marketing/sendgrid-services-cro/?extProvId=5&amp;extPu=49397-gaw&amp;extLi=115523142&amp;sem_adg=8368110942&amp;extCr=8368110942-299384208935&amp;extSi=&amp;extTg=&amp;keyword=sendgrid&amp;extAP=1t1&amp;extMT=e&amp;gclid=EAIaIQobChMIrtuHkIjg4wIVeSCtBh0q6A7hEAAYASAAEgKArvD_BwE" target="_blank" rel="noopener noreferrer">free SendGrid account</a> to get your API keys.

Now you get to see the power and beauty behind <a href="https://www.pubnub.com/products/functions/" target="_blank" rel="noopener noreferrer">PubNub Functions</a> with our <a href="https://www.pubnub.com/docs/blocks-catalog" target="_blank" rel="noopener noreferrer">Partnered Blocks</a>. Go ahead and visit both our <a href="https://www.pubnub.com/docs/blocks-catalog/clicksend-sms" target="_blank" rel="noopener noreferrer">ClickSend Block</a> as well as our <a href="https://www.pubnub.com/docs/blocks-catalog/sendgrid" target="_blank" rel="noopener noreferrer">SendGrid Block</a>. Through those links, PubNub will automatically generate a customizable PubNub Function.

<span style="font-weight: 400;">The serverless, open-source code will completely handle the APIs for you. All you need to do is put in your API keys and you're good to go!</span>

<span style="font-weight: 400;">Once you've set up your PubNub Functions, you can define a </span><b>sendAlerts()</b><span style="font-weight: 400;"> function to publish a message, implementing your Text and Email alerts:</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null">def sendAlerts():
    dictionary = {
    "to" : 'RECEIVING PHONE NUMBER',
    "body": "There is an unregistered user at your desk!"
    }
    pubnub.publish().channel('clicksend-text').message(dictionary).pn_async(publish_callback)

    dictionary = {
    "to": "EMAIL RECEIVER",
    "toname": "EMAIL SENDER",
    "subject": "INTRUDER ALERT",
    "text": "THERE IS AN UNREGISTERED USER AT YOUR DESK"
    }   
    pubnub.publish().channel('email-sendgrid-channel').message(dictionary).pn_async(publish_callback)</pre>
NOTE: In order to properly use a PubNub block, you need to publish over the same channel specified in your block (you can check this in your blocks Functions dashboard) as well as formatting the message payload properly (according to the block's documentation).
<h2>Adding Users to Our Facetracker</h2>
<span style="font-weight: 400;">When an Unregistered face is detected on our webcam, our Python script sends an email/text alert as well as a snapshot image to our client application.</span>

<span style="font-weight: 400;">We now want to add the ability to add a user's face to our app's "</span><b>known_faces</b><span style="font-weight: 400;">" database, so the user will no longer trigger our alert system. To do this, the client application must publish a message over PubNub.</span>

<span style="font-weight: 400;">To receive this message in our python application, we must subscribe to the channel the client is publishing from, and create a </span><b>Subscriber Callback</b><span style="font-weight: 400;"> to handle the incoming message.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null">class MySubscribeCallback(SubscribeCallback):
    def status(self, pubnub, status):
        pass
        # The status object returned is always related to subscribe but could contain
        # information about subscribe, heartbeat, or errors
        # use the operationType to switch on different options
        if status.operation == PNOperationType.PNSubscribeOperation \
                or status.operation == PNOperationType.PNUnsubscribeOperation:
            if status.category == PNStatusCategory.PNConnectedCategory:
                pass
                # This is expected for a subscribe, this means there is no error or issue whatsoever
            elif status.category == PNStatusCategory.PNReconnectedCategory:
                pass
                # This usually occurs if subscribe temporarily fails but reconnects. This means
                # there was an error but there is no longer any issue
            elif status.category == PNStatusCategory.PNDisconnectedCategory:
                pass
                # This is the expected category for an unsubscribe. This means here
                # was no error in unsubscribing from everything
            elif status.category == PNStatusCategory.PNUnexpectedDisconnectCategory:
                pass
                # This is usually an issue with the internet connection, this is an error, handle
                # appropriately retry will be called automatically
            elif status.category == PNStatusCategory.PNAccessDeniedCategory:
                pass
                # This means that PAM does not allow this client to subscribe to this
                # channel and channel group configuration. This is another explicit error
            else:
                pass
                # This is usually an issue with the internet connection, this is an error, handle appropriately
                # retry will be called automatically
        elif status.operation == PNOperationType.PNSubscribeOperation:
            # Heartbeat operations can in fact have errors, so it is important to check first for an error.
            # For more information on how to configure heartbeat notifications through the status
            if status.is_error():
                pass
                # There was an error with the heartbeat operation, handle here
            else:
                pass
                # Heartbeat operation was successful
        else:
            pass
            # Encountered unknown status type
 
    def presence(self, pubnub, presence):
        pass  # handle incoming presence data
    def message(self, pubnub, message):
        addUser(message.message["ID"], message.message["name"])
 
 
pubnub.add_listener(MySubscribeCallback())
pubnub.subscribe().channels('ch1').execute()</pre>
<span style="font-weight: 400;">NOTE: Above we assume the client is publishing the ID of the unknown user (for image file path) as well as the name of the user (to display below the user's face). </span>


With the parameters in hand, we can add the new user to our database.
<pre class="EnlighterJSRAW" data-enlighter-language="null">def addUser(ID, name):
    global known_face_encodings, known_face_names, flag
    path = './Unknown_User' + str(ID) # Append User ID to File Path
    # Load User's picture and learn how to recognize it.
    user_image = face_recognition.load_image_file('% s.jpg' % (path)) # Load Image
    user_face_encoding = face_recognition.face_encodings(user_image)[0] # Encode Image
    known_face_encodings.append(user_face_encoding) # Add Encoded Image to 'Known Faces' Array
    known_face_names.append(name) # Append New User's Name to Database
    flag = 0 # Reset Unknown User Flag</pre>
<h2>React Native Code for Our Client Application</h2>
<h2>Setting Up Our Realtime React Native Environment</h2>
Install <a href="https://apps.apple.com/us/app/xcode/id497799835?mt=12" target="_blank" rel="noopener noreferrer">Xcode</a> so we can build and simulate our app for IOS <span style="font-weight: 400;">and </span><a href="https://developer.android.com/studio?gclid=EAIaIQobChMI1LzfwrDi4wIVAspkCh3lNwvsEAAYASAAEgLXGvD_BwE"><span style="font-weight: 400;">Android Studio</span></a><span style="font-weight: 400;"> for Android.</span>

Then install <a href="https://nodejs.org/en/" target="_blank" rel="noopener noreferrer">Node.js</a> and watchman using <a href="https://brew.sh/" target="_blank" rel="noopener noreferrer">Homebrew</a>:
<pre class="EnlighterJSRAW" data-enlighter-language="null">brew install node
brew install watchman</pre>
Install the React Native CLI with NPM:
<pre class="EnlighterJSRAW" data-enlighter-language="null">npm install -g react-native-cli</pre>
To create a React Native App template, enter the React Native CLI command in your project's directory:
<pre class="EnlighterJSRAW" data-enlighter-language="null">react-native init client
cd client</pre>
Since we're going to be using PubNub in our Client app to send and receive messages, we'll need to install the PubNub React SDK,
<pre class="EnlighterJSRAW" data-enlighter-language="null">npm install --save pubnub pubnub-react</pre>
and then link the library like so:
<pre class="EnlighterJSRAW" data-enlighter-language="null">react-native link pubnub-react</pre>
<h2>Setting Up Realtime Pub/Sub Messaging</h2>
To start sending and receiving messages in realtime in our app, first import the <a href="https://www.pubnub.com/docs/react-native-javascript/pubnub-javascript-sdk" target="_blank" rel="noopener noreferrer">PubNub React SDK</a>.
<pre class="EnlighterJSRAW" data-enlighter-language="null">import PubNubReact from 'pubnub-react';</pre>
Then import the <strong>TouchableOpacity</strong> and <strong>Image</strong> components from React Native,
<pre class="EnlighterJSRAW" data-enlighter-language="null">import {
  StyleSheet,
  View,
  Text,
  TextInput,
  TouchableOpacity,
  Image,
} from 'react-native';
</pre>
<span style="font-weight: 400;">Now we add a constructor at the top of our App Component. The constructor will be responsible for setting up a PubNub instance with our Publish/Subscribe keys as well as initialize the following state variables:</span>
<ul>
 	<li style="font-weight: 400;"><b>image</b><span style="font-weight: 400;"> - Snapshot image from an unknown user alert (we initialize it with a placeholder image until a Snapshot alert arrives).</span></li>
 	<li style="font-weight: 400;"><b>message</b><span style="font-weight: 400;"> - Incoming alert message from the face tracking app.</span></li>
 	<li style="font-weight: 400;"><b>text</b><span style="font-weight: 400;"> - Client user's input for typing in the name of a user.</span></li>
 	<li><b>count</b><span style="font-weight: 400;"> -  To keep track of which unknown user we are getting an alert from.</span></li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="null">export default class App extends React.Component {

  constructor(props) {
    super(props)

    this.pubnub = new PubNubReact({
      publishKey: "YOUR PUBLISH KEY",
      subscribeKey: "YOUR SUBSCRIBE KEY"
    })

    //Base State
    this.state = {
      image: require('./assets/PLACEHOLDER_IMAGE.jpg'),
      message: '',
      text: '',
      count: 0,
    }

    this.pubnub.init(this);
  }

/// .......VVV REST OF THE CODE VVV.......///</pre>
<span style="font-weight: 400;">When our client app first fires up, we declare an asynchronous function that will subscribe to our face tracking alert channel and handle message events. In this case, we receive the ID (count of unknown user) as well as the snapshot image URL (from Cloudinary) of the unknown user.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null">async componentDidMount() {
  this.setUpApp()    
}

async setUpApp(){
  this.pubnub.getMessage("global", msg =&gt; {
    this.setState({count: msg.message.ID})
    this.setState({image: msg.message.url})
  })

  this.pubnub.subscribe({
    channels: ["global"],
    withPresence: false
  });
}</pre>
<span style="font-weight: 400;">Once that image is received by the mobile app, the client user should then be able to add the unknown user to the face tracker's "</span><b>known_faces</b><span style="font-weight: 400;">" database. We can define a function to set the state of the client user's input for the unknown user's name.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null"> handleText = (name) =&gt; {
   this.setState({ text: name })
}
</pre>
<span style="font-weight: 400;">We can also write a function to publish the added user's name along with the added user's ID.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null"> publishName = (text) =&gt; {
  this.pubnub.publish({
    message: {
      ID: this.state.count,
      name: text,
    },
    channel: "ch1"
  });
}
</pre>
<h2>Creating and Rendering App Components</h2>
At the top of our screen we'll render the snapshot image from an incoming "Unknown User" Alert. The source of this image will be a URI we grabbed from the alert message that we saved to state.



<pre class="EnlighterJSRAW" data-enlighter-language="null">` &lt;Image
  source={{uri: this.state.image}}
  style={{width: 250, height: 250}}/&gt;                  `
</pre>



Below that, we can display a suitable caption.
<pre class="EnlighterJSRAW" data-enlighter-language="null">&lt;Text&gt;{'Do You Know This Person?'}&lt;/Text&gt;</pre>
We then create a Text Input component to store the name of the User to be added to the face tracker, if the client decides to do so.
<pre class="EnlighterJSRAW" data-enlighter-language="null">&lt;TextInput style = {styles.input}
         underlineColorAndroid = "transparent"
         placeholder = "Name"
         placeholderTextColor = "#9a73ef"
         autoCapitalize = "none"
         onChangeText = {this.handleText}/&gt;</pre>
Lastly, we create a submit button with TouchableOpacity to publish the added user's name for our Face Tracker to add to the system:
<pre class="EnlighterJSRAW" data-enlighter-language="null">&lt;TouchableOpacity
    style = {styles.submitButton}
    onPress = {
      () =&gt; this.publishName(this.state.text)
    }&gt;
      &lt;Text&gt;"SUBMIT"&lt;/Text&gt;
&lt;/TouchableOpacity&gt;</pre>
<span style="font-weight: 400;">Wrap all those components in a </span><b>&lt;View&gt; &lt;/View&gt;</b><span style="font-weight: 400;"> and you’re good to go!</span>
<h2>Running the Program</h2>
<span style="font-weight: 400;">First, start up the React Native client application on Android or iOS by opening a terminal in the client app's directory.</span>
<pre class="EnlighterJSRAW" data-enlighter-language="null">react-native run-ios

or

react-native run-android</pre>
Then, in another terminal window, run the Python face tracker.
<pre class="EnlighterJSRAW" data-enlighter-language="null">python facetracker.py</pre>
<h2>If You're Still Hungry For More...</h2>
Feel free to send us any of your questions, concerns, or comments at devrel@pubnub.com.

If you’re still hungry for more PubNub Machine Learning content, here are some other articles that you may be interested in:
<ul>
 	<li><a href="https://www.pubnub.com/blog/realtime-machine-learning-online-learning-with-pubnub/" target="_blank" rel="noopener noreferrer">Realtime Machine Learning: Online Learning with PubNub</a></li>
 	<li><a href="https://www.pubnub.com/blog/pubnub-and-machine-learning-algorithm/" target="_blank" rel="noopener noreferrer">How PubNub Can Turbocharge Your Machine Learning Algorithm</a></li>
 	<li><a href="https://www.pubnub.com/blog/cognitive-era-big-data-realtime-edge-computing/">The Cognitive Era: Big Data, Realtime, and the Edge (Computing)</a></li>
</ul>