Skip to content

Commit f057dfb

Browse files
authored
Merge pull request #218 from brilliantlabsAR/camera-qf
Camera quality factor
2 parents 01823c6 + 92a6079 commit f057dfb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+35863
-30621
lines changed

docs/fpga-architecture.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ The SPI driver interfaces the FPGA with the nRF52. The FPGA is fully driven over
1414

1515
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.
1616

17-
| Address | Function | Description |
18-
|:-------:|-----------------------------|-------------|
19-
| 0x10 | `GRAPHICS_CLEAR` | Clears the background frame buffer.
20-
| 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]`**
21-
| 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>
22-
| 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]`**
23-
| 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.
24-
| 0x20 | `CAMERA_CAPTURE` | Starts a new image capture.
25-
| 0x21 | `CAMERA_BYTES_AVAILABLE` | Returns how many bytes are available to read within the capture memory.<br>**Read: `bytes_available[23:0]`**
26-
| 0x22 | `CAMERA_READ_BYTES` | Reads a number of bytes from the capture memory.<br>**Read: `data[7:0]`**<br>**...**<br>**Read: `data[7:0]`**
27-
| 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]`**
28-
| 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]`**
29-
| 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]`**
30-
| 0x26 | `CAMERA_COMPRESSION_FACTOR` | Sets the compression factor of the saved image between `-10` and `10`.<br>**Write: `compression_factor[7:0]`**
31-
| 0xDB | `GET_CHIP_ID` | Returns the chip ID value.<br>**Read: `0x81`**
17+
| Address | Function | Description |
18+
|:-------:|-------------------------|-------------|
19+
| 0x10 | `GRAPHICS_CLEAR` | Clears the background frame buffer.
20+
| 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]`**
21+
| 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>
22+
| 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]`**
23+
| 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.
24+
| 0x20 | `CAMERA_CAPTURE` | Starts a new image capture.
25+
| 0x21 | `CAMERA_BYTES_AVAILABLE`| Returns how many bytes are available to read within the capture memory.<br>**Read: `bytes_available[23:0]`**
26+
| 0x22 | `CAMERA_READ_BYTES` | Reads a number of bytes from the capture memory.<br>**Read: `data[7:0]`**<br>**...**<br>**Read: `data[7:0]`**
27+
| 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]`**
28+
| 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]`**
29+
| 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]`**
30+
| 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%
31+
| 0xDB | `GET_CHIP_ID` | Returns the chip ID value.<br>**Read: `0x81`**
3232

3333
## Graphics
3434

production/focus_camera_script.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ async def capture_and_download(b: Bluetooth):
2727
image_buffer = b""
2828
done = False
2929

30-
await b.send_lua(f"frame.camera.capture()")
30+
await b.send_lua("frame.camera.capture{}")
3131

3232
for _ in range(3):
3333
await b.send_lua("frame.camera.auto{}")

source/application/lua_libraries/camera.c

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ static struct camera_auto_last_values
5050
.gain = 0,
5151
};
5252

53+
static lua_Integer camera_quality_factor = 50;
5354
static size_t jpeg_header_bytes_sent_out = 0;
5455
static size_t jpeg_footer_bytes_sent_out = 0;
5556

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

64+
lua_Integer quality_factor = 50;
65+
66+
if (lua_getfield(L, 1, "quality_factor") != LUA_TNIL)
67+
{
68+
quality_factor = luaL_checkinteger(L, -1);
69+
70+
switch (quality_factor)
71+
{
72+
case 100:
73+
spi_write(FPGA, 0x26, (uint8_t *)"\x01", 1);
74+
break;
75+
76+
case 50:
77+
spi_write(FPGA, 0x26, (uint8_t *)"\x00", 1);
78+
break;
79+
80+
case 25:
81+
spi_write(FPGA, 0x26, (uint8_t *)"\x03", 1);
82+
break;
83+
84+
case 10:
85+
spi_write(FPGA, 0x26, (uint8_t *)"\x02", 1);
86+
break;
87+
88+
default:
89+
luaL_error(L, "quality_factor must be either 100, 50, 25 or 10");
90+
break;
91+
}
92+
}
93+
6394
spi_write(FPGA, 0x20, NULL, 0);
95+
camera_quality_factor = quality_factor;
6496
jpeg_header_bytes_sent_out = 0;
6597
jpeg_footer_bytes_sent_out = 0;
6698
return 0;
@@ -94,12 +126,43 @@ static int lua_camera_read(lua_State *L)
94126
luaL_error(L, "bytes requested is too large");
95127
}
96128

129+
// TODO this ends up placing the arrays in RAM. Make it static somehow
130+
uint8_t *jpeg_header = NULL;
131+
size_t jpeg_header_length = 0;
132+
133+
switch (camera_quality_factor)
134+
{
135+
case 100:
136+
jpeg_header = (uint8_t *)jpeg_header_qf_100;
137+
jpeg_header_length = sizeof(jpeg_header_qf_100);
138+
break;
139+
140+
case 50:
141+
jpeg_header = (uint8_t *)jpeg_header_qf_50;
142+
jpeg_header_length = sizeof(jpeg_header_qf_50);
143+
break;
144+
145+
case 25:
146+
jpeg_header = (uint8_t *)jpeg_header_qf_25;
147+
jpeg_header_length = sizeof(jpeg_header_qf_25);
148+
break;
149+
150+
case 10:
151+
jpeg_header = (uint8_t *)jpeg_header_qf_10;
152+
jpeg_header_length = sizeof(jpeg_header_qf_10);
153+
break;
154+
155+
default:
156+
error_with_message("Invalid camera_quality_factor");
157+
break;
158+
}
159+
97160
// Append JPEG header data
98-
if (jpeg_header_bytes_sent_out < sizeof(jpeg_header))
161+
if (jpeg_header_bytes_sent_out < jpeg_header_length)
99162
{
100163
size_t length =
101-
sizeof(jpeg_header) - jpeg_header_bytes_sent_out < bytes_requested
102-
? sizeof(jpeg_header) - jpeg_header_bytes_sent_out
164+
jpeg_header_length - jpeg_header_bytes_sent_out < bytes_requested
165+
? jpeg_header_length - jpeg_header_bytes_sent_out
103166
: bytes_requested;
104167

105168
memcpy(payload, jpeg_header + jpeg_header_bytes_sent_out, length);

0 commit comments

Comments
 (0)