Merged with master

This commit is contained in:
hrvoje
2016-03-29 21:07:18 +02:00
parent 0b13661a13
commit 3aaefbc4de
6 changed files with 296 additions and 131 deletions
@@ -235,6 +235,108 @@ void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint
}
}
/**
* This function adds padding to input image by mirroring the edge image elements.
* @param[in] *input - input image (grayscale only)
* @param[out] *output - the output image
* @param[in] border_size - amount of padding around image. Padding is made by reflecting image elements at the edge
* Example: f e d c b a | a b c d e f | f e d c b a
*/
void image_add_border(struct image_t *input, struct image_t *output, uint8_t border_size)
{
image_create(output, input->w + 2 * border_size, input->h + 2 * border_size, input->type);
uint8_t *input_buf = (uint8_t *)input->buf;
uint8_t *output_buf = (uint8_t *)output->buf;
// Skip first `border_size` rows, iterate through next input->h rows
for (uint16_t i = border_size; i != (output->h - border_size); i++){
// Mirror first `border_size` columns
for (uint8_t j = 0; j != border_size; j++)
output_buf[i * output->w + (border_size - 1 - j)] = input_buf[(i - border_size) * input->w + j];
// Copy corresponding row values from input image
memcpy(&output_buf[i * output->w + border_size], &input_buf[(i - border_size) * input->w], sizeof(uint8_t) * input->w);
// Mirror last `border_size` columns
for (uint8_t j = 0; j != border_size; j++)
output_buf[i * output->w + output->w - border_size + j] = output_buf[i * output->w + output->w - border_size -1 - j];
}
// Mirror first `border_size` and last `border_size` rows
for (uint8_t i = 0; i != border_size; i++){
memcpy(&output_buf[(border_size - 1) * output->w - i * output->w], &output_buf[border_size * output->w + i * output->w], sizeof(uint8_t) * output->w);
memcpy(&output_buf[(output->h - border_size) * output->w + i * output->w], &output_buf[(output->h - border_size - 1) * output->w - i * output->w], sizeof(uint8_t) * output->w);
}
}
/**
* This function takes previous padded pyramid level and outputs next level of pyramid without padding.
* For calculating new pixel value 5x5 filter matrix suggested by Bouguet is used in decimal number form:
* [1/16 1/8 3/4 1/8 1/16]' x [1/16 1/8 3/4 1/8 1/16]
*
* @param[in] *input - input image (grayscale only)
* @param[out] *output - the output image
* @param[in] border_size - amount of padding around image. Padding is made by reflecting image elements at the edge
* Example: f e d c b a | a b c d e f | f e d c b a
*/
void pyramid_next_level(struct image_t *input, struct image_t *output, uint8_t border_size)
{
// Create output image, new image size is half the size of input image without padding (border)
image_create(output, (input->w + 1 - 2 * border_size) / 2, (input->h + 1 - 2 * border_size ) / 2, input->type);
uint8_t *input_buf = (uint8_t *)input->buf;
uint8_t *output_buf = (uint8_t *)output->buf;
uint16_t row, col; // coordinates of the central pixel; pixel being calculated in input matrix; center of filer matrix
uint16_t w = input->w;
int32_t sum = 0;
for (uint16_t i = 0; i != output->h; i++){
for (uint16_t j = 0; j != output->w; j++){
row = border_size + 2 * i; // First skip border, then every second pixel
col = border_size + 2 * j;
sum = 39 * ( input_buf[(row -2)*w + (col -2)] + input_buf[(row -2)*w + (col +2)] + input_buf[(row +2)*w + (col -2)] + input_buf[(row +2)*w + (col +2)]);
sum += 156 * ( input_buf[(row -2)*w + (col -1)] + input_buf[(row -2)*w + (col +1)] + input_buf[(row -1)*w + (col +2)] + input_buf[(row +1)*w + (col -2)]
+ input_buf[(row +1)*w + (col +2)] + input_buf[(row +2)*w + (col -1)] + input_buf[(row +2)*w + (col +1)] + input_buf[(row -1)*w + (col -2)]);
sum += 234 * ( input_buf[(row -2)*w + (col)] + input_buf[(row)*w + (col -2)] + input_buf[(row)*w + (col +2)] + input_buf[(row +2)*w + (col)]);
sum += 625 * ( input_buf[(row -1)*w + (col -1)] + input_buf[(row -1)*w + (col +1)] + input_buf[(row +1)*w + (col -1)] + input_buf[(row +1)*w + (col +1)]);
sum += 938 * ( input_buf[(row -1)*w + (col)] + input_buf[(row)*w + (col -1)] + input_buf[(row)*w + (col +1)] + input_buf[(row +1)*w + (col)]);
sum += 1406 * input_buf[(row)*w + (col)];
output_buf[i*output->w + j] = sum / 10000;
}
}
}
/**
* This function populates given array of image_t structs with wanted number of padded pyramids based on given input.
* @param[in] *input - input image (grayscale only)
* @param[out] *output - array of image_t structs containing image pyiramid levels. Level zero contains original image,
* followed by `pyr_level` of pyramid.
* @param[in] pyr_level - number of pyramids to be built. If 0, original image is padded and outputed.
* @param[in] border_size - amount of padding around image. Padding is made by reflecting image elements at the edge
* Example: f e d c b a | a b c d e f | f e d c b a
*/
void pyramid_build(struct image_t *input, struct image_t *output_array, uint8_t pyr_level, uint8_t border_size)
{
// Pad input image and save it as '0' pyramid level
image_add_border(input, &output_array[0], border_size);
// Temporary holds 'i' level version of original image to be padded and saved as 'i' pyramid level
struct image_t temp;
for (uint8_t i = 1; i != pyr_level + 1; i++){
pyramid_next_level(&output_array[i-1], &temp, border_size);
image_add_border(&temp, &output_array[i], border_size);
image_free(&temp);
}
}
/**
* This outputs a subpixel window image in grayscale
* Currently only works with Grayscale images as input but could be upgraded to
@@ -243,41 +345,45 @@ void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint
* @param[out] *output Window output (width and height is used to calculate the window size)
* @param[in] *center Center point in subpixel coordinates
* @param[in] subpixel_factor The subpixel factor per pixel
* @param[in] border_size - amount of padding around image. Padding is made by reflecting image elements at the edge
* Example: f e d c b a | a b c d e f | f e d c b a
*/
void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center, uint16_t subpixel_factor)
void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center, uint32_t subpixel_factor, uint8_t border_size)
{
uint8_t *input_buf = (uint8_t *)input->buf;
uint8_t *output_buf = (uint8_t *)output->buf;
// Calculate the window size
uint16_t half_window = output->w / 2;
uint16_t subpixel_w = input->w * subpixel_factor;
uint16_t subpixel_h = input->h * subpixel_factor;
uint32_t subpixel_w = input->w * subpixel_factor;
uint32_t subpixel_h = input->h * subpixel_factor;
// Go through the whole window size in normal coordinates
for (uint16_t i = 0; i < output->w; i++) {
for (uint16_t j = 0; j < output->h; j++) {
// Calculate the subpixel coordinate
uint16_t x = center->x + (i - half_window) * subpixel_factor;
uint16_t y = center->y + (j - half_window) * subpixel_factor;
BoundUpper(x, subpixel_w);
BoundUpper(y, subpixel_h);
uint32_t x = center->x + border_size * subpixel_factor + (i - half_window) * subpixel_factor ;
uint32_t y = center->y + border_size * subpixel_factor + (j - half_window) * subpixel_factor ;
BoundUpper(x, subpixel_w - 1);
BoundUpper(y, subpixel_h - 1);
// Calculate the original pixel coordinate
uint16_t orig_x = x / subpixel_factor;
uint16_t orig_y = y / subpixel_factor;
// Calculate top left (in subpixel coordinates)
uint16_t tl_x = orig_x * subpixel_factor;
uint16_t tl_y = orig_y * subpixel_factor;
uint32_t tl_x = orig_x * subpixel_factor;
uint32_t tl_y = orig_y * subpixel_factor;
// Check if it is the top left pixel
if (tl_x == x && tl_y == y) {
output_buf[output->w * j + i] = input_buf[input->w * orig_y + orig_x];
} else {
// Calculate the difference from the top left
uint16_t alpha_x = (x - tl_x);
uint16_t alpha_y = (y - tl_y);
uint32_t alpha_x = (x - tl_x);
uint32_t alpha_y = (y - tl_y);
// Blend from the 4 surrounding pixels
uint32_t blend = (subpixel_factor - alpha_x) * (subpixel_factor - alpha_y) * input_buf[input->w * orig_y + orig_x];
@@ -339,7 +445,7 @@ void image_calculate_g(struct image_t *dx, struct image_t *dy, int32_t *g)
}
}
// ouput the G vector
// output the G vector
g[0] = sum_dxx / 255;
g[1] = sum_dxy / 255;
g[2] = g[1];
@@ -407,7 +513,7 @@ int32_t image_multiply(struct image_t *img_a, struct image_t *img_b, struct imag
// Calculate the multiplication
for (uint16_t x = 0; x < img_a->w; x++) {
for (uint16_t y = 0; y < img_a->h; y++) {
int16_t mult_c = img_a_buf[y * img_a->w + x] * img_b_buf[y * img_b->w + x];
int32_t mult_c = img_a_buf[y * img_a->w + x] * img_b_buf[y * img_b->w + x];
sum += mult_c;
// Set the difference image
@@ -52,8 +52,8 @@ struct image_t {
/* Image point structure */
struct point_t {
uint16_t x; ///< The x coordinate of the point
uint16_t y; ///< The y coordinate of the point
uint32_t x; ///< The x coordinate of the point // CHANGED 16 -> 32
uint32_t y; ///< The y coordinate of the point // CHANGED 16 -> 32
};
/* Vector structure for point differences */
@@ -64,6 +64,7 @@ struct flow_t {
};
/* Usefull image functions */
void image_add_border(struct image_t *input, struct image_t *output, uint8_t border_size);
void image_create(struct image_t *img, uint16_t width, uint16_t height, enum image_type type);
void image_free(struct image_t *img);
void image_copy(struct image_t *input, struct image_t *output);
@@ -71,7 +72,7 @@ void image_switch(struct image_t *a, struct image_t *b);
void image_to_grayscale(struct image_t *input, struct image_t *output);
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);
void image_yuv422_downsample(struct image_t *input, struct image_t *output, uint16_t downsample);
void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center, uint16_t subpixel_factor);
void image_subpixel_window(struct image_t *input, struct image_t *output, struct point_t *center, uint32_t subpixel_factor, uint8_t border_size);
void image_gradients(struct image_t *input, struct image_t *dx, struct image_t *dy);
void image_calculate_g(struct image_t *dx, struct image_t *dy, int32_t *g);
uint32_t image_difference(struct image_t *img_a, struct image_t *img_b, struct image_t *diff);
@@ -79,5 +80,7 @@ int32_t image_multiply(struct image_t *img_a, struct image_t *img_b, struct imag
void image_show_points(struct image_t *img, struct point_t *points, uint16_t points_cnt);
void image_show_flow(struct image_t *img, struct flow_t *vectors, uint16_t points_cnt, uint8_t subpixel_factor);
void image_draw_line(struct image_t *img, struct point_t *from, struct point_t *to);
void pyramid_next_level(struct image_t *input, struct image_t *output, uint8_t border_size);
void pyramid_build(struct image_t *input, struct image_t *output_array, uint8_t pyr_level, uint8_t border_size);
#endif
@@ -1,6 +1,14 @@
/*
* lucas_kanade.c
*
* Created on: Jan 11, 2016
* Author: hrvoje
*/
/*
* Copyright (C) 2014 G. de Croon
* 2015 Freek van Tienen <freek.v.tienen@gmail.com>
* 2016 Hrvoje Brezak <hrvoje.brezak@gmail.com>
*
* This file is part of Paparazzi.
*
@@ -37,7 +45,7 @@
/**
* Compute the optical flow of several points using the Lucas-Kanade algorithm by Yves Bouguet
* The initial fixed-point implementation is doen by G. de Croon and is adapted by
* The initial fixed-point implementation is done by G. de Croon and is adapted by
* Freek van Tienen for the implementation in Paparazzi.
* @param[in] *new_img The newest grayscale image (TODO: fix YUV422 support)
* @param[in] *old_img The old grayscale image (TODO: fix YUV422 support)
@@ -48,11 +56,14 @@
* @param[in] max_iterations Maximum amount of iterations to find the new point
* @param[in] step_threshold The threshold at which the iterations should stop
* @param[in] max_points The maximum amount of points to track, we skip x points and then take a point.
* @param[in] pyramid_level Level of pyramid used in computation (0 == no pyramids used)
* @return The vectors from the original *points in subpixels
*/
struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, struct point_t *points, uint16_t *points_cnt,
uint16_t half_window_size, uint16_t subpixel_factor, uint8_t max_iterations, uint8_t step_threshold, uint16_t max_points) {
// A straightforward one-level implementation of Lucas-Kanade.
struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, struct point_t *points, uint16_t *points_cnt, uint16_t half_window_size,
uint16_t subpixel_factor, uint8_t max_iterations, uint8_t step_threshold, uint8_t max_points, uint8_t pyramid_level) {
// Pyramidal implementation of Lucas-Kanade feature tracker.
// For all points:
// (1) determine the subpixel neighborhood in the old image
// (2) get the x- and y- gradients
@@ -65,14 +76,21 @@ struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, str
// Allocate some memory for returning the vectors
struct flow_t *vectors = malloc(sizeof(struct flow_t) * max_points);
uint16_t new_p = 0;
uint16_t points_orig = *points_cnt;
*points_cnt = 0;
// determine patch sizes and initialize neighborhoods
uint16_t patch_size = 2 * half_window_size;
uint32_t error_threshold = (25 * 25) *(patch_size *patch_size);
// Determine patch sizes and initialize neighborhoods
uint16_t patch_size = 2 * half_window_size + 1;
uint32_t error_threshold = (25 * 25) * (patch_size * patch_size);
uint16_t padded_patch_size = patch_size + 2;
uint8_t border_size = padded_patch_size / 2 + 2;
step_threshold = step_threshold*(subpixel_factor/100);
// Allocate memory for image pyramids
struct image_t *pyramid_old = malloc(sizeof(struct image_t) * (pyramid_level+1));
struct image_t *pyramid_new = malloc(sizeof(struct image_t) * (pyramid_level+1));
// Build pyramid levels
pyramid_build(old_img, pyramid_old, pyramid_level, border_size);
pyramid_build(new_img, pyramid_new, pyramid_level, border_size);
// Create the window images
struct image_t window_I, window_J, window_DX, window_DY, window_diff;
@@ -82,27 +100,48 @@ struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, str
image_create(&window_DY, patch_size, patch_size, IMAGE_GRADIENT);
image_create(&window_diff, patch_size, patch_size, IMAGE_GRADIENT);
// Calculate the amount of points to skip
float skip_points = (points_orig > max_points) ? points_orig / max_points : 1;
// Iterate through pyramid levels
for (int8_t LVL = pyramid_level; LVL != -1; LVL--) {
uint16_t points_orig = *points_cnt;
*points_cnt = 0;
uint16_t new_p = 0;
// Go trough all points
for (uint16_t i = 0; i < max_points && i < points_orig; i++) {
// Calculate the amount of points to skip - disabled until needed
float skip_points = (points_orig > max_points) ? (float)points_orig / max_points : 1;
// Go through all points
for (uint16_t i = 0; i < max_points && i < points_orig; i++)
{
uint16_t p = i * skip_points;
// If the pixel is outside ROI, do not track it
if (points[p].x < half_window_size || (old_img->w - points[p].x) < half_window_size
|| points[p].y < half_window_size || (old_img->h - points[p].y) < half_window_size) {
continue;
}
// Convert the point to a subpixel coordinate
vectors[new_p].pos.x = points[p].x * subpixel_factor;
vectors[new_p].pos.y = points[p].y * subpixel_factor;
if (LVL == pyramid_level)
{
// Convert the point to a subpixel coordinate on the top pyramid level
vectors[new_p].pos.x = (points[p].x * subpixel_factor) >> pyramid_level;
vectors[new_p].pos.y = (points[p].y * subpixel_factor) >> pyramid_level;
vectors[new_p].flow_x = 0;
vectors[new_p].flow_y = 0;
} else {
// Convert last pyramid level flow into this pyramid level flow guess
vectors[new_p].pos.x = vectors[p].pos.x << 1;
vectors[new_p].pos.y = vectors[p].pos.y << 1;
vectors[new_p].flow_x = vectors[p].flow_x << 1;
vectors[new_p].flow_y = vectors[p].flow_y << 1;
}
// If the pixel is outside ROI, do not track it
if ((((int32_t) vectors[new_p].pos.x + vectors[new_p].flow_x) < 0)
|| ((vectors[new_p].pos.x + vectors[new_p].flow_x) > ((pyramid_new[LVL].w - 1 - 2 * border_size)* subpixel_factor))
|| (((int32_t) vectors[new_p].pos.y + vectors[new_p].flow_y) < 0)
|| ((vectors[new_p].pos.y + vectors[new_p].flow_y) > ((pyramid_new[LVL].h - 1 - 2 * border_size)* subpixel_factor)))
{
continue;
}
// (1) determine the subpixel neighborhood in the old image
image_subpixel_window(old_img, &window_I, &vectors[new_p].pos, subpixel_factor);
image_subpixel_window(&pyramid_old[LVL], &window_I, &vectors[new_p].pos, subpixel_factor, border_size);
// (2) get the x- and y- gradients
image_gradients(&window_I, &window_DX, &window_DY);
@@ -112,37 +151,38 @@ struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, str
image_calculate_g(&window_DX, &window_DY, G);
// calculate G's determinant in subpixel units:
int32_t Det = (G[0] * G[3] - G[1] * G[2]) / subpixel_factor;
int32_t Det = ( G[0] * G[3] - G[1] * G[2]);
// Check if the determinant is bigger than 1
if (Det < 1) {
continue;
}
// a * (Ax - Bx) + (1-a) * (Ax+1 - Bx+1)
// a * Ax - a * Bx + (1-a) * Ax+1 - (1-a) * Bx+1
// (a * Ax + (1-a) * Ax+1) - (a * Bx + (1-a) * Bx+1)
// (4) iterate over taking steps in the image to minimize the error:
bool_t tracked = TRUE;
for (uint8_t it = 0; it < max_iterations; it++) {
struct point_t new_point = {
vectors[new_p].pos.x + vectors[new_p].flow_x,
vectors[new_p].pos.y + vectors[new_p].flow_y
};
for (uint8_t it = max_iterations; it--; ) {
struct point_t new_point = { vectors[new_p].pos.x + vectors[new_p].flow_x,
vectors[new_p].pos.y + vectors[new_p].flow_y };
// If the pixel is outside ROI, do not track it
if (new_point.x / subpixel_factor < half_window_size || (old_img->w - new_point.x / subpixel_factor) < half_window_size
|| new_point.y / subpixel_factor < half_window_size || (old_img->h - new_point.y / subpixel_factor) < half_window_size) {
if ( (( (int32_t)vectors[new_p].pos.x + vectors[new_p].flow_x) < 0)
|| ( new_point.x > ((pyramid_new[LVL].w - 1 - 2*border_size)*subpixel_factor))
|| (((int32_t)vectors[new_p].pos.y + vectors[new_p].flow_y) < 0)
|| ( new_point.y > ((pyramid_new[LVL].h - 1 - 2*border_size)*subpixel_factor)) )
{
tracked = FALSE;
break;
}
// [a] get the subpixel neighborhood in the new image
image_subpixel_window(new_img, &window_J, &new_point, subpixel_factor);
image_subpixel_window(&pyramid_new[LVL], &window_J, &new_point, subpixel_factor, border_size);
// [b] determine the image difference between the two neighborhoods
uint32_t error = image_difference(&window_I, &window_J, &window_diff);
if (error > error_threshold && it > max_iterations / 2) {
if (error > error_threshold && it < max_iterations / 2) {
tracked = FALSE;
break;
}
@@ -150,24 +190,28 @@ struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, str
int32_t b_x = image_multiply(&window_diff, &window_DX, NULL) / 255;
int32_t b_y = image_multiply(&window_diff, &window_DY, NULL) / 255;
// [d] calculate the additional flow step and possibly terminate the iteration
int16_t step_x = (G[3] * b_x - G[1] * b_y) / Det;
int16_t step_y = (G[0] * b_y - G[2] * b_x) / Det;
vectors[new_p].flow_x += step_x;
vectors[new_p].flow_y += step_y;
// Check if we exceeded the treshold
// [d] calculate the additional flow step and possibly terminate the iteration
int16_t step_x = (( (int64_t) G[3] * b_x - G[1] * b_y) * subpixel_factor) / Det;
int16_t step_y = (( (int64_t) G[0] * b_y - G[2] * b_x) * subpixel_factor) / Det;
vectors[new_p].flow_x = vectors[new_p].flow_x + step_x;
vectors[new_p].flow_y = vectors[new_p].flow_y + step_y;
// Check if we exceeded the treshold CHANGED made this better for 0.03
if ((abs(step_x) + abs(step_y)) < step_threshold) {
break;
}
}
} // lucas kanade step iteration
// If we tracked the point we update the index and the count
if (tracked) {
new_p++;
(*points_cnt)++;
}
}
} // go through all points
} // LVL of pyramid
// Free the images
image_free(&window_I);
@@ -176,6 +220,13 @@ struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, str
image_free(&window_DY);
image_free(&window_diff);
for (int8_t i = pyramid_level; i!= -1; i--){
image_free(&pyramid_old[i]);
image_free(&pyramid_new[i]);
}
pyramid_old = NULL;
pyramid_new = NULL;
// Return the vectors
return vectors;
}
@@ -34,7 +34,7 @@
#include "std.h"
#include "image.h"
struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, struct point_t *points, uint16_t *points_cnt,
uint16_t half_window_size, uint16_t subpixel_factor, uint8_t max_iterations, uint8_t step_threshold, uint16_t max_points);
struct flow_t *opticFlowLK(struct image_t *new_img, struct image_t *old_img, struct point_t *points, uint16_t *points_cnt, uint16_t half_window_size,
uint16_t subpixel_factor, uint8_t max_iterations, uint8_t step_threshold, uint8_t max_points, uint8_t pyramid_level);
#endif /* OPTIC_FLOW_INT_H */
@@ -110,7 +110,7 @@ PRINT_CONFIG_VAR(OPTICFLOW_THRESHOLD_VEC)
PRINT_CONFIG_VAR(OPTICFLOW_FAST9_ADAPTIVE)
#ifndef OPTICFLOW_FAST9_THRESHOLD
#define OPTICFLOW_FAST9_THRESHOLD 20
#define OPTICFLOW_FAST9_THRESHOLD 10
#endif
PRINT_CONFIG_VAR(OPTICFLOW_FAST9_THRESHOLD)
@@ -206,7 +206,7 @@ void calc_fast9_lukas_kanade(struct opticflow_t *opticflow, struct opticflow_sta
// FAST corner detection (TODO: non fixed threshold)
struct point_t *corners = fast9_detect(img, opticflow->fast9_threshold, opticflow->fast9_min_distance,
20, 20, &result->corner_cnt);
0, 0, &result->corner_cnt);
// Adaptive threshold
if (opticflow->fast9_adaptive) {
@@ -238,7 +238,8 @@ void calc_fast9_lukas_kanade(struct opticflow_t *opticflow, struct opticflow_sta
result->tracked_cnt = result->corner_cnt;
struct flow_t *vectors = opticFlowLK(&opticflow->img_gray, &opticflow->prev_img_gray, corners, &result->tracked_cnt,
opticflow->window_size / 2, opticflow->subpixel_factor, opticflow->max_iterations,
opticflow->threshold_vec, opticflow->max_track_corners);
opticflow->threshold_vec, opticflow->max_track_corners, 3);
#if OPTICFLOW_DEBUG && OPTICFLOW_SHOW_FLOW
image_show_flow(img, vectors, result->tracked_cnt, opticflow->subpixel_factor);
@@ -299,6 +300,10 @@ void calc_fast9_lukas_kanade(struct opticflow_t *opticflow, struct opticflow_sta
float diff_flow_x = 0;
float diff_flow_y = 0;
// Flow Derotation TODO:
float diff_flow_x = (state->phi - opticflow->prev_phi) * img->w / OPTICFLOW_FOV_W;
float diff_flow_y = (state->theta - opticflow->prev_theta) * img->h / OPTICFLOW_FOV_H;
if (opticflow->derotation) {
diff_flow_x = (state->phi - opticflow->prev_phi) * img->w / OPTICFLOW_FOV_W;
diff_flow_y = (state->theta - opticflow->prev_theta) * img->h / OPTICFLOW_FOV_H;
@@ -48,7 +48,7 @@ struct opticflow_t {
uint16_t search_distance; ///< Search distance for blockmatching alg.
uint8_t derotation; ///< Derotation switched on or off (depended on the quality of the gyroscope measurement)
uint8_t subpixel_factor; ///< The amount of subpixels per pixel
uint16_t subpixel_factor; ///< The amount of subpixels per pixel
uint8_t max_iterations; ///< The maximum amount of iterations the Lucas Kanade algorithm should do
uint8_t threshold_vec; ///< The threshold in x, y subpixels which the algorithm should stop
@@ -61,8 +61,8 @@ struct opticflow_t {
void opticflow_calc_init(struct opticflow_t *opticflow, uint16_t w, uint16_t h);
void opticflow_calc_frame(struct opticflow_t *opticflow, struct opticflow_state_t *state, struct image_t *img,
struct opticflow_result_t *result);
void opticflow_calc_frame(struct opticflow_t *opticflow, struct opticflow_state_t *state, struct image_t *img, struct opticflow_result_t *result);
void calc_fast9_lukas_kanade(struct opticflow_t *opticflow, struct opticflow_state_t *state, struct image_t *img,
struct opticflow_result_t *result);
void calc_edgeflow_tot(struct opticflow_t *opticflow, struct opticflow_state_t *state, struct image_t *img,