Skip to content

Commit

Permalink
Merge pull request #218 from brilliantlabsAR/camera-qf
Browse files Browse the repository at this point in the history
Camera quality factor
  • Loading branch information
siliconwitch authored Jun 27, 2024
2 parents 01823c6 + 92a6079 commit f057dfb
Show file tree
Hide file tree
Showing 51 changed files with 35,863 additions and 30,621 deletions.
30 changes: 15 additions & 15 deletions docs/fpga-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ The SPI driver interfaces the FPGA with the nRF52. The FPGA is fully driven over

Each function is accessed through a register. Registers are always addressed by one byte, followed by a various number of read or write bytes based on the operation.

| Address | Function | Description |
|:-------:|-----------------------------|-------------|
| 0x10 | `GRAPHICS_CLEAR` | Clears the background frame buffer.
| 0x11 | `GRAPHICS_ASSIGN_COLOR` | Assigns a color to one of the 16 color palette slots. Color should be provided in YCbCr format.<br>**Write: `palette_index[7:0]`**<br>**Write: `y[7:0]`**<br>**Write: `cb[7:0]`**<br>**Write: `cr[7:0]`**
| 0x12 | `GRAPHICS_DRAW_SPRITE` | Draws a sprite on the screen. The first two arguments specify an absolute x and y position to print the sprite. The sprite will be printed from its top left corner. The third argument determines the width of the sprite in pixels. The fourth argument determines the number of colors contained in the sprite. This value may be 2, 4, or 16. The final argument specifies the color palette offset for assigning the color values held in the sprite against the stored colors in the palette. Following bytes will then be printed on the background frame buffer.<br>**Write: `x_position[15:0]`**<br>**Write: `y_position[15:0]`**<br>**Write: `width[15:0]`**<br>**Write: `total_colors[7:0]`**<br>**Write: `palette_offset[7:0]`**<br>**Write: `pixel_data[7:0]`**<br>**...**<br>**Write: `pixel_data[7:0]`**<br>
| 0x13 | `GRAPHICS_DRAW_VECTOR` | Draws a cubic Bézier curve from the start position to the end position. Control points 1 and 2 are relative to the start and end positions respectively, and are used to determine the shape of the curve. The final argument determines the color used from the current palette, and can be between 0 and 15.<br>**Write: `x_start_position[15:0]`**<br>**Write: `y_start_position[15:0]`**<br>**Write: `x_end_position[15:0]`**<br>**Write: `y_end_position[15:0]`**<br>**Write: `ctrl_1_x_position[15:0]`**<br>**Write: `ctrl_1_y_position[15:0]`**<br>**Write: `ctrl_2_x_position[15:0]`**<br>**Write: `ctrl_2_y_position[15:0]`**<br>**Write: `color[7:0]`**
| 0x14 | `GRAPHICS_BUFFER_SHOW` | The foreground and background buffers are switched. The new foreground buffer is continuously rendered to the display, and the background buffer can be used to load new draw commands.
| 0x20 | `CAMERA_CAPTURE` | Starts a new image capture.
| 0x21 | `CAMERA_BYTES_AVAILABLE` | Returns how many bytes are available to read within the capture memory.<br>**Read: `bytes_available[23:0]`**
| 0x22 | `CAMERA_READ_BYTES` | Reads a number of bytes from the capture memory.<br>**Read: `data[7:0]`**<br>**...**<br>**Read: `data[7:0]`**
| 0x23 | `CAMERA_ZOOM` | Sets the zoom factor. A setting of `1` captures a 720x720 image, `2` captures 360x360, `3` captures 240x240, and `4` captures 180x180.<br>**Write: `zoom_factor[7:0]`**
| 0x24 | `CAMERA_PAN` | Pans the capture window up or down in discrete steps. A setting of `10` captures the top-most part of the image, `0` is the middle, and `-10` is the bottom-most<br>**Write: `pan_position[7:0]`**
| 0x25 | `CAMERA_READ_METERING` | Returns the current brightness levels for the red, green and blue channels of the camera. Two sets of values are returned representing spot and average metering.<br>**Read: `center_red_level[7:0]`**<br>**Read: `center_green_level[7:0]`**<br>**Read: `center_blue_level[7:0]`**<br>**Read: `average_red_level[7:0]`**<br>**Read: `average_green_level[7:0]`**<br>**Read: `average_blue_level[7:0]`**
| 0x26 | `CAMERA_COMPRESSION_FACTOR` | Sets the compression factor of the saved image between `-10` and `10`.<br>**Write: `compression_factor[7:0]`**
| 0xDB | `GET_CHIP_ID` | Returns the chip ID value.<br>**Read: `0x81`**
| Address | Function | Description |
|:-------:|-------------------------|-------------|
| 0x10 | `GRAPHICS_CLEAR` | Clears the background frame buffer.
| 0x11 | `GRAPHICS_ASSIGN_COLOR` | Assigns a color to one of the 16 color palette slots. Color should be provided in YCbCr format.<br>**Write: `palette_index[7:0]`**<br>**Write: `y[7:0]`**<br>**Write: `cb[7:0]`**<br>**Write: `cr[7:0]`**
| 0x12 | `GRAPHICS_DRAW_SPRITE` | Draws a sprite on the screen. The first two arguments specify an absolute x and y position to print the sprite. The sprite will be printed from its top left corner. The third argument determines the width of the sprite in pixels. The fourth argument determines the number of colors contained in the sprite. This value may be 2, 4, or 16. The final argument specifies the color palette offset for assigning the color values held in the sprite against the stored colors in the palette. Following bytes will then be printed on the background frame buffer.<br>**Write: `x_position[15:0]`**<br>**Write: `y_position[15:0]`**<br>**Write: `width[15:0]`**<br>**Write: `total_colors[7:0]`**<br>**Write: `palette_offset[7:0]`**<br>**Write: `pixel_data[7:0]`**<br>**...**<br>**Write: `pixel_data[7:0]`**<br>
| 0x13 | `GRAPHICS_DRAW_VECTOR` | Draws a cubic Bézier curve from the start position to the end position. Control points 1 and 2 are relative to the start and end positions respectively, and are used to determine the shape of the curve. The final argument determines the color used from the current palette, and can be between 0 and 15.<br>**Write: `x_start_position[15:0]`**<br>**Write: `y_start_position[15:0]`**<br>**Write: `x_end_position[15:0]`**<br>**Write: `y_end_position[15:0]`**<br>**Write: `ctrl_1_x_position[15:0]`**<br>**Write: `ctrl_1_y_position[15:0]`**<br>**Write: `ctrl_2_x_position[15:0]`**<br>**Write: `ctrl_2_y_position[15:0]`**<br>**Write: `color[7:0]`**
| 0x14 | `GRAPHICS_BUFFER_SHOW` | The foreground and background buffers are switched. The new foreground buffer is continuously rendered to the display, and the background buffer can be used to load new draw commands.
| 0x20 | `CAMERA_CAPTURE` | Starts a new image capture.
| 0x21 | `CAMERA_BYTES_AVAILABLE`| Returns how many bytes are available to read within the capture memory.<br>**Read: `bytes_available[23:0]`**
| 0x22 | `CAMERA_READ_BYTES` | Reads a number of bytes from the capture memory.<br>**Read: `data[7:0]`**<br>**...**<br>**Read: `data[7:0]`**
| 0x23 | `CAMERA_ZOOM` | Sets the zoom factor. A setting of `1` captures a 720x720 image, `2` captures 360x360, `3` captures 240x240, and `4` captures 180x180.<br>**Write: `zoom_factor[7:0]`**
| 0x24 | `CAMERA_PAN` | Pans the capture window up or down in discrete steps. A setting of `10` captures the top-most part of the image, `0` is the middle, and `-10` is the bottom-most<br>**Write: `pan_position[7:0]`**
| 0x25 | `CAMERA_READ_METERING` | Returns the current brightness levels for the red, green and blue channels of the camera. Two sets of values are returned representing spot and average metering.<br>**Read: `center_red_level[7:0]`**<br>**Read: `center_green_level[7:0]`**<br>**Read: `center_blue_level[7:0]`**<br>**Read: `average_red_level[7:0]`**<br>**Read: `average_green_level[7:0]`**<br>**Read: `average_blue_level[7:0]`**
| 0x26 | `CAMERA_QUALITY_FACTOR` | Sets the jpeg quality factor of the saved image. High values are higher quality but bigger size.<br>**Write: `quality_factor[1:0]`**.<br>- **0b01** = 100%<br>- **0b00** = 50%<br>- **0b11** = 25%<br>- **0b10** = 10%
| 0xDB | `GET_CHIP_ID` | Returns the chip ID value.<br>**Read: `0x81`**

