Skip to content

Instantly share code, notes, and snippets.

@usedbytes
Last active January 25, 2022 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save usedbytes/0bc9a29bf52724467e4b13d3ed9cb1bd to your computer and use it in GitHub Desktop.
Save usedbytes/0bc9a29bf52724467e4b13d3ed9cb1bd to your computer and use it in GitHub Desktop.
Simple routine to find the middle of the reddest blob in a YUV422 image
const uint8_t threshold = 10;
// Search for the furthest left and furthest right pixels in 'row'
// which are at least as bright as 'maxval - threshold', starting at 'start_idx'
static void search_row(uint8_t *row, int len, int start_idx, uint8_t maxval,
int *left_out, int *right_out)
{
int i;
int left = start_idx;
int right = start_idx;
// Search to the left
for (i = start_idx; i >= 0; i--) {
if (maxval - row[i] <= threshold) {
left = i;
} else {
break;
}
}
// Search to the right
for (i = start_idx + 1; i < len; i++) {
if (maxval - row[i] <= threshold) {
right = i;
} else {
break;
}
}
*left_out = left;
*right_out = right;
}
// Returns the middle 'X' coordinate of the brightest red blob
static int find_red_blob(struct camera_buffer *buf)
{
uint32_t start = time_us_32();
int x, y;
uint8_t reddest = 0;
int max_x = 0, max_y = 0;
// First find the reddest pixel in the image.
// It's a YCbCr image, we only care about "redness", which is Cr
// which is stored in buf->data[2]
for (y = 0; y < buf->height; y++) {
// Note: buf->width / 2, because this is a YUV422 image,
// so the Cr plane is half as wide as the image itself
for (x = 0; x < buf->width / 2; x++) {
uint8_t pix = buf->data[2][buf->strides[2] * y + x];
if (pix > reddest) {
reddest = pix;
max_x = x;
max_y = y;
}
}
}
log_printf(&util_logger, "reddest: %d", reddest);
// Next, we search up and down the rows, looking for ones which are also
// part of the blob.
// On each row, we find the leftmost and rightmost pixel which is within
// some threshold of the reddest value.
// Then we take the middle of that left..right range to use as the
// starting point for searching the next row.
// l and r track the absolute leftmost and rightmost extremes of the
// blob, eventually giving its widest point.
int l = max_x;
int r = max_x;
int tmp_l, tmp_r;
// Search up
int idx = max_x;
for (y = max_y; y >= 0; y--) {
uint8_t *row = &buf->data[2][buf->strides[2] * y];
// Only search this row if the starting point is actually
// red enough
if (reddest - row[idx] < threshold) {
// Note: buf->width / 2, because this is a YUV422 image,
// so the Cr plane is half as wide as the image itself
search_row(row, buf->width / 2, idx, reddest, &tmp_l, &tmp_r);
// Update the global leftmost/rightmost values
l = tmp_l < l ? tmp_l : l;
r = tmp_r > r ? tmp_r : r;
// Calculate the starting point for the next row
idx = tmp_l + ((tmp_r - tmp_l) / 2);
} else {
break;
}
}
// Search down, starting with the middle X coord we've found so far
idx = l + ((r - l) / 2);
for (y = max_y; y < buf->height; y++) {
uint8_t *row = &buf->data[2][buf->strides[2] * y];
if (reddest - row[idx] < threshold) {
search_row(row, buf->width / 2, idx, reddest, &tmp_l, &tmp_r);
l = tmp_l < l ? tmp_l : l;
r = tmp_r > r ? tmp_r : r;
} else {
break;
}
}
// Finally, calculate the overall middle X coord
int mid = l + (r - l) / 2;
log_printf(&util_logger, "Process done. %d us, mid %d", time_us_32() - start, mid);
return mid;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment