32 #ifndef CACHE_LINE_LENGTH
33 #define CACHE_LINE_LENGTH 64
63 #if __GLIBC__ > 2 || (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 16)
77 if (img->
buf != NULL) {
98 output->
ts = input->
ts;
116 memcpy(&old_a, a,
sizeof(
struct image_t));
119 memcpy(a,
b,
sizeof(
struct image_t));
122 memcpy(
b, &old_a,
sizeof(
struct image_t));
138 output->
ts = input->
ts;
143 int height = output->
h;
144 int width = output->
w;
146 for (
int y = 0; y < height; y++) {
147 for (
int x = 0; x < width; x++) {
154 for (
int y = 0; y < height * width; y++) {
181 output->
ts = input->
ts;
184 for (
uint16_t y = 0; y < output->
h; y++) {
185 for (
uint16_t x = 0; x < output->
w; x += 2) {
203 char u = source[0] - 127;
242 if (x % 2 == 1) { x--; }
245 if (x < 0 || x >= im->
w || y < 0 || y >= im->
h) {
251 buf += 2 * (y * (im->
w) + x);
284 if (x % 2 == 1) { x--; }
287 if (x < 0 || x >= im->
w || y < 0 || y >= im->
h) {
293 buf += 2 * (y * (im->
w) + x);
325 if((downsample & (downsample - 1)) != 0){
326 for(
int8_t i = 7; i > 0; i--){
327 if(downsample & (1<<i)){
328 downsample &= (1<<(i));
337 uint16_t pixelskip = (downsample - 1) * 2;
339 output->
w = input->
w / downsample;
340 output->
h = input->
h / downsample;
344 output->
ts = input->
ts;
347 for (
uint16_t y = 0; y < output->
h; y++) {
348 for (
uint16_t x = 0; x < output->
w; x += 2) {
357 source += pixelskip * input->
w;
371 image_create(output, input->
w + 2 * border_size, input->
h + 2 * border_size, input->
type);
377 for (
uint16_t i = border_size; i != (output->
h - border_size); i++) {
380 for (
uint8_t j = 0; j != border_size; j++) {
381 output_buf[i * output->
w + (border_size - 1 - j)] = input_buf[(i - border_size) * input->
w + j];
385 memcpy(&output_buf[i * output->
w + border_size], &input_buf[(i - border_size) * input->
w],
sizeof(
uint8_t) * input->
w);
388 for (
uint8_t j = 0; j != border_size; j++) {
389 output_buf[i * output->
w + output->
w - border_size + j] = output_buf[i * output->
w + output->
w - border_size - 1 - j];
394 for (
uint8_t i = 0; i != border_size; i++) {
395 memcpy(&output_buf[(border_size - 1) * output->
w - i * output->
w], &output_buf[border_size * output->
w + i * output->
w],
397 memcpy(&output_buf[(output->
h - border_size) * output->
w + i * output->
w],
398 &output_buf[(output->
h - border_size - 1) * output->
w - i * output->
w],
sizeof(
uint8_t) * output->
w);
417 image_create(output, (input->
w + 1 - 2 * border_size) / 2, (input->
h + 1 - 2 * border_size) / 2, input->
type);
427 for (
uint16_t i = 0; i != output->
h; i++) {
428 for (
uint16_t j = 0; j != output->
w; j++) {
429 row = border_size + 2 * i;
430 col = border_size + 2 * j;
432 sum = (input_buf[row *
w + col]) >> 1;
433 sum += (input_buf[row *
w + col + 1] + input_buf[row *
w + col - 1]) >> 2;
435 output_buf[i * output->
w + j] = sum;
440 for (
uint16_t i = 0; i != output->
h - border_size; i++) {
441 for (
uint16_t j = 0; j != output->
w - border_size; j++) {
443 row = border_size + i;
444 col = border_size + j;
446 sum = (output_buf[row *
w + col]) >> 1;
447 sum += (output_buf[(row + 1) *
w + col] + output_buf[(row - 1) *
w + col]) >> 2;
449 output_buf[i * output->
w + j] = sum;
472 for (
uint8_t i = 1; i != pyr_level + 1; i++) {
500 uint32_t subpixel_w = (input->
w - 2) * subpixel_factor;
501 uint32_t subpixel_h = (input->
h - 2) * subpixel_factor;
504 for (
uint16_t i = 0; i < output->
w; i++) {
505 for (
uint16_t j = 0; j < output->
h; j++) {
507 uint32_t x = center->
x + border_size * subpixel_factor + (i - half_window) * subpixel_factor;
508 uint32_t y = center->
y + border_size * subpixel_factor + (j - half_window) * subpixel_factor;
510 BoundUpper(x, subpixel_w);
511 BoundUpper(y, subpixel_h);
514 uint16_t orig_x = x / subpixel_factor;
515 uint16_t orig_y = y / subpixel_factor;
518 uint32_t tl_x = orig_x * subpixel_factor;
519 uint32_t tl_y = orig_y * subpixel_factor;
522 if (tl_x == x && tl_y == y) {
523 output_buf[output->
w * j + i] = input_buf[input->
w * orig_y + orig_x];
530 uint32_t blend = (subpixel_factor - alpha_x) * (subpixel_factor - alpha_y) * input_buf[input->
w * orig_y + orig_x];
531 blend += alpha_x * (subpixel_factor - alpha_y) * input_buf[input->
w * orig_y + (orig_x + 1)];
532 blend += (subpixel_factor - alpha_x) * alpha_y * input_buf[input->
w * (orig_y + 1) + orig_x];
533 blend += alpha_x * alpha_y * input_buf[input->
w * (orig_y + 1) + (orig_x + 1)];
536 output_buf[output->
w * j + i] = blend / (subpixel_factor * subpixel_factor);
557 for (
uint16_t x = 1; x < input->
w - 1; x++) {
558 for (
uint16_t y = 1; y < input->
h - 1; y++) {
559 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];
560 dy_buf[(y - 1)*dy->
w + (x - 1)] = (
int16_t)input_buf[(y + 1) * input->
w + x] - (
int16_t)
561 input_buf[(y - 1) * input->
w + x];
575 int32_t sum_dxx = 0, sum_dxy = 0, sum_dyy = 0;
584 sum_dxx += ((
int32_t)dx_buf[y * dx->
w + x] * dx_buf[y * dx->
w + x]);
585 sum_dxy += ((
int32_t)dx_buf[y * dx->
w + x] * dy_buf[y * dy->
w + x]);
586 sum_dyy += ((
int32_t)dy_buf[y * dy->
w + x] * dy_buf[y * dy->
w + x]);
591 g[0] = sum_dxx / 255;
592 g[1] = sum_dxy / 255;
594 g[3] = sum_dyy / 255;
620 for (
uint16_t x = 0; x < img_b->
w; x++) {
621 for (
uint16_t y = 0; y < img_b->
h; y++) {
622 int16_t diff_c = img_a_buf[(y + 1) * img_a->
w + (x + 1)] - img_b_buf[y * img_b->
w + x];
623 sum_diff2 += diff_c * diff_c;
626 if (diff_buf != NULL) {
627 diff_buf[y * diff->
w + x] = diff_c;
656 for (
uint16_t x = 0; x < img_a->
w; x++) {
657 for (
uint16_t y = 0; y < img_a->
h; y++) {
658 int32_t mult_c = img_a_buf[y * img_a->
w + x] * img_b_buf[y * img_b->
w + x];
662 if (mult_buf != NULL) {
663 mult_buf[y * mult->
w + x] = mult_c;
707 int size_crosshair = 5;
710 for (
int i = 0; i < points_cnt; i++) {
712 uint32_t idx = pixel_width * points[i].
y * img->
w + points[i].
x * pixel_width;
728 static uint8_t color[4] = {255, 255, 255, 255};
729 static uint8_t bad_color[4] = {0, 0, 0, 0};
746 static int size_crosshair = 5;
749 for (
uint16_t i = 0; i < points_cnt; i++) {
752 .
x = vectors[i].
pos.
x / subpixel_factor,
753 .y = vectors[i].
pos.
y / subpixel_factor
756 .
x = (
uint32_t)roundf(((
float)vectors[i].pos.x + vectors[i].
flow_x) / subpixel_factor),
757 .
y = (
uint32_t)roundf(((
float)vectors[i].pos.y + vectors[i].
flow_y) / subpixel_factor)
781 int gradient_x, gradient_y, index;
788 uint8_t add_ind = pixel_width - 1;
791 if (loc->
x >= 1 && (loc->
x + 1) < img->
w && loc->
y >= 1 && (loc->
y + 1) < img->
h) {
799 index = loc->
y * img->
w * pixel_width + (loc->
x - 1) * pixel_width;
800 gradient_x -= (int) img_buf[index + add_ind];
801 index = loc->
y * img->
w * pixel_width + (loc->
x + 1) * pixel_width;
802 gradient_x += (int) img_buf[index + add_ind];
804 index = (loc->
y - 1) * img->
w * pixel_width + loc->
x * pixel_width;
805 gradient_y -= (
int) img_buf[index + add_ind];
806 index = (loc->
y + 1) * img->
w * pixel_width + loc->
x * pixel_width;
807 gradient_y += (
int) img_buf[index + add_ind];
813 static int Sobel[9] = { -1, 0, 1, -2, 0, 2, -1, 0, 1};
814 static int total_sobel = 8;
818 for (
int x = -1;
x <= 1;
x++) {
819 for (
int y = -1;
y <= 1;
y++) {
820 index = (loc->
y +
y) * img->
w * pixel_width + (loc->
x +
x) * pixel_width;
822 filt_ind_x = (
x + 1) % 3 + (
y + 1) * 3;
823 gradient_x += Sobel[filt_ind_x] * (int) img_buf[index + add_ind];
826 gradient_y += Sobel[filt_ind_y] * (int) img_buf[index + add_ind];
831 gradient_x /= total_sobel;
895 if (loc->
x >= size_crosshair && loc->
x < img->
w - size_crosshair
896 && loc->
y >= size_crosshair && loc->
y < img->
h - size_crosshair) {
898 from.
x = loc->
x - size_crosshair;
900 to.
x = loc->
x + size_crosshair;
904 from.
y = loc->
y - size_crosshair;
906 to.
y = loc->
y + size_crosshair;
919 static uint8_t color[4] = {255, 255, 255, 255};
934 int xerr = 0, yerr = 0;
940 uint8_t temp_color[4] = {color[0], color[1], color[2], color[3]};
951 if (delta_x > 0) { incx = 1; }
952 else if (delta_x == 0) { incx = 0; }
955 if (delta_y > 0) { incy = 1; }
956 else if (delta_y == 0) { incy = 0; }
961 delta_x = abs(delta_x);
962 delta_y = abs(delta_y);
963 if (delta_x > delta_y) { distance = delta_x * 20; }
964 else { distance = delta_y * 20; }
967 for (
uint16_t t = 0; starty < img->
h && startx < img->
w
968 && t <= distance + 1; t++) {
971 if (startx % 2 == 1) {
972 temp_color[0] = color[2];
973 temp_color[2] = color[0];
975 temp_color[0] = color[0];
976 temp_color[2] = color[2];
978 uint32_t buf_loc = img->
w * pixel_width * starty + startx * pixel_width;
979 img_buf[buf_loc] = temp_color[0];
982 img_buf[buf_loc + 1] = temp_color[1];
984 if (startx + 1 < img->
w) {
985 img_buf[buf_loc + 2] = temp_color[2];
986 img_buf[buf_loc + 3] = temp_color[3];
992 if (xerr > distance) {
996 if (yerr > distance) {
1019 value = *(source -
offset - width) * kernel[0] + *(source - width) * kernel[1] + *(source +
offset - width) * kernel[2] +
1020 *(source -
offset) * kernel[3] + *source * kernel[4] + *(source +
offset) * kernel[5] +
1021 *(source -
offset + width) * kernel[6] + *(source + width) * kernel[7] + *(source +
offset + width) * kernel[8];
1024 value = *(source -
offset) * kernel[3] + *source * kernel[4] + *(source +
offset) * kernel[5] +
1025 *(source -
offset + width) * kernel[6] + *(source + width) * kernel[7] + *(source +
offset + width) * kernel[8];
1028 value = *(source -
offset - width) * kernel[0] + *(source - width) * kernel[1] + *(source +
offset - width) * kernel[2] +
1029 *(source -
offset) * kernel[3] + *source * kernel[4] + *(source +
offset) * kernel[5];
1032 value = *(source - width) * kernel[1] + *(source +
offset - width) * kernel[2] +
1033 *source * kernel[4] + *(source +
offset) * kernel[5] +
1034 *(source + width) * kernel[7] + *(source +
offset + width) * kernel[8];
1037 value = *(source -
offset - width) * kernel[0] + *(source - width) * kernel[1] +
1038 *(source -
offset) * kernel[3] + *source * kernel[4] +
1039 *(source -
offset + width) * kernel[6] + *(source + width) * kernel[7];
1042 value = *source * kernel[4] + *(source +
offset) * kernel[5] +
1043 *(source + width) * kernel[7] + *(source +
offset + width) * kernel[8];
1046 value = *(source -
offset) * kernel[3] + *source * kernel[4] +
1047 *(source -
offset + width) * kernel[6] + *(source + width) * kernel[7];
1050 value = *(source - width) * kernel[1] + *(source +
offset - width) * kernel[2] +
1051 *source * kernel[4] + *(source +
offset) * kernel[5];
1054 value = *(source -
offset - width) * kernel[0] + *(source - width) * kernel[1] +
1055 *(source -
offset) * kernel[3] + *source * kernel[4];
1059 return (
uint8_t) ((int) abs(value) / total);
1074 output->
ts = input->
ts;
1078 int height = output->
h;
1079 int width = output->
w;
1092 for (
int x = 1;
x < width - 1;
x++) {
1103 for (
int y = 1;
y < height - 1;
y++) {
1110 for (
int x = 1;
x < width - 1;
x++) {
1128 for (
int x = 1;
x < width - 1;
x++) {
1143 for (
int x = 1;
x < width - 1;
x++) {
1152 for (
int y = 1;
y < height - 1;
y++) {
1158 for (
int x = 1;
x < width - 1;
x++) {
1173 for (
int x = 1;
x < width - 1;
x++) {
static const float offset[]
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 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.
uint8_t ker_mul_3x3(uint8_t const *source, int_fast8_t const *kernel, uint8_t total, uint8_t setting, int width, int YUV)
Kernel multiplication for a 3 x 3 kernel.
void image_convolution_3x3(struct image_t *input, struct image_t *output, int_fast8_t const *kernel, uint8_t kernel_total)
Image convolution for a 3x3 kernel.
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_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_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 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.
void image_draw_line(struct image_t *img, struct point_t *from, struct point_t *to)
Draw a pink line on the image.
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.
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...
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.
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_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 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 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.
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_to_grayscale(struct image_t *input, struct image_t *output)
Convert an image to grayscale.
void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint8_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_show_flow(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor)
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_free(struct image_t *img)
Free the image.
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.
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type)
Create a new image.
#define CACHE_LINE_LENGTH
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.
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.
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...
Image helper functions like resizing, color filter, converters...
struct timeval ts
The timestamp of creation.
uint32_t buf_size
The buffer size.
void * buf
Image buffer (depending on the image_type)
uint32_t x
The x coordinate of the point.
uint32_t pprz_ts
The timestamp in us since system startup.
uint32_t y
The y coordinate of the point.
enum image_type type
The image type.
struct point_t pos
The original position the flow comes from in subpixels.
struct FloatEulers eulers
Euler Angles at time of image.
int32_t flow_y
The y direction flow in subpixels.
int32_t flow_x
The x direction flow in subpixels.
@ IMAGE_GRAYSCALE
Grayscale image with only the Y part (uint8 per pixel)
@ IMAGE_YUV422
UYVY format (uint16 per pixel)
@ IMAGE_GRADIENT
An image gradient (int16 per pixel)
@ IMAGE_INT16
An image to hold disparity image data from openCV (int16 per pixel)
@ IMAGE_JPEG
An JPEG encoded image (not per pixel encoded)
efficient fixed-point optical-flow calculation
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
signed char int8_t
Typedef defining 8 bit char type.