## Graphics

Expand Down
2 changes: 1 addition & 1 deletion production/focus_camera_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def capture_and_download(b: Bluetooth):
image_buffer = b""
done = False

await b.send_lua(f"frame.camera.capture()")
await b.send_lua("frame.camera.capture{}")

for _ in range(3):
await b.send_lua("frame.camera.auto{}")
Expand Down
69 changes: 66 additions & 3 deletions source/application/lua_libraries/camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ static struct camera_auto_last_values
.gain = 0,
};

static lua_Integer camera_quality_factor = 50;
static size_t jpeg_header_bytes_sent_out = 0;
static size_t jpeg_footer_bytes_sent_out = 0;

Expand All @@ -60,7 +61,38 @@ static int lua_camera_capture(lua_State *L)
luaL_error(L, "camera is asleep");
}

lua_Integer quality_factor = 50;

if (lua_getfield(L, 1, "quality_factor") != LUA_TNIL)
{
quality_factor = luaL_checkinteger(L, -1);

switch (quality_factor)
{
case 100:
spi_write(FPGA, 0x26, (uint8_t *)"\x01", 1);
break;

case 50:
spi_write(FPGA, 0x26, (uint8_t *)"\x00", 1);
break;

case 25:
spi_write(FPGA, 0x26, (uint8_t *)"\x03", 1);
break;

case 10:
spi_write(FPGA, 0x26, (uint8_t *)"\x02", 1);
break;

default:
luaL_error(L, "quality_factor must be either 100, 50, 25 or 10");
break;
}
}

