Last active
January 25, 2022 19:52
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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