# Capturing Camera Images with CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/103/269/medium800/camera_PXL_20210630_155133165.jpg?1625070459)

CircuitPython supports capturing images from "parallel cameras" on select boards. You have to select the right module or library depending on the microcontroller family:

- ESP32 family: the built in `espcamera` module configures cameras and captures images
- RP2040 family: the built in&nbsp;`imagcapture` captures images, and camera-specific installable libraries such as `adafruit_ov5640` configure the camera.

While not up to standards we’re used to from a current smartphone or laptop, these camera modules are nicely balanced to the capabilities of recent 32-bit microcontrollers.

Danger: CircuitPython on the Grand Central M4 is prone to locking up when the camera function is used. The Arduino implementation is much more reliable on that board. We recommend using Espressif or RP2040/Pico instead.

The Arduino library for OV7670 cameras on the Grand Central M4 has [its own dedicated guide](https://learn.adafruit.com/adafruit-ov7670-camera-library-samd51).

## Parts

### Items needed

- Compatible microcontroller board & camera, such as  

  - [Adafruit Memento with ESP32-S3](https://www.adafruit.com/product/5420) (if you have this product you may want to proceed to the [dedicated guide](https://learn.adafruit.com/adafruit-memento-camera-board))
  - [Raspberry Pi Pico](https://www.adafruit.com/product/4864) with [PiCowBell Camera](https://www.adafruit.com/product/5945)

- SPI TFT module recommended with Raspberry Pi Pico
- Appropriate USB data + power cable

Warning: 

OV7670, OV5640, and OV2640 camera modules with the 18 pin, 2-row header can be found on Amazon, eBay, etc. Make sure the pinout matches the camera shown above, as occasionally there are incompatible variants. The cameras are sometimes sold in **sets** which is a good idea, as they’re easily damaged with the wrong voltage or rough handling, especially if you need to modify it for use with the Grand Central M4. This guide shows how to wire these cameras, but because there are multiple high speed digital signals, a manufactured PCB is highly recommended!

Other sensor models (such as OV3660) exist, but they require different initialization code and cannot currently be used.

When using `esp32camera`, a wider range of camera boards are supported, but note that the guide author has only tried OV2640 and OV5640. A list of cameras supported by the underlying `esp32camera` library [can be seen on GitHub](https://github.com/adafruit/esp32-camera#supported-sensor).

## Parts
### 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)

### Raspberry Pi Pico RP2040

[Raspberry Pi Pico RP2040](https://www.adafruit.com/product/4864)
The Raspberry Pi foundation changed single-board computing [when they released the Raspberry Pi computer](https://www.raspberrypi.org/archives/723), now they're ready to do the same for microcontrollers with the release of the brand new **Raspberry Pi Pico**. This...

In Stock
[Buy Now](https://www.adafruit.com/product/4864)
[Related Guides to the Product](https://learn.adafruit.com/products/4864/guides)
![Angle shot of Raspberry Pi Pico RP2040](https://cdn-shop.adafruit.com/640x480/4864-00.jpg)

### Adafruit PiCowbell Camera Breakout - Autofocus 72 Degree Lens

[Adafruit PiCowbell Camera Breakout - Autofocus 72 Degree Lens](https://www.adafruit.com/product/5945)
Ding dong! Hear that? It's the PiCowbell ringing, letting you know that the new&nbsp; **Adafruit PiCowbell OV5640 Camera Breakout with 72-Degree Lens and Autofocus** &nbsp;is in stock.

This is&nbsp;a quality OV5640 camera with a 5 Megapixel sensor element, a 72-degree...

In Stock
[Buy Now](https://www.adafruit.com/product/5945)
[Related Guides to the Product](https://learn.adafruit.com/products/5945/guides)
![Angled shot of long, rectangular camera breakout board.](https://cdn-shop.adafruit.com/640x480/5945-00.jpg)

### USB C to Micro B Cable - 3 ft 1 meter

[USB C to Micro B Cable - 3 ft 1 meter](https://www.adafruit.com/product/3878)
As technology changes and adapts, so does Adafruit! Rather than the regular USB A, this cable has&nbsp; **USB C to Micro B** &nbsp;plugs!

USB C is the latest industry-standard connector for transmitting data _and_ power. Like Lightning and MagSafe cables, USB C has no...

In Stock
[Buy Now](https://www.adafruit.com/product/3878)
[Related Guides to the Product](https://learn.adafruit.com/products/3878/guides)
![USB C to Micro B Cable. 3ft 1 meter.](https://cdn-shop.adafruit.com/640x480/3878-00.jpg)

### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

Out of Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

### USB C to USB C Cable - USB 3.1 Gen 4 with E-Mark - 1 meter long

[USB C to USB C Cable - USB 3.1 Gen 4 with E-Mark - 1 meter long](https://www.adafruit.com/product/4199)
As technology changes and adapts, so does Adafruit! Rather than the regular USB A, this cable has&nbsp; **USB C to USB C** &nbsp;plugs!

USB C is the latest industry-standard connector for transmitting data&nbsp;_and_&nbsp;power. Like Lightning and MagSafe cables, USB C...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4199)
[Related Guides to the Product](https://learn.adafruit.com/products/4199/guides)
![USB C to USB C cable. USB 3.1 gen 4 with E-Mark. 1 meter long](https://cdn-shop.adafruit.com/640x480/4199-01.jpg)

### Part: OV7670 Camera Boards
quantity: 1
Lot of 5 camera boards
[OV7670 Camera Boards](https://www.amazon.com/AITRIP-OV7670-640x480-0-3Mega-Arduino/dp/B09126R875)

### Part:  OV2640 Camera Board
quantity: 1
Camera module, 2 Megapixel
[ OV2640 Camera Board](https://www.waveshare.com/OV2640-Camera-Board.htm)

# Capturing Camera Images with CircuitPython

## Cameras and Pinouts

The [ESP-LyraP-CAM](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp-lyrap-cam-v1.1.html) v1.1 module included with the Kaluga development kit is ready to go: it includes the pull-up resistors on the I2C communication lines, here labeled SIOC and SIOD (equivalent to SCL and SDA).

![sensors_esp-lyrap-cam-v1.0-3d.png](https://cdn-learn.adafruit.com/assets/assets/000/102/945/medium640/sensors_esp-lyrap-cam-v1.0-3d.png?1624373059)

The typical OV7670 module doesn't include the I2C pull-up resistors, so you may have to add them. This one was also modified so that it would fit directly on the header of a Grand Central M4 board.

![sensors_camera_ov7670-closeup.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/946/medium640/sensors_camera_ov7670-closeup.jpg?1624373221)

![](https://cdn-learn.adafruit.com/assets/assets/000/102/948/medium800/sensors_PXL_20210622_145417522.jpg?1624376166)

## Pins

See the specific board pages for details on how to connect the pins to a microcontroller.

- 3.3V: Connect to a regulated 3.3V supply
- GND (sometimes labeled DGND): Connect to GND
- SDA, SCL (sometimes labeled SIOC, SIOD): I2C bus used to configure the camera.
- XLK (sometimes labeled XCLK): Clock signal from the microcontroller to the camera.
- VS, HS, PLK (sometimes labeled SYNC, HREF, PCLK):  
Vertical & Horizontal synchronization pulses, and pixel clock from the camera to the microcontroller
- D0..D7: Pixel data from the camera to the microcontroller
- RET, PWDN: Reset and Power Down pins from the microcontroller are used during initialization to reset the camera into a known state.

# Capturing Camera Images with CircuitPython

## Working with espcamera

![](https://cdn-learn.adafruit.com/assets/assets/000/114/606/medium800/camera_PXL_20220831_162732845.jpg?1661963367)

CircuitPython 8 and 9 use a new importable camera module for Espressif ESP32 microcontrollers including the ESP32, the ESP32-S2, and the ESP32-S3. It's just different enough from the **adafruit\_ov_####_** modules that different code is needed.

Requirements:

- A compatible board and microcontroller with PSRAM
- A build of CircuitPython 8 or newer with the **espcamera** built in module enabled
- A supported camera, connected properly

At the moment, we really like the [esp32-s3-eye from Espressif](https://github.com/espressif/esp-who/blob/master/docs/en/get-started/ESP32-S3-EYE_Getting_Started_Guide.md) since it packs a 2-megapixel camera and LCD into a cute little development kit. The following examples are all coded for this board.

### Part:  ESP32-S3-EYE
quantity: 1
Development kit from Espressif with ESP32-S3 and 2-megapixel camera
[ ESP32-S3-EYE](https://www.mouser.com/ProductDetail/Espressif-Systems/ESP32-S3-EYE?qs=Rp5uXu7WBW8jiAfcrui1pQ%3D%3D)

Info: CircuitPython 9 does not require reserving PSRAM: the CIRCUITPY_RESERVED_PSRAM= directive is ignored. Read the below only if you are using CircuitPython 8.

## Configure reserved PSRAM (CircuitPython 8 only)

The camera captures images to a special region of RAM called "reserved PSRAM". This is a portion of RAM that is set aside and cannot be used for regular Python objects, but can be used by **espcamera** (as well as other behind the scenes activity such as sockets and networking that are managed by **esp-idf** ). The large size of images, especially bitmap images, are why psram is required for **espcamera**.

Boards like the esp32-s3-eye that include a camera module built in already reserve a fixed amount of PSRAM, usually 1MiB (1048576 bytes). For other boards, or if you want to fine-tune the default reserved value, you must place a line in the **CIRCUITPY/.env** file with the amount, such as:

```terminal
CIRCUITPY_RESERVED_PSRAM=1048576
```

After updating the **.env** file, you must hard-reset the board for the change to take effect. You can verify the setting in the repl:

```terminal
&gt;&gt;&gt; import espidf
&gt;&gt;&gt; espidf.get_reserved_psram()
1048576
```

Continue to the next pages for some examples! First up: [LCD Viewfinder](https://learn.adafruit.com/capturing-camera-images-with-circuitpython/working-with-esp32_camera?preview_token=TwCvxQOCWaVC_xJrIzBCuQ).

# Capturing Camera Images with CircuitPython

## Example: LCD Viewfinder

![](https://cdn-learn.adafruit.com/assets/assets/000/114/605/medium800/camera_PXL_20220825_145959996.MP.jpg?1661963207)

Info: 

This program is designed for the ESP32-S3-EYE development kit.

Your project will use a specific set of CircuitPython libraries and the&nbsp; **code.py** &nbsp;file. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Drag the contents of the uncompressed bundle directory onto your Feather board's **CIRCUITPY** &nbsp;drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.

When CircuitPython restarts, the live camera view will be shown on the LCD. You can click the button marked "BOOT" to switch between live camera view and a color-bar test pattern. The test pattern is shown here. A small black sticker has been placed over the **extremely** bright green power LED.

![Directory](https://adafruit.github.io/Adafruit_Learning_System_Guides/CircuitPython_ESP32_Camera_esp32-s3-eye-lcdview.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_ESP32_Camera/esp32-s3-eye-lcdview/code.py

## How it works

#### Libraries

First, the code imports the necessary libraries. In particular:

- **espcamera** to interface with the camera
- **displayio** to use Bitmap objects

```auto
import struct

import adafruit_ticks
import board
import displayio
import espcamera
import keypad
```

#### Test-pattern Toggle Button

The "Boot" button on this board can be used as a regular button with `keypad.Keys`. The other 4 buttons share a single pin, so using them is more complicated.

```auto
button = keypad.Keys((board.BOOT,), value_when_pressed=False)
```

#### Camera

Next, the camera object is created. Because the LCD's size is 240x240, we use the 240x240 resolution mode, `FrameSize.R240X240` when setting up the camera. Setting the `vflip` property makes the LCD show the image right side up. Depending whether you want a mirror mode or not you can set the `hmirror` property to `True`.

```auto
cam = espcamera.Camera(                                                      
    data_pins=board.CAMERA_DATA,                                                
    external_clock_pin=board.CAMERA_XCLK,                                       
    pixel_clock_pin=board.CAMERA_PCLK,                                          
    vsync_pin=board.CAMERA_VSYNC,                                               
    href_pin=board.CAMERA_HREF,                                                 
    pixel_format=esp32_camera.PixelFormat.RGB565,                               
    frame_size=esp32_camera.FrameSize.R240X240,                                 
    i2c=board.I2C(),                                                            
    external_clock_frequency=20_000_000,                                        
    framebuffer_count=2,                                                        
    grab_mode=esp32_camera.GrabMode.WHEN_EMPTY)                                 
                                                                                
cam.vflip = True
```

#### Forever Loop to Display and check button

Whenever a "pressed" event arrives, toggle the "colorbar" property of the camera. It defaults to `False` (off), so pressing BOOT once toggles it on and pressing BOOT again toggles it back off.

To make the display refresh as quickly as possible, we bypass displayio and send out our bitmap directly to the LCD. Just for bragging rights, we calculate the Frames Per Second (FPS) that we update the LCD. Refresh rates of 25FPS can be obtained with this code.

```auto
while True:
    if (event := button.events.get()) and event.pressed:
        cam.colorbar = not cam.colorbar
    frame = cam.take(1)                                                         
    if isinstance(frame, displayio.Bitmap):                                     
        display_bus.send(44, frame)                                             
        t1 = adafruit_ticks.ticks_ms()                                          
        fps = 1000 / adafruit_ticks.ticks_diff(t1, t0)
        print(f"{fps:3.1f}fps")  # typically runs at about 25fps
        t0 = t1
```

# Capturing Camera Images with CircuitPython

## Example: Webcam with Adafruit IO

![](https://cdn-learn.adafruit.com/assets/assets/000/114/604/medium800/camera_Screenshot_2022-08-31_at_11-21-06_Adafruit_IO.png?1661963117)

Info: 

This program is designed for the ESP32-S3-EYE development kit.

Upload a jpeg image to Adafruit IO at regular intervals

This example requires:

- ESP32-S3-EYE development kit from Espressif

To use, you must set up WiFi and Adafruit IO:

- On [io.adafruit.com](https://io.adafruit.com), create a feed named "image" and turn **OFF** history
- On io.adafruit.com, create a dashboard and add an "image" block using the feed "image" as its data
- Set up **CIRCUITPY/.env** with WiFI and Adafruit IO credentials

Your project will use a specific set of CircuitPython libraries and the&nbsp; **code.py** &nbsp;file. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Drag the contents of the uncompressed bundle directory onto your Feather board's **CIRCUITPY** &nbsp;drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.

When the new code starts, it will upload an image to Adafruit IO approximately every 10 seconds.

![Folder](https://adafruit.github.io/Adafruit_Learning_System_Guides/CircuitPython_ESP32_Camera_esp32-s3-eye-adafruitio.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_ESP32_Camera/esp32-s3-eye-adafruitio/code.py

## How it works

Many parts of this example are similar to the previous one, but the explanations are not repeated.

For this example you'll need to configure your **CIRCUITPY/.env** file properly. It will need to contain the following keys. The values depend on your WiFi and adafruit io settings.

```auto
AIO_KEY=YourAioKey
AIO_USERNAME=YourAioUsername
CIRCUITPY_WEB_API_PASSWORD=YourWebApiPassword
CIRCUITPY_WIFI_PASSWORD=YourWifiPassword
CIRCUITPY_WIFI_SSID=YourWifiName
```

#### Adafruit IO Credentials

Adafruit IO Credentials are stored in the **CIRCUITPY/.env** file and retrieved using dotenv:

```auto
aio_username = os.getenv('/.env', 'AIO_USERNAME')
aio_key = os.getenv('/.env', 'AIO_KEY')
```

The WiFi interface is assumed to be configured for the web workflow, so we skip making a connection ourselves and skip directly to creating the connection to Adafruit IO:

```auto
pool = socketpool.SocketPool(wifi.radio)

print("Connecting to Adafruit IO")
mqtt_client = MQTT.MQTT(
    broker="io.adafruit.com",
    username=aio_username,
    password=aio_key,
    socket_pool=pool,
    ssl_context=ssl.create_default_context(),
)
mqtt_client.connect()
io = IO_MQTT(mqtt_client)
```

We wait for a JPEG image capture to be ready from the camera. Then, we encode it in a specific way that Adafruit IO understands, and upload it. This repeats forever, waiting 10 seconds between image captures.

```auto
while True:
    frame = cam.take(1)
    if isinstance(frame, memoryview):
        jpeg = frame
        print(f"Captured {len(jpeg)} bytes of jpeg data")

        # b2a_base64() appends a trailing newline, which IO does not like
        encoded_data = binascii.b2a_base64(jpeg).strip()
        print(f"Expanded to {len(encoded_data)} for IO upload")

        io.publish("image", encoded_data)

        time.sleep(10)
```

# Capturing Camera Images with CircuitPython

## Example: QR Code Scanner

![](https://cdn-learn.adafruit.com/assets/assets/000/114/603/medium800/camera_PXL_20220831_161511151.jpg?1661963099)

Info: 

## QR Code Scanner

This program is designed for the ESP32-S3-EYE development kit.

`qrio`, the built-in module for decoding QR codes, is discussed in more detail [in its dedicated guide](https://learn.adafruit.com/scan-qr-codes-with-circuitpython).

Whenever it "sees" a QR code, it will print the contained data on the REPL. It also shows the live view on the LCD.

Your project will use a specific set of CircuitPython libraries and the&nbsp; **code.py** &nbsp;file. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Drag the contents of the uncompressed bundle directory onto your Feather board's **CIRCUITPY** &nbsp;drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.

Once the demo starts, it will look for a QR code and print it on the REPL. While it works, it'll show the camera image on the viewfinder so you can line up the code within the frame.

This code works great with a standard or telephoto lens, but a wide-angle or fish-eye lens distorts the QR code and prevents CircuitPython from decoding it.

Scanning from a computer LCD or phone screen works sometimes, but scanning from paper is more reliable. It helps if the image is large (several inches or 75 to 100mm), since most cameras don't have good close focus for a small (two inches or 50mm or smaller) codes.

![Folder](https://adafruit.github.io/Adafruit_Learning_System_Guides/CircuitPython_ESP32_Camera_esp32-s3-eye-qrio-repl.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_ESP32_Camera/esp32-s3-eye-qrio-repl/code.py

The QR decoder is specific to the size of image, so it needs to be created to match the camera's image dimensions:

```auto
qrdecoder = qrio.QRDecoder(cam.width, cam.height)
```

Each frame is simply passed on to the QR decoder, which returns zero or more pieces of data. Because the data might or might not be valid UTF-8, we try two ways of decoding it into a printable value.

```auto
# (inside the forever-loop)
    for row in qrdecoder.decode(frame, qrio.PixelPolicy.RGB565_SWAPPED):
        payload = row.payload
        try:
            payload = payload.decode("utf-8")
        except UnicodeError:
            payload = str(payload)
        print(payload)
```

## Creating QR Codes

There are lots of sites & services to generate QR codes. [This one](https://www.the-qrcode-generator.com/) seems pretty no-nonsense.

If you have Python installed on your host computer, you can use the [Adafruit miniQR Library](https://circuitpython.readthedocs.io/projects/miniqr/en/latest/#)to show QR codes in a terminal window.

If you use the Duck Duck Go search engine, you can search for "qr" + your terms, [like so](https://duckduckgo.com/?t=ffsb&q=qr+https%3A%2F%2Fadafrui.it&ia=answer). It can help to use the web browser's magnification function (ctrl-+ or command-+) to adjust the image to be bigger on screen.

![Example](https://cdn-learn.adafruit.com/assets/assets/000/103/803/original/camera_Screenshot_2021-08-12_10-54-15.png?1628783668 )

# Capturing Camera Images with CircuitPython

## Documentation: espcamera

# Capturing Camera Images with CircuitPython

## Install TinyUF2 on Espressif Kaluga

Info: 

Now, use the breakout USB connection in lieu of either of the built-in USB Micro B ports to install and use CircuitPython.

Start by connecting the USB Breakout Cable to the Kaluga board.

- **Black** : Use a Male/Female Extension Jumper Wire to connect to **GND**
- **White** : Connect to **IO19**
- **Green** : Connect to **IO20**
- **Red** : Use a Male/Female Extension Jumper Wire to connect to **5V**

![sensors_PXL_20210629_171325610.jpg](https://cdn-learn.adafruit.com/assets/assets/000/103/223/medium640/sensors_PXL_20210629_171325610.jpg?1624987366)

Danger: 

If you're familiar with our other products and chipsets you may be famliar with our drag-n-drop bootloader, a.k.a UF2. We have a UF2 bootloader for the ESP32-S2, that will let you drag firmware on/off a USB disk drive.

Warning: 

However, thanks to the ROM bootloader, you don't have to worry about it if the UF2 bootloader is damaged. The ROM bootloader can never be disabled or erased, so its always there if you need it! You can simply re-load the UF2 bootloader (USB-disk-style) with the ROM bootloader (non-USB-drive)

You can use the TinyUF2 bootloader to load code directly, say CircuitPython or the binary output of an Arduino compilation or you can use it to load a&nbsp;_second_&nbsp;bootloader on, like UF2 which has a drag-n-drop interface.

Danger: 

# Method 1: WebSerial ESPTool / `esptool`

This section outlines using WebSerial ESPTool or `esptool` to flash the UF2 bootloader onto your ESP32-S2 board.

## Step 1. Download the tinyuf2 combined.bin file here

Note that this file is 3MB but that's because the bootloader is near the end of the available flash. It's not actually 3MB large, most of the file is empty but its easier to program if we give you one combined 'swiss cheese' file. Save this file to your desktop or wherever you plan to run esptool from

[combined.bin](https://cdn-learn.adafruit.com/assets/assets/000/103/224/original/combined.bin?1624988368)
## Step 2. Place your board in bootloader mode

Entering the bootloader is easy. Complete the following steps.

1. **Make sure your ESP32-S2 is plugged into USB port to your computer using a data/sync cable.** &nbsp;Charge-only cables will not work!
2. **Turn on the On/Off switch** &nbsp;- If your board has a power switch, check that you see the OK light on so you know the board is powered, a prerequisite!
3. **Press and hold the DFU / Boot0 button down.** &nbsp;Don't let go of it yet!
4. **Press and release the Reset button.** &nbsp;You should have the DFU/Boot0 button pressed while you do this.
5. **Now you can release the DFU / Boot0 button**

![](https://cdn-learn.adafruit.com/assets/assets/000/103/225/medium800/sensors_PXL_20210629_174607633.jpg?1624988907)

Because there are several incompatible versions of the Kaluga TFT display, the bootloader's screen may appear incorrectly or not at all. This does not affect its operation.

### Check for a new serial / COM port
 **On Windows check the Device manager&nbsp;** - you will see a COM port, for example here its COM88. You may also see another "Other device" called ESP32-S2

It's best to do this with no other dev boards plugged in so you don't get confused about which COM port is the ESP32-S2

![install_uf2_bootloader_Windows_Device_Manager.png](https://cdn-learn.adafruit.com/assets/assets/000/101/577/medium640/install_uf2_bootloader_Windows_Device_Manager.png?1618614418)

On Mac/Linux you will need to find the tty name which lives under /dev

On Linux, try&nbsp; **ls** &nbsp; **/dev/ttyS\*** &nbsp;for example, to find the matching serial port name. In this case it shows up as&nbsp; **/dev/ttyS87**. If you don't see it listed try&nbsp; **ls /dev/ttyA\*&nbsp;** on some Linux systems it might show up like&nbsp; **/dev/ttyACM0**

On Mac, try&nbsp; **ls /dev/cu.usbmodem\*** &nbsp;for example, to find the matching serial port name. In this case, it shows up as&nbsp; **/dev/cu.usbmodem01**

It's best to do this with no other dev boards plugged in so you don't get confused about which serial port is the ESP32-S2

![install_uf2_bootloader_adafruit_products_image_(4).png](https://cdn-learn.adafruit.com/assets/assets/000/101/578/medium640/install_uf2_bootloader_adafruit_products_image_%284%29.png?1618614511)

![install_uf2_bootloader_adafruit_products_Metro_ESP_32_bootloader_serial_name.png](https://cdn-learn.adafruit.com/assets/assets/000/101/579/medium640/install_uf2_bootloader_adafruit_products_Metro_ESP_32_bootloader_serial_name.png?1618614539)

## Step 3 Option A. Use the Web Serial ESPTool to upload

The WebSerial ESPTool was designed to be a web-capable option for programming ESP32-S2 boards. It allows you to erase the contents of the microcontroller and program up to 4 files at different offsets.

You will have to use the Chrome browser for this to work, Safari and Firefox, etc are _not_ supported because we need Web Serial and only Chrome is supporting it to the level needed.

### Enable Web Serial (For older chrome)
Primary: 

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

**Restart Chrome**

![install_uf2_bootloader_adafruit_products_Enable_Features.jpg](https://cdn-learn.adafruit.com/assets/assets/000/101/562/medium640/install_uf2_bootloader_adafruit_products_Enable_Features.jpg?1618608210)

### Connecting
In the **Chrome browser** visit [https://adafruit.github.io/Adafruit\_WebSerial\_ESPTool/](https://adafruit.github.io/Adafruit_WebSerial_ESPTool/). It should look like the image to the left.

![camera_Screen_Shot_2022-04-04_at_3.07.03_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/625/medium640/camera_Screen_Shot_2022-04-04_at_3.07.03_PM.png?1649366866)

Press the&nbsp; **Connect** &nbsp;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 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.

![camera_Screen_Shot_2022-04-04_at_3.12.49_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/626/medium640/camera_Screen_Shot_2022-04-04_at_3.12.49_PM.png?1649366909)

The Javascript code will now try to connect to the ROM bootloader. It may timeout for a bit until it succeeds. On success, you will see that it is&nbsp; **Connected** &nbsp;and will print out a unique&nbsp; **MAC address** &nbsp;identifying the board.

![camera_Screen_Shot_2022-04-04_at_3.16.00_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/627/medium640/camera_Screen_Shot_2022-04-04_at_3.16.00_PM.png?1649367045)

Once you have successfully connected, the command toolbar will appear.

![camera_Screen_Shot_2022-04-04_at_3.18.26_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/628/medium640/camera_Screen_Shot_2022-04-04_at_3.18.26_PM.png?1649367078)

### Erasing the Contents

If you would like to erase the entire flash area so that you can start with a clean slate, you can use the erase feature. We recommend doing this if you are having issues.

To erase the contents, click the Erase button. You will be prompted whether you want to continue. Click OK to continue or if you changed your mind, just click cancel.

![camera_Screen_Shot_2022-04-04_at_3.19.58_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/629/medium640/camera_Screen_Shot_2022-04-04_at_3.19.58_PM.png?1649367120)

### Programming the Microcontroller

Programming the microcontroller can be done with up to 4 files at different locations, but with the&nbsp; **tinyuf2combo** &nbsp; **BIN** &nbsp;file, which you should have downloaded under **Step 1** on this&nbsp;page, you only need to use 1 file.

You can click on&nbsp; **Choose a file...** &nbsp;from any of the available buttons. It will only attempt to program buttons with a file and a unique location. Then select the Adafruit CircuitPython&nbsp; **BIN** &nbsp;files (not the UF2 file!)

Verify that the&nbsp; **Offset** &nbsp;box next to the file location you used is 0x0.

![install_uf2_bootloader_adafruit_products_image_(3).png](https://cdn-learn.adafruit.com/assets/assets/000/101/574/medium640/install_uf2_bootloader_adafruit_products_image_%283%29.png?1618608677)

Once you choose a file, the button text will change to match your filename. You can then select the Program button to start flashing.

![camera_Screen_Shot_2022-04-04_at_3.22.13_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/630/medium640/camera_Screen_Shot_2022-04-04_at_3.22.13_PM.png?1649367171)

A progress bar will appear and after a minute or two, you will have written the firmware.

![camera_Screen_Shot_2022-04-04_at_3.23.42_PM.png](https://cdn-learn.adafruit.com/assets/assets/000/110/631/medium640/camera_Screen_Shot_2022-04-04_at_3.23.42_PM.png?1649367200)

Info: 

## Step 3. Option B. Use esptool.py to upload (for advanced users)

Once you have entered ROM bootloader mode, you can then&nbsp;[use Espressif's esptool program](https://github.com/espressif/esptool)&nbsp;to communicate with the chip!&nbsp;`esptool`&nbsp;is the 'official' programming tool and is the most common/complete way to program an ESP chip.

### Install ESPTool.py

You will need to use the command line / Terminal to install and run&nbsp;`esptool`.

You will also need to have pip and Python installed (any version!)

Install the latest version using pip (you may be able to run&nbsp;`pip`&nbsp;without the&nbsp;`3`&nbsp;depending on your setup):

`pip3 install --upgrade esptool`

Then, you can run:

`esptool.py`

### Test the Installation

Run&nbsp;`esptool.py`&nbsp;in a new terminal/command line and verify you get something like the below:

![](https://cdn-learn.adafruit.com/assets/assets/000/101/580/medium800/install_uf2_bootloader_adafruit_products_image_%282%29.png?1618614758)

Info: 

Run the following command, replacing the identifier after&nbsp;`--port`&nbsp;with the&nbsp;`COMxx`,&nbsp;`/dev/cu.usbmodemxx`&nbsp;or&nbsp;`/dev/ttySxx`&nbsp;you found above.

`esptool.py --port COM88 chip_id`

You should get a notice that it connected over that port and found an ESP32-S2

![](https://cdn-learn.adafruit.com/assets/assets/000/101/581/medium800/install_uf2_bootloader_adafruit_products_image_%283%29.png?1618615988)

### Installing the Bootloader

Run this command and replace the serial port name with your matching port and the file you just downloaded

`esptool.py --port COM88 write_flash 0x0 tinyuf2_combo.bin`

Don't forget to change the `--port` name to match.

There might be a bit of a 'wait' when programming, where it doesn't seem like it's working. Give it a minute, it has to erase the old flash code which can cause it to seem like it's not running.

You'll finally get an output like this:

![](https://cdn-learn.adafruit.com/assets/assets/000/101/548/medium800/install_uf2_bootloader_adafruit_products_image.png?1618598592)

## Step 4. Reset the board
Click the RESET button to launch the bootloader. You'll see a new disk drive on your computer with the name **KALUGA1BOOT**.

You're now ready to copy the CircuitPython UF2 on to the drive which will set up CircuitPython!

# Method 2: Flash an Arduino Sketch

This section outlines flashing an Arduino sketch onto your ESP32-S2 board, which automatically installs the UF2 bootloader as well.

## Arduino IDE Setup

If you don't already have the Arduino IDE installed, the first thing you will need to do is to download the latest release of the Arduino IDE. ESP32-S2 requires **version 1.8** &nbsp;or higher. Click the link to download the latest.

[Arduino IDE Download](https://www.arduino.cc/en/software)
After you have downloaded and installed **&nbsp;** the latest version of Arduino IDE, you will need to start the IDE&nbsp;and navigate to&nbsp;the&nbsp; **Preferences** &nbsp;menu. You can access it from the&nbsp; **File \> Preferences** menu in&nbsp;Windows&nbsp;or&nbsp;Linux, or the&nbsp; **Arduino \> Preferences** menu on&nbsp;OS X.

The **Preferences** window will open.

In the **Additional Boards Manager URLs** field, you'll want to add a new URL. The list of URLs is comma separated, and&nbsp;_you will only have to add each&nbsp;URL once._ The URLs point to index files that the Board Manager uses to build the list of available & installed boards.

Copy the following URL.

`https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json`

Add the URL to the the **Additional Boards Manager URLs** field (highlighted in red below).

![](https://cdn-learn.adafruit.com/assets/assets/000/107/290/medium800/install_uf2_bootloader_esp32_s2_Arduino_Template_RP2040_preferences_window.png?1639413677)

Click **OK** to save and close **Preferences**.

In the **Tools \> Boards** menu you should see the **ESP32 Arduino** menu. In the expanded menu, it should contain the ESP32 boards along with all the latest ESP32-S2 boards.

Now that your IDE is setup, you can continue on to loading the sketch.

## Load the Blink Sketch
In the **Tools \> Boards** menu you should see the **ESP32 Arduino** menu. In the expanded menu, look for the menu option for the **ESP32S2 Dev Module** , and click on it to choose it.

Open the Blink sketch by clicking through **File \> Examples \> 01.Basics \> Blink**.

![](https://cdn-learn.adafruit.com/assets/assets/000/107/291/medium800/install_uf2_bootloader_esp32_s2_Arduino_Template_RP2040_open_Blink.png?1639413760)

Once open, click Upload from the sketch window.

![](https://cdn-learn.adafruit.com/assets/assets/000/107/292/medium800/install_uf2_bootloader_esp32_s2_CP_Template_ESP32-S2_factory_reset_blink_upload.png?1639413852)

Once successfully uploaded, the little red LED will begin blinking once every second. At that point, you can now enter the bootloader.

# Capturing Camera Images with CircuitPython

## Espressif Kaluga Setup

Danger: 

Warning: 

The Kaluga development kit from Espressif includes almost everything you need: The microcontroller, a camera, and an LCD.

Take the assembled Kaluga board stack (all three boards) and attach the camera at the dedicated header, making sure the pins are inserted properly.

You **do not** need to add any pull-up resistors; they are already provided on the Kaluga's audio daughterboard.

There are at least 3 variants of the LCD board that ship with the Kaluga:

- st7789
- ili9341
- ili9341 with rotation=90

There are no markings to distinguish the three, so you will need to try each variant until you find the one that works.

First, make sure you can see the Kaluga's **CIRCUITPY** drive and connect to the REPL. Open the REPL and double check that `import imagecapture` works without showing an error. (note: if it does, the most likely reason is that you are using CircuitPython 8 or newer, which is incompatible with the code in this guide)

Then, copy the correct bundle to your device. It will automatically reload and start displaying the image from the camera on the built-in LCD.

## Kaluga 1.3 with OV2640 and ili9341 display (CircuitPython 7)
Info: 

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Espressif Kaluga ESP32-S2 with OV2640 display showing the test pattern. The test pattern's color bars appear heavily distorted due to the viewing angle.

![sensors_PXL_20210628_152101987.jpg](https://cdn-learn.adafruit.com/assets/assets/000/103/163/medium640/sensors_PXL_20210628_152101987.jpg?1624894632)

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_displayio_kaluga1_3_ili9341.py

Your **CIRCUITPY** drive should resemble the screenshot below

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov2640.mpy**
- **adafruit\_ili9341.mpy**

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.4 or newer.

If the image does not fill the whole display, try removing `rotation=90` from the line beginning `display = ILI9341`. If it does not appear at all or is in reverse video, try the example for the st7789 display.

![Folder](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov2640_ov2640_displayio_kaluga1_3_ili9341.py.png )

## Kaluga 1.3 with OV2640 and st7789 display (CircuitPython 7)
Info: 

If you have a Kaluga 1.3 board with an ili9341 LCD display, use the project below.

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov2640.mpy**
- **adafruit\_st7789.mpy**

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.4 or newer.

If the image does not appear at all or is in reverse video, try the example for the ili9341. display.

The author did not have a Kaluga with an st7789 display, so this example is untested.

![Folder](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov2640_ov2640_displayio_kaluga1_3_st7789.py.png )

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_displayio_kaluga1_3_st7789.py

## Kaluga 1.3 with OV7670 and ili9341 display
Info: 

Take the assembled Kaluga board stack (all three boards) and attach the camera at the dedicated header, making sure the pins are inserted properly.

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov7670.mpy**
- **adafruit\_ili9341.mpy**

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.4 or newer.

If the image does not fill the whole display, try removing `rotation=90` from the line beginning `display = ILI9341`. If it does not appear at all or is in reverse video, try the example for the st7789 display.

![Folder](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov7670_ov7670_displayio_kaluga1_3_ili9341.py.png )

https://github.com/adafruit/Adafruit_CircuitPython_OV7670/blob/main/examples/ov7670_displayio_kaluga1_3_ili9341.py

## Adapting to other ESP32-S2 boards

By selecting appropriate pins, you can adapt the example to work on other RP2040 boards:

- **mclk** , **pclk** , **vsync** , **href** : Free choice of any pin
- **reset** , **shutdown** : Free choice of any pin. Can omit one or both, but the initialization sequence is less reliable.
- **d0** … **d7** : Free choice of any pin

### USB Type A Plug Breakout Cable with Premium Female Jumpers

[USB Type A Plug Breakout Cable with Premium Female Jumpers](https://www.adafruit.com/product/4448)
If you'd like to connect a USB-capable chip to your USB host, this cable will make the task very simple. **There is no converter chip in this cable!** Its basically a plain USB cable that's cut in half and with jumper sockets on the power and data lines. Simple to use,...

In Stock
[Buy Now](https://www.adafruit.com/product/4448)
[Related Guides to the Product](https://learn.adafruit.com/products/4448/guides)
![Angled shot of Black, USB-A plug cable with four socket jumpers.](https://cdn-shop.adafruit.com/640x480/4448-01.jpg)

### USB Extension Cable - 3 meters / 10 ft long

[USB Extension Cable - 3 meters / 10 ft long](https://www.adafruit.com/product/993)
This handy USB extension cable will make it easy for you to extend your USB cable when it won't reach. The connectors are gold plated for years of reliability. We use these handy cables all over our factory and homes. Cable is standard "Adafruit black".  
  
Cable length:...

Out of Stock
[Buy Now](https://www.adafruit.com/product/993)
[Related Guides to the Product](https://learn.adafruit.com/products/993/guides)
![USB Type A Extension Cable](https://cdn-shop.adafruit.com/640x480/993-03.jpg)

# Capturing Camera Images with CircuitPython

## Raspberry Pi Pico Wiring

![](https://cdn-learn.adafruit.com/assets/assets/000/103/165/medium800/sensors_PXL_20210628_152956057.jpg?1624895168)

## Wiring
There's no ready-made breakout board for the OV cameras and the Raspberry Pi, so get ready to do some wiring.

This diagram shows the many connections needed. Continue below for a list.

Danger: 

![](https://cdn-learn.adafruit.com/assets/assets/000/103/252/medium800/camera_picofritz_bb.png?1625003033)

Because the camera has two rows of connections that are 0.100 apart, a standard solderless breadboard doesn't work very well. Use a solderable breadboard or perfboard. If your solderable perfboard has a gap down the middle, you can use an IDC Breakout Helper, but these do not work well with solderless breadboards.

You can also use jumper wires (M-F to go from breadboard to camera, or F-F to go from pico pin header to camera), which is also nice because it gives you some flexibility to orient the camera differently than the LCD.

### Power & Ground

- Connect **GND** of LCD, Pico, and Camera
- Connect **3V3** from Pico to Camera
- Connect **3V3** from Pico to I2C pull-up resistors (×2)
- Connect **VSYS** from Pico to LCD **VIN**

### LCD Connections

- Connect Pico **GP2** to LCD **SCK**
- Connect Pico **GP3** to LCD **MOSI**
- Connect Pico **GP0** to LCD **D/C**
- Connect Pico **GP1** to LCD **CS**

### I2C Connections

- Connect one I2C pull-up resistor to Pico **GP8**
- Connect the other I2C pull-up resistor to Pico **GP9**
- Connect Pico **GP8** to Camera **SDA**
- Connect Pico **GP9** to Camera **SCL**

### Camera Control Connections

- Connect Pico **GP7** to Camera **VSYNC**
- Connect Pico **GP10** to Camera **RESET**
- Connect Pico **GP11** to Camera **CLOCK**
- Connect Pico **GP20** to Camera **MCLK**
- Connect Pico **GP21** to Camera **HREF**

### Camera Data Connections

- Connect Pico **GP12** to Camera **D0**
- Connect Pico **GP13** to Camera **D1**
- Connect Pico **GP14** to Camera **D2**
- Connect Pico **GP15** to Camera **D3**
- Connect Pico **GP16** to Camera **D4**
- Connect Pico **GP17** to Camera **D5**
- Connect Pico **GP18** to Camera **D6**
- Connect Pico **GP19** to Camera **D7**

Info: 

Make sure you can see the Pico's **CIRCUITPY** drive and connect to the REPL. Open the REPL and double check that `import imagecapture` works without showing an error. Then, copy the correct bundle to your device. It will automatically reload and start displaying the image from the camera on the built-in LCD.

## For the OV2640 camera

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov2640.mpy**
- **adafruit\_st7789.mpy**

![Folder](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov2640_ov2640_displayio_pico_st7789_2in.py.png )

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_displayio_pico_st7789_2in.py

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.0 or newer.

## For the OV7670 camera

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov7670.mpy**
- **adafruit\_st7789.mpy**

![List](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov7670_ov7670_displayio_pico_st7789_2in.py.png )

https://github.com/adafruit/Adafruit_CircuitPython_OV7670/blob/main/examples/ov7670_displayio_pico_st7789_2in.py

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.0 or newer.

## Adapting to other RP2040 boards

By selecting appropriate pins, you can adapt the example to work on other RP2040 boards which are supported by CircuitPython and have enough pins exposed for the connections below:

- **mclk** , **pclk** , **vsync** , **href** : Free choice of any pin
- **reset** , **shutdown** : Free choice of any pin. Can omit one or both, but the initialization sequence is less reliable.
- **d0** … **d7** : These 8 pins must be consecutive in the " **IO##**" ordering, so you could use **IO3** … **IO10** ,&nbsp; **IO9** … **IO16** , etc.

### Raspberry Pi Pico RP2040

[Raspberry Pi Pico RP2040](https://www.adafruit.com/product/4864)
The Raspberry Pi foundation changed single-board computing [when they released the Raspberry Pi computer](https://www.raspberrypi.org/archives/723), now they're ready to do the same for microcontrollers with the release of the brand new **Raspberry Pi Pico**. This...

In Stock
[Buy Now](https://www.adafruit.com/product/4864)
[Related Guides to the Product](https://learn.adafruit.com/products/4864/guides)
![Angle shot of Raspberry Pi Pico RP2040](https://cdn-shop.adafruit.com/640x480/4864-00.jpg)

### Premium Female/Female Jumper Wires - 40 x 6"

[Premium Female/Female Jumper Wires - 40 x 6"](https://www.adafruit.com/product/266)
Handy for making wire harnesses or jumpering between headers on PCB's. These premium jumper wires approximately 6" (150mm) long and come in a 'strip' of 40 (4 pieces of each of ten colors). They have 0.1" sockets on either end and fit cleanly next to each other on...

In Stock
[Buy Now](https://www.adafruit.com/product/266)
[Related Guides to the Product](https://learn.adafruit.com/products/266/guides)
![Cable assembly of forty 6" long jumper wires with socket connectors.](https://cdn-shop.adafruit.com/640x480/266-04.jpg)

### Premium Female/Male 'Extension' Jumper Wires - 40 x 6" (150mm)

[Premium Female/Male 'Extension' Jumper Wires - 40 x 6" (150mm)](https://www.adafruit.com/product/826)
Handy for making wire harnesses or jumpering between headers on PCB's. These premium jumper wires are 6" (150mm) long and come in a 'strip' of 40 (4 pieces of each of ten rainbow colors). They have 0.1" male header contacts on one end and 0.1" female header contacts...

In Stock
[Buy Now](https://www.adafruit.com/product/826)
[Related Guides to the Product](https://learn.adafruit.com/products/826/guides)
![Angled shot of Premium Female/Male 'Extension' Jumper Wires - 40 x 6 (150mm)](https://cdn-shop.adafruit.com/640x480/826-04.jpg)

### Through-Hole Resistors - 2.2K ohm 5% 1/4W - Pack of 25

[Through-Hole Resistors - 2.2K ohm 5% 1/4W - Pack of 25](https://www.adafruit.com/product/2782)
ΩMG! You're not going to be able to resist these handy resistor packs!&nbsp;Well, axially, they&nbsp;do all of the resisting for you!

This is a **25 Pack of 2.2K Ω Resistors.** More specifically, they are **carbon film** , through-hole...

In Stock
[Buy Now](https://www.adafruit.com/product/2782)
[Related Guides to the Product](https://learn.adafruit.com/products/2782/guides)
![Angled shot of 25 Through-Hole Resistors - 2.2K ohm 5% 1/4W.](https://cdn-shop.adafruit.com/640x480/2782-00.jpg)

# Capturing Camera Images with CircuitPython

## Grand Central M4 Wiring

![](https://cdn-learn.adafruit.com/assets/assets/000/103/166/medium800/sensors_PXL_20210628_152641944.jpg?1624895740)

Danger: 

Before you can use an OV7670 camera with the Grand Central M4, you have to perform some hardware modifications which are [detailed on their own page.](https://learn.adafruit.com/adafruit-ov7670-camera-library-samd51/hardware) These modifications are not easily reversible and will make it difficult to use the camera modules on other boards.

Then, position the camera so that it sticks off the right side of the Grand Central PCB and the SDA/SCL pins insert into the third row of the header and insert it carefully.

Align the pins of the TFT Shield and insert it into the Grand Central too.

Connect GND and 3V3 from the TFT Shield to the modified pins of the OV7670.

Now, make sure you can see the Grand Central's **CIRCUITPY** drive and connect to the REPL. Open the REPL and double check that `import imagecapture` works without showing an error. Then, copy the correct bundle to your device. It will automatically reload and start displaying the image from the camera on the built-in LCD.

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov7670.mpy**
- **adafruit\_st7789.mpy**

![FIle](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov7670_ov7670_displayio_gcm4_tftshield18.py.png)

CircuitPython will automatically reload and begin showing the image on the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.0 or newer.

## Adapting to other SAM D5x/E5x boards

By selecting appropriate pins, you can adapt the example to work on other SAM D5x/E5x boards supported by CircuitPython which expose enough pins for the connections below:

- **mclk:** Free choice of any PWM pin
- **pclk** , **vsync** , **href** : Only the specific PCC pins may be used.
- **reset** , **shutdown** : Free choice of any pin. Can omit one or both, but the initialization sequence is less reliable.
- **d0** … **d7** : Only the specific PCC pins may be used.

### Adafruit Grand Central M4 Express featuring the SAMD51

[Adafruit Grand Central M4 Express featuring the SAMD51](https://www.adafruit.com/product/4064)
Are you ready? Really ready? Cause here comes the **Adafruit Grand Central** featuring the **Microchip ATSAMD51**. This dev board is so big, it's not named after a Metro train, it's a whole freakin' _station_!

This board is like a freight...

In Stock
[Buy Now](https://www.adafruit.com/product/4064)
[Related Guides to the Product](https://learn.adafruit.com/products/4064/guides)
![Angled Shot of the Adafruit Grand Central M4 Express featuring the SAMD51.](https://cdn-shop.adafruit.com/640x480/4064-05.jpg)

### Adafruit 1.8" Color TFT Shield w/microSD and Joystick

[Adafruit 1.8" Color TFT Shield w/microSD and Joystick](https://www.adafruit.com/product/802)
This lovely little shield is the best way to add a small, colorful and bright display to any project. We took our popular 1.8" TFT breakout board and remixed it into an Arduino shield complete with microSD card slot and a 5-way joystick navigation switch and three selection buttons! Since...

In Stock
[Buy Now](https://www.adafruit.com/product/802)
[Related Guides to the Product](https://learn.adafruit.com/products/802/guides)
![Hand pressing buttons and moving joystick on TFT shield, display shows actions and then displays robot](https://cdn-shop.adafruit.com/product-videos/640x480/802-05.jpg)

### Through-Hole Resistors - 2.2K ohm 5% 1/4W - Pack of 25

[Through-Hole Resistors - 2.2K ohm 5% 1/4W - Pack of 25](https://www.adafruit.com/product/2782)
ΩMG! You're not going to be able to resist these handy resistor packs!&nbsp;Well, axially, they&nbsp;do all of the resisting for you!

This is a **25 Pack of 2.2K Ω Resistors.** More specifically, they are **carbon film** , through-hole...

In Stock
[Buy Now](https://www.adafruit.com/product/2782)
[Related Guides to the Product](https://learn.adafruit.com/products/2782/guides)
![Angled shot of 25 Through-Hole Resistors - 2.2K ohm 5% 1/4W.](https://cdn-shop.adafruit.com/640x480/2782-00.jpg)

### Hook-up Wire Spool Set - 22AWG Solid Core - 6 x 25 ft

[Hook-up Wire Spool Set - 22AWG Solid Core - 6 x 25 ft](https://www.adafruit.com/product/1311)
Perfect for bread-boarding, free wiring, etc. This box contains 6 spools of solid-core wire. The wire is easy to solder to and when bent it keeps its shape pretty well. We like to have a few spools of this stuff around which is why this set is quite nice! We suggest picking up wire strippers...

Out of Stock
[Buy Now](https://www.adafruit.com/product/1311)
[Related Guides to the Product](https://learn.adafruit.com/products/1311/guides)
![Hook-up Wire Spool Set in box with 6 colorful wires coming out](https://cdn-shop.adafruit.com/640x480/1311-04.jpg)

# Capturing Camera Images with CircuitPython

## Working with Image Data

## RGB Data

When the OV7670 is working in RGB mode (the default), it is in a 16-bit format called "RGB565-swapped". This means that every pixel is treated as a 16-bit number, with the left and right 8 bits "swapped":

![](https://cdn-learn.adafruit.com/assets/assets/000/103/214/medium800/sensors_Screenshot_2021-06-29_09-46-17.png?1624978000)

The OV2640 uses a 16-bit format called "BGR565-swapped", which switches the positions of the red and blue values within the pixel.

Happily, displayio's ColorConverter is able to deal with this format natively, but it is tough to write efficient Python code to work with it. In some circumstances, the CircuitPython version of the `ulab` library can help.

In the examples before now, the "capture" operation worked with a bitmap object, but it can also work with a `ulab` array:

```python
from ulab import numpy as np

arr = np.zeros((80, 60), dtype=np.uint16)
camera.capture(arr)
arr.byteswap(inplace=True)
```

After using **byteswap** , the order of the values within the pixel is now:

![](https://cdn-learn.adafruit.com/assets/assets/000/103/215/medium800/sensors_Screenshot_2021-06-29_09-53-05.png?1624978420)

making it possible to extract an individual red, green, or blue value with bit shifts (this code is for RGB565):

```auto
def R(pixel):
    return pixel &gt;&gt; 11
    
def G(pixel):
    return (pixel &amp; 0b11111100000) &gt;&gt; 5
    
def B(pixel):
    return pixel &amp; 0b11111
    
print("The green value of the pixel at (0,0) is", G(arr[0,0]))
```

Wholesale modifications of the pixel data can be done with ulab. For instance, to invert colors in the whole image,

```python
arr[:] = ~arr
```

That's exactly what the following program does on the Espressif Kaluga with OV2640.

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov2640.mpy**
- **adafruit\_ili9341.mpy**

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.0 or newer.

If the image does not fill the whole display, try removing `rotation=90` from the line beginning `display = ILI9341`. If it does not appear at all or is in reverse video, try adapting the example to use the st7789 display.

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_displayio_kaluga1_3_ili9341_ulab.py

## YUV Data

YUV is another representation of image data. Y represents the luminance (brightness) of a pixel, while U and V represent the color information. [Wikipedia has an article about YUV](https://en.wikipedia.org/wiki/YUV), if you'd like to know more.

The most useful thing about YUV data is that it allows easily extracting a greyscale image, by using the data from every other byte. That is how this "image in a terminal window" example works on the Espressif Kaluga with OV2640.

The OV2640 can be placed in YUV mode by assigning a property:

```python
cam.colorspace = adafruit_ov2640.OV2640_COLOR_YUV
```

The OV7670 is similar:

```python
cam.colorspace = adafruit_ov7670.OV7670_COLOR_YUV
```

To demonstrate the YUV mode, the simpletest demo converts a low resolution camera image into lo-fi ASCII art.

![](https://cdn-learn.adafruit.com/assets/assets/000/103/249/medium800thumb/sensors_ezgif.com-optimize.jpg?1624996976)

Click the **Download Project Bundle** button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the **entire**  **lib**  **folder** and the **code.py file** to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should resemble the image.

You should have in **/** of the **CIRCUITPY** drive:

- **code.py**

And in the **lib** folder on your **CIRCUITPY** drive:

- **adafruit\_bus\_device**
- **adafruit\_ov2640.mpy**

CircuitPython will automatically reload. Connect to the REPL and the image will be shown in the finest 3-bit ASCII art. If it doesn't, use the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.0 or newer.

If the REPL updates very slowly, one trick is to reset the Kaluga so that it forgets about the LCD display if you ran one of the demos that uses the LCD. Updating the LCD display is much slower than sending data over the USB CDC connection.

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_simpletest.py

## Test modes

These cameras have a test mode which shows color bars.

You can activate the test pattern mode on the OV2640 camera like so:

```python
cam.test_pattern = True
```

It's a little different on the OV7670:

```python
cam.test_pattern = adafruit_ov7670.OV7670_TEST_PATTERN_COLOR_BAR
```

# Capturing Camera Images with CircuitPython

## Capturing JPEG data (OV2640)

![](https://cdn-learn.adafruit.com/assets/assets/000/103/557/medium800/camera_img0012.jpg?1626899461 Unmodified JPEG taken with an OV2640 camera on Espressif Kaluga)

The OV2640 camera module can also capture JPEG images up to 2 megapixels (1600x1200 pixels). This still requires a large buffer (of _width×height÷5_ bytes, or 384,000 bytes for a 2-megapixel image), so the demo below is coded for the Kaluga development board together with the MicroSD card breakout board+.

**CircuitPython doesn't encode or decode the JPEG image itself, it just uses a JPEG-encoded file produced by the camera and stores it on the SD card.**

Make the following connections for the SD card breakout:

- **IO18** to **CLK**
- **IO14** to **DI**
- **IO17** to **DO**
- **IO12** to **CS**
- **GND** to **GND**
- **5V** to **5V**

While the demo runs, it will show a live image on the LCD. When you hold the REC button, it will save the picture as a jpeg image to the inserted SD card. Note that because the REC button is only polled when the screen is not updating, you have to **hold** it, not just quickly **press** it.

Warning: 

## Code
Info: 

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_jpeg_sd_kaluga1_3.py

## Parts
### MicroSD card breakout board+

[MicroSD card breakout board+](https://www.adafruit.com/product/254)
Not just a simple breakout board, this microSD adapter goes the extra mile - designed for ease of use.

- Onboard 5v-\>3v regulator provides 150mA for power-hungry cards
- 3v level shifting means you can use this with ease on either 3v or 5v systems
- Uses a proper level...

In Stock
[Buy Now](https://www.adafruit.com/product/254)
[Related Guides to the Product](https://learn.adafruit.com/products/254/guides)
![Angled shot of blue, rectangle microSD breakout board.](https://cdn-shop.adafruit.com/640x480/254-06.jpg)

### USB Type A Plug Breakout Cable with Premium Female Jumpers

[USB Type A Plug Breakout Cable with Premium Female Jumpers](https://www.adafruit.com/product/4448)
If you'd like to connect a USB-capable chip to your USB host, this cable will make the task very simple. **There is no converter chip in this cable!** Its basically a plain USB cable that's cut in half and with jumper sockets on the power and data lines. Simple to use,...

In Stock
[Buy Now](https://www.adafruit.com/product/4448)
[Related Guides to the Product](https://learn.adafruit.com/products/4448/guides)
![Angled shot of Black, USB-A plug cable with four socket jumpers.](https://cdn-shop.adafruit.com/640x480/4448-01.jpg)

### USB Extension Cable - 3 meters / 10 ft long

[USB Extension Cable - 3 meters / 10 ft long](https://www.adafruit.com/product/993)
This handy USB extension cable will make it easy for you to extend your USB cable when it won't reach. The connectors are gold plated for years of reliability. We use these handy cables all over our factory and homes. Cable is standard "Adafruit black".  
  
Cable length:...

Out of Stock
[Buy Now](https://www.adafruit.com/product/993)
[Related Guides to the Product](https://learn.adafruit.com/products/993/guides)
![USB Type A Extension Cable](https://cdn-shop.adafruit.com/640x480/993-03.jpg)

# Capturing Camera Images with CircuitPython

## OV2640 Webcam with Adafruit IO

With a WiFi-enabled board like the Espressif Kaluga, you can upload your image data to [Adafruit IO](https://io.adafruit.com/). We made sure that this example works with the free version, so you can try it out even if you haven't upgraded to a Plus subscription yet. New to Adafruit IO? [Start with this guide](https://learn.adafruit.com/adafruit-io-basics-airlift/circuitpython) to learn the basics.

## Set up the IO Feed

Create a feed called "image" and then set "Feed History" to "OFF". This allows storage of data up to 100kB, which is plenty to upload JPEGs at 640x480 resolution. (You can choose another feed name but you'll need to make sure that Adafruit IO's "key" for the feed matches what you use in your CircuitPython program!)

![camera_ksnip_20210730-131743.png](https://cdn-learn.adafruit.com/assets/assets/000/103/674/medium640/camera_ksnip_20210730-131743.png?1627669145)

![camera_ksnip_20210730-131835.png](https://cdn-learn.adafruit.com/assets/assets/000/103/675/medium640/camera_ksnip_20210730-131835.png?1627669163)

## Set up the IO Dashboard

Create a new dashboard. Click the gear icon and then "Create New Block". Choose the camera icon ("image") and then select your feed named "image". Enter a block title if you like, and click "Create Block".

![camera_ksnip_20210730-132031.png](https://cdn-learn.adafruit.com/assets/assets/000/103/676/medium640/camera_ksnip_20210730-132031.png?1627669259)

![camera_ksnip_20210730-132030.png](https://cdn-learn.adafruit.com/assets/assets/000/103/677/medium640/camera_ksnip_20210730-132030.png?1627669271)

## Secrets File Setup for Adafruit IO

If you don't have a **secrets.py** file in your **CIRCUITPY** drive yet, create one and add the information about your WiFi connection.

Then, add the following code to your **secrets.py** &nbsp;file, **replacing** `_your_adafruit_io_username` **with your Adafruit IO username.**

Then, **replace** &nbsp;`_your_big_huge_super_long_aio_key_` **with your Adafruit IO Active Key**.

```auto
secrets = {
    'ssid' : '_your_wifi_ssid_',
    'password' : '_your_wifi_password_',
    'aio_username' : '_your_adafruit_io_username_',
    'aio_key' : '_your_big_huge_super_long_aio_key_',
}
```

Make sure you **save this file** before proceeding as **secrets.py** in the root directory of your board **CIRCUITPY** drive **.**

## Upload the code

Grab the Bundle below and unzip it on your Espressif Kaluga's **CIRCUITPY** drive. It will automatically start the code and upload a 640x480 JPEG to Adafruit IO every 3 seconds or so.

![File](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov2640_ov2640_aio_kaluga1_3.py.png )

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_aio_kaluga1_3.py

# Capturing Camera Images with CircuitPython

## Working with BMP format data

You can also work with and save BMP format data from an OV2640 or OV7670 camera. Use this format if you need to do image processing within CircuitPython, or if your camera doesn't have a JPEG mode.

Make the following connections for the SD card breakout:

- **IO18** to **CLK**
- **IO14** to **DI**
- **IO17** to **DO**
- **IO12** to **CS**
- **GND** to **GND**
- **5V** to **5V**

While the demo runs, it will show a live image on the LCD. When you hold the REC button, it will save the picture as a BMP image to the inserted SD card. Note that because the REC button is only polled when the screen is not updating, you have to **hold** it, not just quickly **press** it.

![File](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/ov2640_ov2640_bmp_sd_kaluga1_3.py.png )

https://github.com/adafruit/Adafruit_CircuitPython_OV2640/blob/main/examples/ov2640_bmp_sd_kaluga1_3.py

# Capturing Camera Images with CircuitPython

## Coding Image Filters in C

CircuitPython 9's new&nbsp;[**bitmaptools**](https://docs.circuitpython.org/en/latest/shared-bindings/bitmapfilter/index.html) module includes a number of image filters: false color, lookup, mix, morph, and solarize.

If you have a different image processing task, and CircuitPython + ulab code is not fast enough, you can code a new algorithm in C. Note that this will require you to build your own custom CircuitPython firmware, so [familiarize yourself with that process first.](https://learn.adafruit.com/building-circuitpython) Then, get an overview of how to [add a CircuitPython module coded in C](https://learn.adafruit.com/extending-circuitpython/a-complex-module).

There are 4 main parts you'll need:

- A declaration of the C function for processing the image
- The actual implementation of the image processing algorithm
- The function binding, which converts from CircuitPython arguments to C arguments
- The function's entry in the bitmaptools "globals table"

To illustrate each of these parts, the implementation of solarize will be used as an example.

In the file **shared-bindings/bitmapfilter/\_\_init\_\_.h** is a declaration of the image processing function. Solarize takes a bitmap (which it modifies in-place), an optional mask bitmap, and a threshold value from 0 to 1 as a float:

```auto
void shared_module_bitmapfilter_solarize(
    displayio_bitmap_t *bitmap,
    displayio_bitmap_t *mask,
    const mp_float_t threshold);
```

The C implementation of solarize in **shared-module/bitmapfilter/\_\_init\_\_.c** is shown below. Here are some key items to note:

- The threshold value is converted to a scaled integer just once. This is because on most microcontrollers, computations on integers are faster than computations on floating-point numbers.
- The bitmap depth is checked to determine if it's the right kind. In this example, only processing of 16-bit images is implemented. Furthermore, it is assumed (by the `IMAGE_GET_RGB565_PIXEL_FAST` and `IMAGE_PUT_RGB565_PIXEL_FAST` functions) that 16-bit images are always in **RGB565\_SWAPPED** format.
- The image is processed by rows. `IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR` gets a pointer to the first pixel of a particular row (Y) value, while the GET/PUT macros take just a column (X) value.
- If the optional mask bitmap is not NULL, it is checked before deciding whether to alter a given pixel.
- Other functions can take apart or put together pixel values. There are macros for YUV & RGB conversion, etc. They are near the top of the file.
- If your algorithm needs temporary space it can use `scratchpad_alloc` or `scratch_bitmap16`. The **morph** algorithm does this, using small scratch bitmap so that it can process the image a row at a time.

```auto
void shared_module_bitmapfilter_solarize(
    displayio_bitmap_t *bitmap,
    displayio_bitmap_t *mask,
    const mp_float_t threshold) {

    int threshold_i = (int32_t)MICROPY_FLOAT_C_FUN(round)(256 * threshold);
    switch (bitmap-&gt;bits_per_value) {
        default:
            mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth"));
        case 16: {
            for (int y = 0, yy = bitmap-&gt;height; y &lt; yy; y++) {
                uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y);
                for (int x = 0, xx = bitmap-&gt;width; x &lt; xx; x++) {
                    if (mask &amp;&amp; common_hal_displayio_bitmap_get_pixel(mask, x, y)) {
                        continue; // Short circuit.
                    }
                    int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
                    int y = COLOR_RGB565_TO_Y(pixel);
                    if (y &gt; threshold_i) {
                        y = MIN(255, MAX(0, 2 * threshold_i - y));
                        int u = COLOR_RGB565_TO_U(pixel);
                        int v = COLOR_RGB565_TO_V(pixel);
                        pixel = COLOR_YUV_TO_RGB565(y, u, v);
                        IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel);
                    }
                }
            }
            break;
        }
    }
}
```

In the file **shared-bindings/bitmapfilter/\_\_init\_\_.c** , is the adapter function from CircuitPython to C. It opens with the C function definition, which will always have the following form. Next, the possible Python function arguments are declared, first as an `enum{}` and second as an `allowed_args[]`. The `args[]` array is created to have the same number of elements as `allowed_args[]`. Each element in the `enum` must match the element of&nbsp;`allowed_args[]` and can be used to index into the&nbsp;`args[]` array. The function `mp_arg_parse_all` takes care of converting the input arguments into the `args[]` array.

```cpp
STATIC mp_obj_t bitmapfilter_solarize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    enum { ARG_bitmap, ARG_threshold, ARG_mask };
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
        { MP_QSTR_threshold, MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } },
        { MP_QSTR_mask, MP_ARG_OBJ, { .u_obj = MP_ROM_NONE } },
    };
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
```

Next, the required processing of each object into the correct C type, such as `mp_float_t` or `displayio_bitmap_t *`, and dealing with the case where an optional argument was not specified:

```cpp
// (continued from above)
    mp_float_t threshold = (args[ARG_threshold].u_obj == NULL) ? MICROPY_FLOAT_CONST(0.5) : mp_obj_get_float(args[ARG_threshold].u_obj);
    mp_arg_validate_type(args[ARG_bitmap].u_obj, &amp;displayio_bitmap_type, MP_QSTR_bitmap);
    displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj);


    displayio_bitmap_t *mask = NULL;
    if (args[ARG_mask].u_obj != mp_const_none) {
        mp_arg_validate_type(args[ARG_mask].u_obj, &amp;displayio_bitmap_type, MP_QSTR_mask);
        mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj);
    }
```

Finally, the converted arguments are passed to the function that implements the filter, and the modified bitmap is used as the CircuitPython return value. Immediately following the function definition is a line to create the CircuitPython function object.

If your algorithm needs to return something other than the modified bitmap, then you would need to add calls to build the CircuitPython object corresponding to the output or result of the C image processing function, and return this instead of the bitmap argument.

```cpp
// (continued from above)
    shared_module_bitmapfilter_solarize(bitmap, mask, threshold);
    return args[ARG_bitmap].u_obj;
}
MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_solarize_obj, 0, bitmapfilter_solarize);
```

The final element is an entry in the bitmapfilter's module globals table for the function, near the bottom of **shared-bindings/bitmapfilter/\_\_init\_\_.c** :

```auto
STATIC const mp_rom_map_elem_t bitmapfilter_module_globals_table[] = {
    // ...
    { MP_ROM_QSTR(MP_QSTR_solarize), MP_ROM_PTR(&amp;bitmapfilter_solarize_obj) },
    // ...
};
```

At this point, you can compile your code and address any build errors that occur.

If you're using a Linux or Mac based development environment, you can also test your filter on a host computer before uploading firmware to a board. You can do this by building in the **ports/unix** subdirectory with a commandline like **make -j8 VARIANT=coverage**. The created program **build-coverage/micropython** has importable **bitmapfilter** and **displayio** modules (among others). You can run this **micropython** (including under the gdb debugger) for testing your algorithm on a host computer. By setting **MICROPYPATH=/complete/path/to/circuitpython/tests/testlib** in your shell environment, you will be able to import some useful routines for getting bitmap test data (`import blinka_image`) and for printing out representations of bitmaps on screen (`import dump_bitmap`)

You can run the test suite, including image processing tests, with **make -j8 VARIANT=coverage test**. This will run the tests including those in **tests/circuitpython**. Have a look at an existing test such as **tests/circuitpython/bitmapfilter\_solar.py** and its "expected output" file **tests/circuitpython/bitmapfilter\_solar.py.exp**. After some preliminaries, it creates a test bitmap with several color ramps, and runs the solarize algorithm on it. It dumps the image using Unicode characters that represent 5 brightness levels, showing the R, G, and B image channels separately:

```auto
print("solarize (masked)")
bitmapfilter.solarize(b, mask=q)
dump_bitmap_rgb_swapped(b)
```

In a proper, wide terminal window the results can be seen, though they can be difficult to interpret.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/050/medium800/camera_ksnip_20240115-110629.png?1705338451)

# Capturing Camera Images with CircuitPython

## Documentation: adafruit_ov2640

# Capturing Camera Images with CircuitPython

## Documentation: adafruit_ov7670

# Capturing Camera Images with CircuitPython

## Documentation: adafruit_ov5640


## Featured Products

### Raspberry Pi Pico RP2040

[Raspberry Pi Pico RP2040](https://www.adafruit.com/product/4864)
The Raspberry Pi foundation changed single-board computing [when they released the Raspberry Pi computer](https://www.raspberrypi.org/archives/723), now they're ready to do the same for microcontrollers with the release of the brand new **Raspberry Pi Pico**. This...

In Stock
[Buy Now](https://www.adafruit.com/product/4864)
[Related Guides to the Product](https://learn.adafruit.com/products/4864/guides)
### Adafruit PiCowbell Camera Breakout - Autofocus 72 Degree Lens

[Adafruit PiCowbell Camera Breakout - Autofocus 72 Degree Lens](https://www.adafruit.com/product/5945)
Ding dong! Hear that? It's the PiCowbell ringing, letting you know that the new&nbsp; **Adafruit PiCowbell OV5640 Camera Breakout with 72-Degree Lens and Autofocus** &nbsp;is in stock.

This is&nbsp;a quality OV5640 camera with a 5 Megapixel sensor element, a 72-degree...

In Stock
[Buy Now](https://www.adafruit.com/product/5945)
[Related Guides to the Product](https://learn.adafruit.com/products/5945/guides)
### USB C to Micro B Cable - 3 ft 1 meter

[USB C to Micro B Cable - 3 ft 1 meter](https://www.adafruit.com/product/3878)
As technology changes and adapts, so does Adafruit! Rather than the regular USB A, this cable has&nbsp; **USB C to Micro B** &nbsp;plugs!

USB C is the latest industry-standard connector for transmitting data _and_ power. Like Lightning and MagSafe cables, USB C has no...

In Stock
[Buy Now](https://www.adafruit.com/product/3878)
[Related Guides to the Product](https://learn.adafruit.com/products/3878/guides)
### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

Out of Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
### USB C to USB C Cable - USB 3.1 Gen 4 with E-Mark - 1 meter long

[USB C to USB C Cable - USB 3.1 Gen 4 with E-Mark - 1 meter long](https://www.adafruit.com/product/4199)
As technology changes and adapts, so does Adafruit! Rather than the regular USB A, this cable has&nbsp; **USB C to USB C** &nbsp;plugs!

USB C is the latest industry-standard connector for transmitting data&nbsp;_and_&nbsp;power. Like Lightning and MagSafe cables, USB C...

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

## Related Guides

- [Adafruit PiCowbell Camera Breakout](https://learn.adafruit.com/adafruit-picowbell-camera-breakout.md)
- [CircuitPython Libraries on any Computer with FT232H](https://learn.adafruit.com/circuitpython-on-any-computer-with-ft232h.md)
- [MP3 Playback in CircuitPython with Lars the Sloth Puppet](https://learn.adafruit.com/mp3-circuitpython-lars.md)
- [Talking HAL 9000 with RP2040 Prop Maker Feather](https://learn.adafruit.com/hal-9000-rp2040-prop-maker.md)
- [Little Desktop Connection Machine](https://learn.adafruit.com/little-connection-machine.md)
- [Lucky Cat with Circuit Playground Express](https://learn.adafruit.com/lucky-cat-with-circuit-playground-express.md)
- [LO-LA59 Droid](https://learn.adafruit.com/lola-droid.md)
- [Arduino to CircuitPython](https://learn.adafruit.com/arduino-to-circuitpython.md)
- [Adafruit Feather RP2040 RFM69](https://learn.adafruit.com/feather-rp2040-rfm69.md)
- [Data Logging with Feather and CircuitPython](https://learn.adafruit.com/data-logging-with-feather-and-circuitpython.md)
- [Timelapse Spy Camera](https://learn.adafruit.com/timelapse-spy-camera.md)
- [Custom HID Devices in CircuitPython](https://learn.adafruit.com/custom-hid-devices-in-circuitpython.md)
- [Adafruit pIRkey](https://learn.adafruit.com/adafruit-pirkey-python-programmable-infrared-usb-adapter.md)
- [Adafruit MagTag COVID Vaccination Percent Tracker](https://learn.adafruit.com/adafruit-magtag-covid-vaccination-percent-tracker.md)
- [Adafruit PyPortal - IoT for CircuitPython](https://learn.adafruit.com/adafruit-pyportal.md)