spi_write(FPGA, 0x20, NULL, 0);
camera_quality_factor = quality_factor;
jpeg_header_bytes_sent_out = 0;
jpeg_footer_bytes_sent_out = 0;
return 0;
Expand Down Expand Up @@ -94,12 +126,43 @@ static int lua_camera_read(lua_State *L)
luaL_error(L, "bytes requested is too large");
}

// TODO this ends up placing the arrays in RAM. Make it static somehow
uint8_t *jpeg_header = NULL;
size_t jpeg_header_length = 0;

switch (camera_quality_factor)
{
case 100:
jpeg_header = (uint8_t *)jpeg_header_qf_100;
jpeg_header_length = sizeof(jpeg_header_qf_100);
break;

case 50:
jpeg_header = (uint8_t *)jpeg_header_qf_50;
jpeg_header_length = sizeof(jpeg_header_qf_50);
break;

case 25:
jpeg_header = (uint8_t *)jpeg_header_qf_25;
jpeg_header_length = sizeof(jpeg_header_qf_25);
break;

case 10:
jpeg_header = (uint8_t *)jpeg_header_qf_10;
jpeg_header_length = sizeof(jpeg_header_qf_10);
break;

default:
error_with_message("Invalid camera_quality_factor");
break;
}

// Append JPEG header data
if (jpeg_header_bytes_sent_out < sizeof(jpeg_header))
if (jpeg_header_bytes_sent_out < jpeg_header_length)
{
size_t length =
sizeof(jpeg_header) - jpeg_header_bytes_sent_out < bytes_requested
? sizeof(jpeg_header) - jpeg_header_bytes_sent_out
jpeg_header_length - jpeg_header_bytes_sent_out < bytes_requested
? jpeg_header_length - jpeg_header_bytes_sent_out
: bytes_requested;

memcpy(payload, jpeg_header + jpeg_header_bytes_sent_out, length);
Expand Down
Loading

0 comments on commit f057dfb

Please sign in to comment.