# Facial Detection and Recognition with MEMENTO

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/127/575/medium800thumb/adafruit_products_herogif-ezgif.com-video-to-gif-converter.jpg?1707411811)

Want to play around with computer vision "at the edge" without the overhead and complexity of compiling a dataset and training a model?

Upload the code in this guide to your Adafruit MEMENTO Camera Board and **turn the MEMENTO into a camera that can both detect and recognize faces**!

**Going further** - the example code in this guide may be used and modified to build your next facial detection or recognition electronics project!&nbsp;

### About the code in this guide

This project uses an example written by Me-No-Dev for Espressif Systems, [CameraWebServer.ino](https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/Camera/CameraWebServer). This example was modified by the author of this guide to reduce the flash size overhead (we removed the web functionality, isolated the face detection/recognition calls, brought this overhead into **main.cpp** and **ra\_filter.h** ), add compatibility for the Adafruit MEMENTO development board (added camera compatibility and added "blitting" the camera's raw image to the MEMENTO's TFT instead of to a webpage), set up a PlatformIO build environment to decrease compile time, and created an interactive demo around the code.

## Parts
Featured
### MEMENTO - Python Programmable DIY Camera - Bare Board

[MEMENTO - Python Programmable DIY Camera - Bare Board](https://www.adafruit.com/product/5420)
Make memories, or just a cool camera-based project,&nbsp;with **Adafruit's MEMENTO Camera Board**. It's a development board with everything you need to create programmable camera and vision projects: with a camera module, TFT preview screen, buttons, SD card slot and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5420)
[Related Guides to the Product](https://learn.adafruit.com/products/5420/guides)
![Video of a DIY camera on a lazy susan.](https://cdn-shop.adafruit.com/product-videos/640x480/5420-05.jpg)

### Pink and Purple Woven USB A to USB C Cable - 1 meter long

[Pink and Purple Woven USB A to USB C Cable - 1 meter long](https://www.adafruit.com/product/5153)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers, and more.&nbsp;&nbsp;[If you want something just like it but for Micro B, we...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5153)
[Related Guides to the Product](https://learn.adafruit.com/products/5153/guides)
![Angled shot of coiled pink and purple USB cable with USB A and USB C connectors.](https://cdn-shop.adafruit.com/640x480/5153-02.jpg)

### 256MB Micro SD Memory Card

[256MB Micro SD Memory Card](https://www.adafruit.com/product/5251)
Add storage in a jiffy using this **256MB microSD card**. Preformatted to FAT32, so it works out of the packaging with our projects. Works great with any device in the Adafruit shop that uses microSD cards. Ideal for use with Feathers, data loggers, or small Linux SBCs (not good...

In Stock
[Buy Now](https://www.adafruit.com/product/5251)
[Related Guides to the Product](https://learn.adafruit.com/products/5251/guides)
![Angled shot of Small microSD card 256mb](https://cdn-shop.adafruit.com/640x480/5251-00.jpg)

### Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh

[Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh](https://www.adafruit.com/product/4236)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 420mAh for a total of about 1.55 Wh. If you need a larger (or smaller!) battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4236)
[Related Guides to the Product](https://learn.adafruit.com/products/4236/guides)
![Lithium Ion Polymer Battery 3.7v 420mAh with JST 2-PH connector and short cable](https://cdn-shop.adafruit.com/640x480/4236-04.jpg)

You also may want an RGBW LED Ring with 8 bright NeoPixels. We include this with the MEMENTO Camera Enclosure Kit:

Featured
### Adafruit MEMENTO Camera Enclosure & Hardware Kit

[Adafruit MEMENTO Camera Enclosure & Hardware Kit](https://www.adafruit.com/product/5843)
Once you've picked up your **MEMENTO Camera** and you're ready to take it out into the world, here is a chic and minimalist enclosure that will look great on the runways of Paris or the street photography of New York City! These front and back plates have been...

In Stock
[Buy Now](https://www.adafruit.com/product/5843)
[Related Guides to the Product](https://learn.adafruit.com/products/5843/guides)
![Overhead shot of two square-shaped PCB boards for a DIY camera above eight black plastic screws and four black plastic hex nuts with 3pin to 3pin JST PH cable and adhesive sticker.](https://cdn-shop.adafruit.com/640x480/5843-05.jpg)

If you do not have the MEMENTO Camera Enclosure Kit (or if it is out of stock), you can build your own ring light for the MEMENTO using the following parts:

Featured
### NeoPixel Ring - 12 x 5050 RGBW LEDs w/ Integrated Drivers

[NeoPixel Ring - 12 x 5050 RGBW LEDs w/ Integrated Drivers](https://www.adafruit.com/product/2852)
What is better than smart RGB LEDs? Smart RGB+White LEDs! These NeoPixel rings now have 4 LEDs in them (red, green, blue _and_ white) for excellent lighting effects. Round and round and round they go! &nbsp;

**This is the 12 LED RGBW NeoPixel Ring in Natural White**....

In Stock
[Buy Now](https://www.adafruit.com/product/2852)
[Related Guides to the Product](https://learn.adafruit.com/products/2852/guides)
![NeoPixel Ring with 12 x 5050 RGBW LEDs lighting up rainbow and white](https://cdn-shop.adafruit.com/product-videos/640x480/2852-01.jpg)

Featured
### JST PH 2mm 3-pin Plug-Plug Cable - 100mm long

[JST PH 2mm 3-pin Plug-Plug Cable - 100mm long](https://www.adafruit.com/product/4336)
This cable is a little over 100mm / 4" long&nbsp;and fitted with JST-PH 3-pin connectors on either end.&nbsp;

We dig the solid and compact nature of these connectors and the latch that keeps the cable from coming apart easily. We're carrying these to <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4336)
[Related Guides to the Product](https://learn.adafruit.com/products/4336/guides)
![Angled shot of JST PH 3-pin Plug-Plug Cable - 100mm long.](https://cdn-shop.adafruit.com/640x480/4336-01.jpg)

# Facial Detection and Recognition with MEMENTO

## Wiring

### Wiring using the MEMENTO Camera Enclosure Kit
If you are using the [Adafruit MEMENTO Camera Enclosure Kit](https://www.adafruit.com/product/5843) with this guide, use the included JST cable to connect the _Adafruit MEMENTO Camera LED Ring Front Plate_ 3-pin JST Connector and the 3-pin JST connector labeled A1 on the MEMENTO.

### Wiring without the MEMENTO Camera Enclosure Kit
If you do not have the MEMENTO Camera Enclosure Kit (or if it is out of stock), you can build your own ring light for the MEMENTO using the following parts:

Featured
### NeoPixel Ring - 12 x 5050 RGBW LEDs w/ Integrated Drivers

[NeoPixel Ring - 12 x 5050 RGBW LEDs w/ Integrated Drivers](https://www.adafruit.com/product/2852)
What is better than smart RGB LEDs? Smart RGB+White LEDs! These NeoPixel rings now have 4 LEDs in them (red, green, blue _and_ white) for excellent lighting effects. Round and round and round they go! &nbsp;

**This is the 12 LED RGBW NeoPixel Ring in Natural White**....

In Stock
[Buy Now](https://www.adafruit.com/product/2852)
[Related Guides to the Product](https://learn.adafruit.com/products/2852/guides)
![NeoPixel Ring with 12 x 5050 RGBW LEDs lighting up rainbow and white](https://cdn-shop.adafruit.com/product-videos/640x480/2852-01.jpg)

Featured
### JST PH 2mm 3-pin Plug-Plug Cable - 100mm long

[JST PH 2mm 3-pin Plug-Plug Cable - 100mm long](https://www.adafruit.com/product/4336)
This cable is a little over 100mm / 4" long&nbsp;and fitted with JST-PH 3-pin connectors on either end.&nbsp;

We dig the solid and compact nature of these connectors and the latch that keeps the cable from coming apart easily. We're carrying these to <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4336)
[Related Guides to the Product](https://learn.adafruit.com/products/4336/guides)
![Angled shot of JST PH 3-pin Plug-Plug Cable - 100mm long.](https://cdn-shop.adafruit.com/640x480/4336-01.jpg)

You must cut the JST PH 3-pin cable in half using a wire cutter. Using a soldering iron, make the following connections between the cable and the NeoPixel ring.&nbsp;

- **JST VCC (red wire)** to **NeoPixel PWR**
- **JST GND (black wire)** to **NeoPixel GND**
- **JST Data (white wire)** to **NeoPixel Data In**

Then, plug the cable into the MEMENTO's A1 JST port.

![adafruit_products_memento-fdfr-camera_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/127/576/medium640/adafruit_products_memento-fdfr-camera_bb.png?1707412828)

# Facial Detection and Recognition with MEMENTO

## Upload Code

## Upload Code using&nbsp;Web Serial ESPTool

The WebSerial ESPTool was designed to be a web-capable option for programming Espressif ESP family microcontroller boards that have a serial-based ROM bootloader. It allows you to erase the contents of the microcontroller and program up to 4 files at different offsets.

For boards that lack native USB, like the ESP32 or ESP32-C3 microcontroller, this is how any firmware like CircuitPython&nbsp; **.bin** &nbsp;files can be loaded.&nbsp; **There is no drag-and-drop to a folder option for these boards.**

For boards with native USB, like ESP32-S2, -S3, etc. this is how the UF2 bootloader&nbsp; **.bin** &nbsp;file can be loaded. Once the UF2 bootloader is on, firmware like CircuitPython&nbsp; **.uf2** &nbsp;files can be drag-and-dropped to a&nbsp; **BOOT** &nbsp;folder.

This tool is a good alternative for folks who cannot run Python&nbsp; **esptool.py** &nbsp;on their computer or are having difficulty installing or using&nbsp; **esptool.py**.

Info: Web Serial support requires at least Firefox 151 or a Chrome-89-based browser.

### Enable Web Serial (older Chrome versions)
If you have an ancient version of Chrome, before Chome 89, you'll need to enable the Serial API, which is easy.

Visit&nbsp;&nbsp; **chrome://flags** &nbsp;from within Chrome. Find and enable the&nbsp; **Experimental Web Platform features**

**Restart Chrome**

![adafruit_products_Enable_Features.jpg](https://cdn-learn.adafruit.com/assets/assets/000/127/459/medium640/adafruit_products_Enable_Features.jpg?1706906912)

## Allowing Web Serial in Firefox

As a general security measure, [site permission](https://support.mozilla.org/en-US/kb/site-permission-add-ons) will need to be granted to allow Web Serial access in Firefox. This should only be required the first time you access the web page since Firefox will save (remember) the permission. If you want to remove this permission later, see how to&nbsp;[manage extensions](https://support.mozilla.org/en-US/kb/extensions-button).

When you click the **Connect** button on the [Adafruit WebSerial page](https://adafruit.github.io/Adafruit_WebSerial_ESPTool/), a dialog will appear requesting permissions to install an add-on. The "add-on" here is the serial access and this is site specific. So make sure you are actually on the [Adafruit WebSerial page](https://adafruit.github.io/Adafruit_WebSerial_ESPTool/)&nbsp;first.

Click the&nbsp; **Continue to installation** button.

![](https://cdn-learn.adafruit.com/assets/assets/000/144/272/medium640/adafruit_products_ff_addon_diag1.png?1779468229)

A second dialog will appear asking to verify enabling the "add-on".

Click **Add**.

![](https://cdn-learn.adafruit.com/assets/assets/000/144/273/medium640/adafruit_products_ff_addon_diag2.png?1779468257)

And finally it will provide a drop down selection dialog to select the actual COM port.

Select the COM port for the board being programmed.

![](https://cdn-learn.adafruit.com/assets/assets/000/144/274/medium640/adafruit_products_ff_addon_diag3.png?1779468288)

### Enter Bootloader Mode

Before you can use the tool, you will need to put your board in bootloader mode. **Before you start, make sure your ESP32-S2/S3 is plugged into a USB port to your computer using a data/sync cable.** &nbsp;Charge-only cables will not work!

**Turn on the On/Off switch** &nbsp;- check that you see the green power light on so you know the board is powered, a prerequisite!

To enter the bootloader:

1. **Press and hold the BOOT/DFU button down (green box).**&nbsp;Don't let go of it yet!
2. **Press and release the Reset button (red box).**&nbsp;You should still have the BOOT/DFU button pressed while you do this.
3. **Now you can release the BOOT/DFU button.**

![](https://cdn-learn.adafruit.com/assets/assets/000/127/460/medium800/adafruit_products_bootReset.jpg?1706907056)

No USB drive will appear when you've entered the ROM bootloader. This is normal!

## Download the application for your board

Click the button below to download the application binary file for your board.

[Download Firmware for MEMENTO Face Detection and Recognition](https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/main/MEMENTO/Memento_Face_Detect_Recognize)
## Connect and Upload

You should have plugged in&nbsp; **only the MEMENTO board that you intend to flash**. That way there's no confusion in picking the proper port when it's time!

In the Chrome browser visit [https://adafruit.github.io/Adafruit\_WebSerial\_ESPTool/](https://adafruit.github.io/Adafruit_WebSerial_ESPTool/). You should see something like the image shown.

![factory_reset___esp32_s2_s3_adafruit_products_ESPTool.png](https://cdn-learn.adafruit.com/assets/assets/000/127/461/medium640/factory_reset___esp32_s2_s3_adafruit_products_ESPTool.png?1706907329)

Press the&nbsp; **Connect** button in the top right of the web browser. You will get a pop-up asking you to select the COM or Serial port.

**Remember, you should remove all other USB devices so&nbsp;**** _only_&nbsp;the ESP32-S2/S3 board is attached, that way there's no confusion over multiple ports!**

On some systems, such as MacOS, there may be additional system ports that appear in the list.

![adafruit_products_factory_reset___esp32_s2_s3_Select_Device.png](https://cdn-learn.adafruit.com/assets/assets/000/127/462/medium640/adafruit_products_factory_reset___esp32_s2_s3_Select_Device.png?1706907389)

The JavaScript code will now try to connect to the ROM bootloader. It may time out for a bit until it succeeds. On success, you will see that it is **Connected** and will print out a unique **MAC address** identifying the board along with other information that was detected.

![adafruit_products_factory_reset___esp32_s2_Screen_Shot_2022-04-04_at_3.16.00_PM_(1).png](https://cdn-learn.adafruit.com/assets/assets/000/127/463/medium640/adafruit_products_factory_reset___esp32_s2_Screen_Shot_2022-04-04_at_3.16.00_PM_%281%29.png?1706907433)

On the top of the tool, ensure the offset is set to `0x0` and click _"Choose a File..."_

From the file browser, select the .bin file you downloaded earlier.

![adafruit_products_choose_file.png](https://cdn-learn.adafruit.com/assets/assets/000/127/481/medium640/adafruit_products_choose_file.png?1707158390)

Click _Program_ and the binary will be uploaded to your MEMENTO board.

![adafruit_products_program.png](https://cdn-learn.adafruit.com/assets/assets/000/127/483/medium640/adafruit_products_program.png?1707158607)

After the binary is uploaded to the MEMENTO, the console will instruct you to reset your device.

**Press the RESET button on the MEMENTO**. You should see the MEMENTO's screen briefly glow green, then show a preview of what the camera is seeing.

![adafruit_products_fw_done_upload.png](https://cdn-learn.adafruit.com/assets/assets/000/127/485/medium640/adafruit_products_fw_done_upload.png?1707158646)

# Facial Detection and Recognition with MEMENTO

## Usage

This application switches between two modes, face _detection_ and face _recognition_.&nbsp;

What's the difference?

Face _detection_ identifies when _any_ face is present whereas face _recognition&nbsp;_can identify a _specific_ face.&nbsp;Performing face detection is faster than performing face recognition. In face recognition, algorithms not only detect the face but also attempt to identify similarities between faces.

## Face Detection

After uploading the code and pressing RESET, the MEMENTO's screen displays what the camera module sees.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/496/medium800thumb/adafruit_products_memento-no-tracking-ezgif.com-video-to-gif-converter.jpg?1707245232)

Move your face in front of the camera. If a face is detected by the MEMENTO, the screen displays the text, _"DETECTED FACE!"._&nbsp; A bounding box is drawn around the face and contains facial landmarks within it.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/507/medium800/adafruit_products_det_face_text.png?1707248552)

## Face Detection Explanation

To understand what's happening in this demo, let's define a few terms first:

_What is the green box around my face?_

![](https://cdn-learn.adafruit.com/assets/assets/000/127/514/medium800/adafruit_products_Pasted_Image_2_6_24__4_33_PM.png?1707255255)

In computer vision, the green box around an object is called a [_bounding box_](https://developers.google.com/machine-learning/glossary#bounding-box). This box contains the x and y coordinates (the boundaries) of the detected object.

_What are the points placed over my face?_

![](https://cdn-learn.adafruit.com/assets/assets/000/127/513/medium800/adafruit_products_2Pasted_Image_2_6_24__4_33_PM.png?1707255239)

These points are called [landmarks](https://en.wikipedia.org/wiki/Landmark_detection#Facial_landmarks). The landmarks identified by this demo are facial landmarks, such as your left eye, mouth (left corner), nose, right eye, and mouth (right corner). Landmarks are primarily used for facial recognition but also can be used for emotional/mood analysis or pose detection.

## Face Recognition

Unlike the face detection demo which runs automatically, face recognition has a few steps. Before we can detect a face, the face needs to be _enrolled_ first.

To enroll a new face, press the shutter button on the MEMENTO.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/486/medium800/adafruit_products_shutter_btn.png?1707166538)

After pressing the shutter, the NeoPixel ring emits a white light to illuminate a face. The light indicates the MEMENTO is in "face enroll mode" and is attempting to detect a face.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/510/medium800thumb/adafruit_products_shutter-press-ezgif.com-video-to-gif-converter.jpg?1707250056)

Move your face in front of the camera. If a face is detected, the screen will briefly display _Enrolled a new face with ID #0_ and the NeoPixel ring will turn off.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/516/medium800thumb/adafruit_products_enroll-face-ezgif.com-video-to-gif-converter.jpg?1707256366)

The next time the same face is moved in front of the camera, it will recognize it and the NeoPixel ring will turn green.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/548/medium800/adafruit_products_IMG_8154.jpg?1707325973)

When you point the camera at a different, unrelated, face, the NeoPixel ring will glow red to indicate that the camera has detected a face but it is not one of the enrolled faces.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/549/medium800/adafruit_products_red.png?1707326027)

## Going Further - "Tricking" the Facial Recognition

Since the facial recognition demo runs on an embedded system, Ladyada asked me to try out both the recognition performed by the MEMENTO's ESP32x and my iPhone's FaceID.

To attempt to test the face recognition code further, I went with something basic. I took a photo of my face and printed it out on printer paper.

![adafruit_products_print.png](https://cdn-learn.adafruit.com/assets/assets/000/127/492/medium640/adafruit_products_print.png?1707338016)

Then,&nbsp;I placed the MEMENTO into the enrollment mode and enrolled my face.

&nbsp;

![adafruit_products_enroll-face-ezgif.com-video-to-gif-converter.gif](https://cdn-learn.adafruit.com/assets/assets/000/127/515/medium640thumb/adafruit_products_enroll-face-ezgif.com-video-to-gif-converter.jpg?1707337993)

After enrolling my face, I placed the&nbsp;_photo&nbsp;_of my face in front of the camera. It was recognized by the MEMENTO and lit up the NeoPixels with a green light.

![adafruit_products_IMG_8171.jpg](https://cdn-learn.adafruit.com/assets/assets/000/127/572/medium640/adafruit_products_IMG_8171.jpg?1707337937)

However, my iPhone did not recognize the photo of my face. Even holding the photo in different lighting did not help.

_Why?_

The iPhone uses a more advanced version of facial recognition called [Face ID](https://en.wikipedia.org/wiki/Face_ID). This system doesn't identify a face using a camera module like the MEMENTO code does, it performs recognition on the _depth_ of the image.

Face ID begins by projecting over 30,000 infrared (invisible) "dots" onto your face. A module then projects infrared light on your face and an infrared camera takes a picture of the dots.&nbsp;

![Face ID. (2023, December 25). In Wikipedia. https://en.wikipedia.org/wiki/Face_ID](https://cdn-learn.adafruit.com/assets/assets/000/127/493/medium800/adafruit_products_Apple_Face_ID_infrared_dot_projector.jpg?1707240353 Face ID. (2023, December 25). In Wikipedia. https://en.wikipedia.org/wiki/Face_ID)

The pattern is then securely stored as a "map" (shown by the image above) in the iPhone's storage. The next time you put your iPhone up to your face, the camera will generate a new map and try to match it to the saved map.

Earlier on this page, we discussed landmarks as the method of identifying features for facial recognition. This is similar, except Face ID identifies over 30,000 landmark points compared to the MEMENTO which identifies 6 landmarks.

# Facial Detection and Recognition with MEMENTO

## Code Walkthrough

## Example/Demo Code History and Explanation

This project uses an example written by Me-No-Dev for Espressif Systems named [CameraWebServer.ino](https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/Camera/CameraWebServer). The example was modified by the author of this guide for Adafruit Industries to reduce the flash size overhead (we removed the web server functionality, isolated the face detection/recognition calls, brought this overhead into **main.cpp** and **ra\_filter.h** ), add compatibility for the Adafruit MEMENTO development board (added camera compatibility and added "blitting" the camera's raw image to the MEMENTO's TFT instead of to a webpage), and build an interactive demo around it.

So, since this is a larger codebase than a typical learn project and we only modified the code, this page won't explain _everything_ that CameraWebServer does. It will explain the important and modifiable code segments within **main.cpp**.

## Capturing a photo

Most applications for a digital camera like the MEMENTO require the camera to save photos in a compressed file format (like JPEG) to save space on the SD card and a large resolution, we found the facial detection code runs fastest with a smaller frame size (240x240px) and the RGB565 raw bitmap.

Within **main.cpp** , the `initCamera()` function handles initializing the MEMENTO's camera. This code segment configures the camera's frame size to 240x240px and its pixel format to RGB565.

```auto
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.frame_size = FRAMESIZE_240X240;
config.pixel_format = PIXFORMAT_RGB565;
config.fb_count = 2;
```

Within the `loop()`, we don't need to perform conversion from RGB565 to another format or resolution. The code tells the camera to take a picture and then stores it in a frame buffer.

```auto
// capture from the camera into the frame buffer
Serial.printf("Capturing frame...\n");
fb = esp_camera_fb_get();
if (!fb) {
Serial.printf("ERROR: Camera capture failed\n");
} else {
Serial.printf("Frame capture successful!\n");
...
}
```

## Face Detection

After a frame (photo) is successfully captured, the code performs face detection. In this example, the code runs two stages of inference.

In the first stage,&nbsp;inference on a model (`s1`) to detect objects is performed. The `s1.infer()` function call performs inference on the image, stored in the framebuffer (`fb`). If any objects are detected, they're stored in `candidates`.

```auto
Serial.printf("Frame capture successful!\n");
// Face detection
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
```

The second line runs another inference on a different model, `s2`. This call uses the objects detected in the first stage to then attempt to detect faces. Faces are stored in the `results` list.

```auto
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
```

When a face is detected, the list of results will be non-zero. The code prints that a face has been detected. The face detection boxes and landmarks are drawn to the TFT in the `draw_face_boxes` function.

```auto
if (results.size() > 0) {
  Serial.println("Detected face!");
  ...
  // Draw face detection boxes and landmarks on the framebuffer
  draw_face_boxes(&rfb, &results, face_id);
  ...
}
```

Finally, the 240x240px frame buffer is drawn to the TFT display. Since the next iteration of `loop()` requires the use of the frame buffer, `fb`, to take a photo, we release it.

```auto
// Blit framebuffer to TFT
uint8_t temp;
for (uint32_t i = 0; i < fb->len; i += 2) {
  temp = fb->buf[i + 0];
  fb->buf[i + 0] = fb->buf[i + 1];
  fb->buf[i + 1] = temp;
}
pyCameraFb->setFB((uint16_t *)fb->buf);
tft.drawRGBBitmap(0, 0, (uint16_t *)pyCameraFb->getBuffer(), 240, 240);
// Release the framebuffer
esp_camera_fb_return(fb);
```

## Face Recognition

To recognize a face, the code takes a picture and performs face detection (explained above) on the frame.

```auto
...
Serial.printf("Frame capture successful!\n");
// Face detection
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
if (results.size() > 0) {
  Serial.println("Detected face!");
...
```

A structure holding the frame buffer data, `rfb`, is created and data is copied from the frame buffer (`fb`) to the new structure.

```auto
int face_id = 0;
fb_data_t rfb;
rfb.width = fb->width;
rfb.height = fb->height;
rfb.data = fb->buf;
rfb.bytes_per_pixel = 2;
rfb.format = FB_RGB565;
...
```

Since face recognition is a _slow_ operation to perform. The code only attempts it if it detected a face and is enrolling the face, or if a face was previously enrolled. The `run_face_recognition` method is called with the copy of frame buffer data and the `results` from the second inference function.

```auto
if (recognizer.get_enrolled_id_num() > 0 || is_enrolling) {
	face_id = run_face_recognition(&rfb, &results);
}
...
```

Within the `run_face_recognition` function, a vector of landmarks (discussed on the "Usage" page of this guide) is created from the inference results. Then, a `tensor` multi-dimensional array is created and shaped to fit the framebuffer's data.

```auto
std::vector<int> landmarks = results->front().keypoint;
int id = -1;
(void)id;

Tensor<uint8_t> tensor;
tensor.set_element((uint8_t *)fb->data)
	.set_shape({fb->height, fb->width, 3})
	.set_auto_free(false);
```

### Enrolling a New Face

The function obtains the amount of faces which are currently enrolled. Then, it verifies if the MEMENTO is in enroll-mode and if the number of faces enrolled is less than the maximum.

If that condition is true, the code proceeds to enroll a new face and assign it a face identifier number. The serial and TFT print the new enrolled identifier and disables the enroll mode (`is_enrolling = false`).

```auto
int enrolled_count = recognizer.get_enrolled_id_num();
if (enrolled_count < FACE_ID_SAVE_NUMBER && is_enrolling) {
int id = recognizer.enroll_id(tensor, landmarks, "", true);
    Serial.printf("Enrolled ID: %d", id);
    tft.setCursor(0, 230);
    tft.setTextColor(ST77XX_CYAN);
    tft.print("Enrolled a new face with ID #");
    tft.print(id);
    is_enrolling = false;
```

### Recognizing a Face

The results of the facial recognition model, `recognizer` are stored in `recognize`, a structure containing the face similarity value (measuring the similarity between the frame's landmarks and the landmarks on the saved face).

```auto
face_info_t recognize = recognizer.recognize(tensor, landmarks);
```

The `recognize` similairity value weighs the image's assessed similarity value against a saved face's similairity value. 

The similairity values range from `0.0` to `1.0`, where a value of `1.0` is a "confident positive match". In order to avoid a _false positive_ (the code "recognizes" an invalid face), we added a confidence threshold. This threshold, `FR_CONFIDENCE_THRESHOLD`, is used to detect how "confident" the match is by comparing it to the similiarity value.

If the code did did not have a confidence threshold, the code recognizes a face with much lower accuracy and possibly raises false positive or false negative matches.

In the code segment below, if the face is recognized (and its  similarity value is larger than the `FR_CONFIDENCE_THRESHOLD` value), the MEMENTO's display shows that a face has been recognized and the NeoPixel ring lights up green.

```auto
if (recognize.id >= 0 && recognize.similarity >= FR_CONFIDENCE_THRESHOLD) {
    // Face was recognized, print out to serial and TFT
    Serial.printf("Recognized ID: %d", recognize.id);
    Serial.printf("with similarity of: %0.2f", recognize.similarity);
    tft.setCursor(0, 220);
    tft.setTextColor(ST77XX_CYAN);
    tft.print("Recognized Face ID #");
    tft.print(id);
    tft.print("\nSimilarity: ");
    tft.print(recognize.similarity);
    // Set pixel ring to green to indicate a recognized face
    for (int i = 0; i <= NUMPIXELS; i++) {
      pixels.setPixelColor(i, pixels.Color(0, 255, 0));
    }
    pixels.show();
    delay(2500);
  }
```

If the code did not recognize a face, but other faces are enrolled, the TFT prints "Intruder alert" and the NeoPixel ring shows a red color.

```auto
} else if (recognizer.get_enrolled_id_num() > 0) {
  // Face was not recognized but we have faces enrolled
  Serial.println("Intruder alert - face not recognized as an enrolled face!");
  Serial.printf("This face has a similarity of: %0.2f\n",
  recognize.similarity);
  // Set pixel ring to green to indicate a recognized face
  for (int i = 0; i <= NUMPIXELS; i++) {
  pixels.setPixelColor(i, pixels.Color(255, 0, 0));
  }
  pixels.show();
  delay(1000);
}
...
```

### Adjust the Confidence Threshold

The confidence threshold,&nbsp;`FR_CONFIDENCE_THRESHOLD`, determines how "confident" the face match is by comparing it to a similarity value.

If the confidence threshold value is too low, the code may incorrectly recognize a face. If the value is too high, the code may not recognize a face unless there is an exact match between the enrolled face and the image you just took.

To adjust this value in code, you will need to adjust the value of `FR_CONFIDENCE_THRESHOLD` to a number between 0.0 and 1.0, where 1.0 is an exact match:

```auto
// Threshold (0.0 - 1.0) to determine whether the face detected is a positive
// match NOTE - This value is adjustable, you may "tune" it for either a more
// confident match
#define FR_CONFIDENCE_THRESHOLD 0.7
```

Then, you will need to build and upload the code. This is discussed on the _Modify Code using PlatformIO&nbsp;_page of this guide.

### Save Faces to Flash Memory

This code does not save the enrolled faces if the MEMENTO is rebooted. However, if you want to "lock" the code to save the enrolled faces between device reboots, you will need to set the following variable to **true**.

```auto
// True if you want to save faces to flash memory and load them on boot, False
// otherwise
#define SAVE_FACES_TO_FLASH false
```

Then, you will need to build and upload the code. This is discussed on the _Modify Code using PlatformIO&nbsp;_page of this guide.

### Adjust the Number of Recognized Faces

The demo provided in this guide recognizes a maximum of four faces. If you want to recognize more faces, the following variable will need to be modified.&nbsp;

```auto
// The number of faces to save
// NOTE - these faces are saved to the ESP32's flash memory and survive between
// reboots
#define FACE_ID_SAVE_NUMBER 4
```

Increasing the `FACE_ID_SAVE_NUMBER` increases the amount of time required to recognize a new face. After adjusting this number, you will need to build and upload the code to the MEMENTO. This is discussed on the&nbsp;_Modify Code using PlatformIO&nbsp;_page of this guide.

# Facial Detection and Recognition with MEMENTO

## Restoring MEMENTO Demo and UF2 Bootloader

You're probably used to seeing the&nbsp; **CAMERABOOT** &nbsp;drive when loading CircuitPython or Arduino. The&nbsp; **CAMERABOOT** &nbsp;drive is part of the UF2 bootloader and allows you to drag and drop files, such as CircuitPython.&nbsp; However, the application in this guide uses a large partition size, which overwrites the UF2 bootloader present on the MEMENTO.

This means that after installing the facial detection application, double-tapping the RESET button will not put your MEMENTO into bootloader mode.&nbsp;

However, you can get your MEMENTO back to "normal" by writing a new binary application to the board that repairs your board's UF2 bootloader and performs a factory reset:

[Instructions for MEMENTO Factory Reset and Bootloader Repair](https://learn.adafruit.com/adafruit-memento-camera-board/factory-reset#factory-reset-and-bootloader-repair-3107941)
# Facial Detection and Recognition with MEMENTO

## Modify Code using PlatformIO

Warning: 

This project library brings in a&nbsp;_considerable_&nbsp;_number_&nbsp;of dependencies and takes a&nbsp;_looong&nbsp;_time to compile using Arduino IDE. If you want to modify the code in this guide, you'll want to compile the project using PlatformIO rather than Arduino IDE.

## Install PlatformIO

Follow this page's instructions to install PlatformIO and Visual Studio Code (the IDE of choice for using PlatformIO).

[Download and Install PlatformIO](https://platformio.org/install/ide?install=vscode)
## Configure Your Workspace

The ZIP file below includes a pre-configured workspace for using PlatformIO.&nbsp; **Download and unzip this file**. Then, save it somewhere safe, like your desktop.

[Download Project Code and PlatformIO Environment](https://github.com/adafruit/Adafruit_Learning_System_Guides/raw/main/MEMENTO/Memento_Face_Detect_Recognize/memento_platformio_camera.zip)
Open Visual Studio Code (VSCode). To ensure you have installed the PlatformIO extension properly,&nbsp; **look for the alien symbol in your VSCode sidebar.**

![](https://cdn-learn.adafruit.com/assets/assets/000/127/466/medium800/adafruit_products_vscode.png?1707146655)

Underneath Start,&nbsp; **click&nbsp;_Open..._**

![](https://cdn-learn.adafruit.com/assets/assets/000/127/467/medium800/adafruit_products_open.png?1707146708)

 **Navigate to the folder created when you unzipped the zip file. Then, Click Open** &nbsp;to open the workspace.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/468/medium800/adafruit_products_memento_vscode_fd_cam.png?1707146927)

A large amount of configuration files and directories will appear in your VSCode instance.

To compile this code, we are only going to discuss the following files and directories:

- **platformio.ini** &nbsp;- This is the project configuration file used to build the demo code. More&nbsp;[documentation about this file is located here](https://docs.platformio.org/en/latest/projectconf/index.html).
- **lib** &nbsp;directory -&nbsp;This directory is intended for project-specific (private) libraries. PlatformIO will compile them to static libraries and link them into executable files.
  - For our project, the specific library within this directory is the&nbsp;[Adafruit\_PyCamera](https://github.com/adafruit/Adafruit_PyCamera/)&nbsp;library.&nbsp;

- **src** directory - The directory where the project's source code, **main.cpp** , is located as well as the included headers (such as **ra\_filter.h** which stores the facial recognition/detection overhead).&nbsp;

## Build and Upload with PlatformIO

Before the code is built, you'll need to make two changes to the platformio.ini file:

- Change&nbsp;`upload_port`&nbsp;to reflect the MEMENTO's upload port.&nbsp;
  - Don't know the desired port? We have steps to find them for&nbsp;[Windows](https://learn.adafruit.com/adafruit-memento-camera-board/advanced-serial-console-on-windows#whats-the-com-2977217),&nbsp;[MacOS](https://learn.adafruit.com/adafruit-memento-camera-board/advanced-serial-console-on-mac-and-linux#whats-the-port-2977243), and&nbsp;[Linux](https://learn.adafruit.com/adafruit-memento-camera-board/advanced-serial-console-on-linux).

- The&nbsp;`monitor_port`&nbsp;is different from the&nbsp;`upload_port`, and will only appear on your computer when you've uploaded the test code. For now, leave this alone.
  - After uploading the test code, change&nbsp;`monitor_port`&nbsp;to reflect the MEMENTO's monitor/serial port.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/469/medium800/adafruit_products_pio_ini.png?1707147298)

Navigate to&nbsp;`src/main.cpp`&nbsp;to open the example code.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/470/medium800/adafruit_products_main.png?1707147359)

With this file open,&nbsp; **click the Alien symbol on the VSCode sidebar** &nbsp;to open the PlatformIO Project Explorer.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/472/medium800/adafruit_products_pio_alien.png?1707147801)

Underneath PlatformIO's Project Tasks, click&nbsp; **Build**.&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/127/473/medium800/adafruit_products_build_task.png?1707147811)

Once the build task is completed, the terminal will show&nbsp;`SUCCESS`&nbsp;along with the time it took to compile the project.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/474/medium800/adafruit_products_build_suc.png?1707147851)

Before uploading this project to the board,&nbsp;[put the board into ROM Bootloader Mode](https://learn.adafruit.com/adafruit-memento-camera-board/factory-reset?preview_token=4voYBMZdO8AtkFcVdydTUA#step-2-enter-rom-bootloader-mode-3106832).&nbsp;

From the PlatformIO Project Tasks menu, click&nbsp; **Upload**.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/475/medium800/adafruit_products_upload_task.png?1707150597)

Once the upload completes, the terminal should look like the following screenshot and show&nbsp;`SUCCESS`.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/476/medium800/Cursor_and_adafruit_products_upload_complete_png__2276%C3%971300_.png?1707150631)

Press the RST (Reset) button on the&nbsp;MEMENTO to run the uploaded code.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/477/medium800/adafruit_products_rst.png?1707150653)

After the board resets, you'll see a preview of what the camera module is seeing on the MEMENTO display. Follow the "Usage" page in this guide for detailed usage instructions.

Congrats - you have successfully compiled and uploaded the example code. You may make any modifications or extensions to this code that you'd like!


## Guide Products

### MEMENTO - Python Programmable DIY Camera - Bare Board

[MEMENTO - Python Programmable DIY Camera - Bare Board](https://www.adafruit.com/product/5420)
Make memories, or just a cool camera-based project,&nbsp;with **Adafruit's MEMENTO Camera Board**. It's a development board with everything you need to create programmable camera and vision projects: with a camera module, TFT preview screen, buttons, SD card slot and...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5420)
[Related Guides to the Product](https://learn.adafruit.com/products/5420/guides)
### Pink and Purple Woven USB A to USB C Cable - 1 meter long

[Pink and Purple Woven USB A to USB C Cable - 1 meter long](https://www.adafruit.com/product/5153)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers, and more.&nbsp;&nbsp;[If you want something just like it but for Micro B, we...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5153)
[Related Guides to the Product](https://learn.adafruit.com/products/5153/guides)
### 256MB Micro SD Memory Card

[256MB Micro SD Memory Card](https://www.adafruit.com/product/5251)
Add storage in a jiffy using this **256MB microSD card**. Preformatted to FAT32, so it works out of the packaging with our projects. Works great with any device in the Adafruit shop that uses microSD cards. Ideal for use with Feathers, data loggers, or small Linux SBCs (not good...

In Stock
[Buy Now](https://www.adafruit.com/product/5251)
[Related Guides to the Product](https://learn.adafruit.com/products/5251/guides)
### Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh

[Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh](https://www.adafruit.com/product/4236)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 420mAh for a total of about 1.55 Wh. If you need a larger (or smaller!) battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4236)
[Related Guides to the Product](https://learn.adafruit.com/products/4236/guides)
### Adafruit MEMENTO Camera Enclosure & Hardware Kit

[Adafruit MEMENTO Camera Enclosure & Hardware Kit](https://www.adafruit.com/product/5843)
Once you've picked up your **MEMENTO Camera** and you're ready to take it out into the world, here is a chic and minimalist enclosure that will look great on the runways of Paris or the street photography of New York City! These front and back plates have been...

In Stock
[Buy Now](https://www.adafruit.com/product/5843)
[Related Guides to the Product](https://learn.adafruit.com/products/5843/guides)
### NeoPixel Ring - 12 x 5050 RGBW LEDs w/ Integrated Drivers

[NeoPixel Ring - 12 x 5050 RGBW LEDs w/ Integrated Drivers](https://www.adafruit.com/product/2852)
What is better than smart RGB LEDs? Smart RGB+White LEDs! These NeoPixel rings now have 4 LEDs in them (red, green, blue _and_ white) for excellent lighting effects. Round and round and round they go! &nbsp;

**This is the 12 LED RGBW NeoPixel Ring in Natural White**....

In Stock
[Buy Now](https://www.adafruit.com/product/2852)
[Related Guides to the Product](https://learn.adafruit.com/products/2852/guides)
### JST PH 2mm 3-pin Plug-Plug Cable - 100mm long

[JST PH 2mm 3-pin Plug-Plug Cable - 100mm long](https://www.adafruit.com/product/4336)
This cable is a little over 100mm / 4" long&nbsp;and fitted with JST-PH 3-pin connectors on either end.&nbsp;

We dig the solid and compact nature of these connectors and the latch that keeps the cable from coming apart easily. We're carrying these to <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/4336)
[Related Guides to the Product](https://learn.adafruit.com/products/4336/guides)

## Related Guides

- [Adafruit MEMENTO Camera Board](https://learn.adafruit.com/adafruit-memento-camera-board.md)
- [Qualia S3 Compass](https://learn.adafruit.com/qualia-s3-compass.md)
- [Raspberry Pi Azure IoT Hub Dashboard with CircuitPython](https://learn.adafruit.com/raspberry-pi-iot-dashboard-with-azure-and-circuitpython.md)
- [Mini GIF Players](https://learn.adafruit.com/mini-gif-players.md)
- [Driving TM1814 addressable LEDs](https://learn.adafruit.com/driving-tm1814-addressable-leds.md)
- [MicroLipo v2 Case](https://learn.adafruit.com/microlipo-case.md)
- [IoT Battery Monitor](https://learn.adafruit.com/iot-battery-monitor.md)
- [MagTag Covid Tracking Project IoT Display](https://learn.adafruit.com/magtag-covid-tracking-project-iot-display.md)
- [Pip-Boy 2040 Wrist-Mounted Prop](https://learn.adafruit.com/pip-boy-2040.md)
- [NeoPixel Flame Torch](https://learn.adafruit.com/neopixel-flame-torch.md)
- [4x4 Rotary Encoder MIDI Messenger](https://learn.adafruit.com/4x4-rotary-encoder-midi-messenger.md)
- [MagTag Twitter Display](https://learn.adafruit.com/magtag-twitter-display.md)
- [Wireless LED Juggling Balls with ESP-NOW](https://learn.adafruit.com/wireless-juggling-balls-esp-now.md)
- [QT Py CH32V203 eInk / ePaper Daily Calendar and Clock](https://learn.adafruit.com/ch32v203-eink-epaper-calendar-and-clock.md)
- [Controlling Objects in Unity with a 9 DoF Sensor and Arduino](https://learn.adafruit.com/controlling-objects-in-unity-with-arduino.md)
- [Video Playing 2.1" Round Ornament TFT](https://learn.adafruit.com/2-1-round-ornament-tft.md)
