66 if (img->
buf != NULL) {
87 output->
ts = input->
ts;
104 memcpy(&old_a, a,
sizeof(
struct image_t));
107 memcpy(a, b,
sizeof(
struct image_t));
110 memcpy(b, &old_a,
sizeof(
struct image_t));
126 output->
ts = input->
ts;
131 for (
int y = 0; y < output->
h; y++) {
132 for (
int x = 0; x < output->
w; x++) {
162 output->
ts = input->
ts;
165 for (
uint16_t y = 0; y < output->
h; y++) {
166 for (
uint16_t x = 0; x < output->
w; x += 2) {
184 char u = source[0] - 127;
223 if (x % 2 == 1) { x--; }
226 if (x < 0 || x >= im->
w || y < 0 || y >= im->
h) {
232 buf += 2 * (y * (im->
w) + x);
265 if (x % 2 == 1) { x--; }
268 if (x < 0 || x >= im->
w || y < 0 || y >= im->
h) {
274 buf += 2 * (y * (im->
w) + x);
303 uint16_t pixelskip = (downsample - 1) * 2;
306 output->
ts = input->
ts;
309 for (
uint16_t y = 0; y < output->
h; y++) {
310 for (
uint16_t x = 0; x < output->
w; x += 2) {
320 source += (downsample - 1) * input->
w * 2;
334 image_create(output, input->
w + 2 * border_size, input->
h + 2 * border_size, input->
type);
340 for (
uint16_t i = border_size; i != (output->
h - border_size); i++) {
343 for (
uint8_t j = 0; j != border_size; j++) {
344 output_buf[i * output->
w + (border_size - 1 - j)] = input_buf[(i - border_size) * input->
w + j];
348 memcpy(&output_buf[i * output->
w + border_size], &input_buf[(i - border_size) * input->
w],
sizeof(
uint8_t) * input->
w);
351 for (
uint8_t j = 0; j != border_size; j++) {
352 output_buf[i * output->
w + output->
w - border_size + j] = output_buf[i * output->
w + output->
w - border_size - 1 - j];
357 for (
uint8_t i = 0; i != border_size; i++) {
358 memcpy(&output_buf[(border_size - 1) * output->
w - i * output->
w], &output_buf[border_size * output->
w + i * output->
w],
360 memcpy(&output_buf[(output->
h - border_size) * output->
w + i * output->
w],
361 &output_buf[(output->
h - border_size - 1) * output->
w - i * output->
w],
sizeof(
uint8_t) * output->
w);
379 image_create(output, (input->
w + 1 - 2 * border_size) / 2, (input->
h + 1 - 2 * border_size) / 2, input->
type);
388 for (
uint16_t i = 0; i != output->
h; i++) {
390 for (
uint16_t j = 0; j != output->
w; j++) {
391 row = border_size + 2 * i;
392 col = border_size + 2 * j;
394 sum = 39 * (input_buf[(row - 2) * w + (col - 2)] + input_buf[(row - 2) * w + (col + 2)] +
395 input_buf[(row + 2) * w + (col - 2)] + input_buf[(row + 2) * w + (col + 2)]);
396 sum += 156 * (input_buf[(row - 2) * w + (col - 1)] + input_buf[(row - 2) * w + (col + 1)] +
397 input_buf[(row - 1) * w + (col + 2)] + input_buf[(row + 1) * w + (col - 2)]
398 + input_buf[(row + 1) * w + (col + 2)] + input_buf[(row + 2) * w + (col - 1)] + input_buf[(row + 2) * w + (col + 1)] +
399 input_buf[(row - 1) * w + (col - 2)]);
400 sum += 234 * (input_buf[(row - 2) * w + (col)] + input_buf[(row) * w + (col - 2)] +
401 input_buf[(row) * w + (col + 2)] + input_buf[(row + 2) * w + (col)]);
402 sum += 625 * (input_buf[(row - 1) * w + (col - 1)] + input_buf[(row - 1) * w + (col + 1)] +
403 input_buf[(row + 1) * w + (col - 1)] + input_buf[(row + 1) * w + (col + 1)]);
404 sum += 938 * (input_buf[(row - 1) * w + (col)] + input_buf[(row) * w + (col - 1)] +
405 input_buf[(row) * w + (col + 1)] + input_buf[(row + 1) * w + (col)]);
406 sum += 1406 * input_buf[(row) * w + (col)];
408 output_buf[i * output->
w + j] = sum / 10000;
431 for (
uint8_t i = 1; i != pyr_level + 1; i++) {
459 uint32_t subpixel_w = (input->
w - 2) * subpixel_factor;
460 uint32_t subpixel_h = (input->
h - 2) * subpixel_factor;
463 for (
uint16_t i = 0; i < output->
w; i++) {
464 for (
uint16_t j = 0; j < output->
h; j++) {
466 uint32_t x = center->
x + border_size * subpixel_factor + (i - half_window) * subpixel_factor;
467 uint32_t y = center->
y + border_size * subpixel_factor + (j - half_window) * subpixel_factor;
469 BoundUpper(x, subpixel_w);
470 BoundUpper(y, subpixel_h);
473 uint16_t orig_x = x / subpixel_factor;
474 uint16_t orig_y = y / subpixel_factor;
477 uint32_t tl_x = orig_x * subpixel_factor;
478 uint32_t tl_y = orig_y * subpixel_factor;
481 if (tl_x == x && tl_y == y) {
482 output_buf[output->
w * j + i] = input_buf[input->
w * orig_y + orig_x];
489 uint32_t blend = (subpixel_factor - alpha_x) * (subpixel_factor - alpha_y) * input_buf[input->
w * orig_y + orig_x];
490 blend += alpha_x * (subpixel_factor - alpha_y) * input_buf[input->
w * orig_y + (orig_x + 1)];
491 blend += (subpixel_factor - alpha_x) * alpha_y * input_buf[input->
w * (orig_y + 1) + orig_x];
492 blend += alpha_x * alpha_y * input_buf[input->
w * (orig_y + 1) + (orig_x + 1)];
495 output_buf[output->
w * j + i] = blend / (subpixel_factor * subpixel_factor);
516 for (
uint16_t x = 1; x < input->
w - 1; x++) {
517 for (
uint16_t y = 1; y < input->
h - 1; y++) {
518 dx_buf[(y - 1)*dx->
w + (x - 1)] = (
int16_t)input_buf[y * input->
w + x + 1] - (
int16_t)input_buf[y * input->
w + x - 1];
519 dy_buf[(y - 1)*dy->
w + (x - 1)] = (
int16_t)input_buf[(y + 1) * input->
w + x] - (
int16_t)
520 input_buf[(y - 1) * input->
w + x];
534 int32_t sum_dxx = 0, sum_dxy = 0, sum_dyy = 0;
543 sum_dxx += ((
int32_t)dx_buf[y * dx->
w + x] * dx_buf[y * dx->
w + x]);
544 sum_dxy += ((
int32_t)dx_buf[y * dx->
w + x] * dy_buf[y * dy->
w + x]);
545 sum_dyy += ((
int32_t)dy_buf[y * dy->
w + x] * dy_buf[y * dy->
w + x]);
550 g[0] = sum_dxx / 255;
551 g[1] = sum_dxy / 255;
553 g[3] = sum_dyy / 255;
579 for (
uint16_t x = 0; x < img_b->
w; x++) {
580 for (
uint16_t y = 0; y < img_b->
h; y++) {
581 int16_t diff_c = img_a_buf[(y + 1) * img_a->
w + (x + 1)] - img_b_buf[y * img_b->
w + x];
582 sum_diff2 += diff_c * diff_c;
585 if (diff_buf != NULL) {
586 diff_buf[y * diff->
w + x] = diff_c;
615 for (
uint16_t x = 0; x < img_a->
w; x++) {
616 for (
uint16_t y = 0; y < img_a->
h; y++) {
617 int32_t mult_c = img_a_buf[y * img_a->
w + x] * img_b_buf[y * img_b->
w + x];
621 if (mult_buf != NULL) {
622 mult_buf[y * mult->
w + x] = mult_c;
666 int size_crosshair = 5;
669 for (
int i = 0; i < points_cnt; i++) {
671 uint32_t idx = pixel_width * points[i].
y * img->
w + points[i].
x * pixel_width;
687 static uint8_t color[4] = {255, 255, 255, 255};
688 static uint8_t bad_color[4] = {0, 0, 0, 0};
705 static int size_crosshair = 5;
708 for (
uint16_t i = 0; i < points_cnt; i++) {
711 .
x = vectors[i].
pos.
x / subpixel_factor,
712 .y = vectors[i].
pos.
y / subpixel_factor
715 .
x = (vectors[i].
pos.
x + vectors[i].
flow_x) / subpixel_factor,
716 .
y = (vectors[i].pos.y + vectors[i].
flow_y) / subpixel_factor
740 int gradient_x, gradient_y, index;
747 uint8_t add_ind = pixel_width - 1;
750 if (loc->
x >= 1 && (loc->
x + 1) < img->
w && loc->
y >= 1 && (loc->
y + 1) < img->
h) {
758 index = loc->
y * img->
w * pixel_width + (loc->
x - 1) * pixel_width;
759 gradient_x -= (int) img_buf[index + add_ind];
760 index = loc->
y * img->
w * pixel_width + (loc->
x + 1) * pixel_width;
761 gradient_x += (int) img_buf[index + add_ind];
763 index = (loc->
y - 1) * img->
w * pixel_width + loc->
x * pixel_width;
764 gradient_y -= (
int) img_buf[index + add_ind];
765 index = (loc->
y + 1) * img->
w * pixel_width + loc->
x * pixel_width;
766 gradient_y += (
int) img_buf[index + add_ind];
772 static int Sobel[9] = { -1, 0, 1, -2, 0, 2, -1, 0, 1};
773 static int total_sobel = 8;
777 for (
int x = -1;
x <= 1;
x++) {
778 for (
int y = -1;
y <= 1;
y++) {
779 index = (loc->
y +
y) * img->
w * pixel_width + (loc->
x +
x) * pixel_width;
781 filt_ind_x = (
x + 1) % 3 + (
y + 1) * 3;
782 gradient_x += Sobel[filt_ind_x] * (int) img_buf[index + add_ind];
785 gradient_y += Sobel[filt_ind_y] * (int) img_buf[index + add_ind];
790 gradient_x /= total_sobel;
854 if (loc->
x >= size_crosshair && loc->
x < img->
w - size_crosshair
855 && loc->
y >= size_crosshair && loc->
y < img->
h - size_crosshair) {
857 from.
x = loc->
x - size_crosshair;
859 to.
x = loc->
x + size_crosshair;
863 from.
y = loc->
y - size_crosshair;
865 to.
y = loc->
y + size_crosshair;
878 static uint8_t color[4] = {255, 255, 255, 255};
893 int xerr = 0, yerr = 0;
899 uint8_t temp_color[4] = {color[0], color[1], color[2], color[3]};
910 if (delta_x > 0) { incx = 1; }
911 else if (delta_x == 0) { incx = 0; }
914 if (delta_y > 0) { incy = 1; }
915 else if (delta_y == 0) { incy = 0; }
920 delta_x = abs(delta_x);
921 delta_y = abs(delta_y);
922 if (delta_x > delta_y) { distance = delta_x * 20; }
923 else { distance = delta_y * 20; }
926 for (
uint16_t t = 0; starty < img->
h && startx < img->
w
927 && t <= distance + 1; t++) {
930 if (startx % 2 == 1) {
931 temp_color[0] = color[2];
932 temp_color[2] = color[0];
934 temp_color[0] = color[0];
935 temp_color[2] = color[2];
937 uint32_t buf_loc = img->
w * pixel_width * starty + startx * pixel_width;
938 img_buf[buf_loc] = temp_color[0];
941 img_buf[buf_loc + 1] = temp_color[1];
943 if (startx + 1 < img->
w) {
944 img_buf[buf_loc + 2] = temp_color[2];
945 img_buf[buf_loc + 3] = temp_color[3];
951 if (xerr > distance) {
955 if (yerr > distance) {
void image_gradients(struct image_t *input, struct image_t *dx, struct image_t *dy)
Calculate the gradients using the following matrix: [0 -1 0; -1 0 1; 0 1 0].
void set_color_yuv422(struct image_t *im, int x, int y, uint8_t Y, uint8_t U, uint8_t V)
Sets Y,U,V for a single pixel.
uint32_t buf_size
The buffer size.
void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint16_t downsample)
Simplified high-speed low CPU downsample function without averaging downsample factor must be 1...
uint32_t image_difference(struct image_t *img_a, struct image_t *img_b, struct image_t *diff)
Calculate the difference between two images and return the error This will only work with grayscale i...
void image_switch(struct image_t *a, struct image_t *b)
This will switch image *a and *b This is faster as image_copy because it doesn't copy the whole image...
void image_free(struct image_t *img)
Free the image.
void image_draw_line_color(struct image_t *img, struct point_t *from, struct point_t *to, const uint8_t *color)
Draw a line on the image.
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
void image_draw_line(struct image_t *img, struct point_t *from, struct point_t *to)
Draw a pink line on the image.
void image_show_flow_color(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor, const uint8_t *color, const uint8_t *bad_color)
Shows the flow from a specific point to a new point This works on YUV422 and Grayscale images...
void image_copy(struct image_t *input, struct image_t *output)
Copy an image from inut to output This will only work if the formats are the same.
void image_show_points(struct image_t *img, struct point_t *points, uint16_t points_cnt)
Show points in an image by coloring them through giving the pixels the maximum value.
uint32_t x
The x coordinate of the point.
uint32_t pprz_ts
The timestamp in us since system startup.
void image_show_flow(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor)
void image_draw_rectangle(struct image_t *img, int x_min, int x_max, int y_min, int y_max, uint8_t *color)
Draw a rectangle on the image.
void pyramid_build(struct image_t *input, struct image_t *output_array, uint8_t pyr_level, uint16_t border_size)
This function populates given array of image_t structs with wanted number of padded pyramids based on...
void pyramid_next_level(struct image_t *input, struct image_t *output, uint8_t border_size)
This function takes previous padded pyramid level and outputs next level of pyramid without padding...
Image helper functions like resizing, color filter, converters...
int16_t flow_x
The x direction flow in subpixels.
void image_gradient_pixel(struct image_t *img, struct point_t *loc, int method, int *dx, int *dy)
Get the gradient at a pixel location.
void image_add_border(struct image_t *input, struct image_t *output, uint8_t border_size)
This function adds padding to input image by mirroring the edge image elements.
void * buf
Image buffer (depending on the image_type)
void image_draw_crosshair(struct image_t *img, struct point_t *loc, const uint8_t *color, uint32_t size_crosshair)
Draw a cross-hair on the image.
struct point_t pos
The original position the flow comes from.
uint32_t y
The y coordinate of the point.
void image_to_grayscale(struct image_t *input, struct image_t *output)
Convert an image to grayscale.
efficient fixed-point optical-flow calculation
struct timeval ts
The timestamp of creation.
UYVY format (uint16 per pixel)
void image_calculate_g(struct image_t *dx, struct image_t *dy, int32_t *g)
Calculate the G vector of an image gradient This is used for optical flow calculation.
An image gradient (int16 per pixel)
uint16_t image_yuv422_colorfilt(struct image_t *input, struct image_t *output, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M)
Filter colors in an YUV422 image.
struct FloatEulers eulers
Euler Angles at time of image.
int16_t flow_y
The y direction flow in subpixels.
int32_t image_multiply(struct image_t *img_a, struct image_t *img_b, struct image_t *mult)
Calculate the multiplication between two images and return the error This will only work with image g...
int check_color_yuv422(struct image_t *im, int x, int y, uint8_t y_m, uint8_t y_M, uint8_t u_m, uint8_t u_M, uint8_t v_m, uint8_t v_M)
Checks the color of a single pixel in a YUV422 image.
void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center, uint32_t subpixel_factor, uint8_t border_size)
This outputs a subpixel window image in grayscale Currently only works with Grayscale images as input...
An JPEG encoded image (not per pixel encoded)
enum image_type type
The image type.
void image_show_points_color(struct image_t *img, struct point_t *points, uint16_t points_cnt, uint8_t *color)
Show points in an image by coloring them through giving the pixels the maximum value.