Реклама Google — средство выживания форумов :)
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdint.h>
#include <stdbool.h>
struct vector_2d
{
float x, y;
bool valid;
};
#define MATRIX_EDGE_LENGTH 16
#define MATRIX_CENTER ((MATRIX_EDGE_LENGTH - 1) / 2.0f)
// average brightness outside of these limits indicates a blind camera, if in paranoid mode
#define BLINDNESS_LOW_THRESHOLD 2
#define BLINDNESS_HIGH_THRESHOLD 200
bool halo_center(uint8_t pixels[], struct vector_2d *center, bool origin_at_matrix_center, bool paranoid)
{
struct {
int sums[2][MATRIX_EDGE_LENGTH]; // projected on x and y axes
int weighted[2];
} r;
int scale = 0;
memset(&r, 0, sizeof(r));
// project to axes
for (int i = 0; i < MATRIX_EDGE_LENGTH; i++)
{
for (int j = 0; j < MATRIX_EDGE_LENGTH; j++)
{
int pixel = pixels[i + j * MATRIX_EDGE_LENGTH];
r.sums[0][i] += pixel;
r.sums[1][j] += pixel;
scale += pixel;
}
}
for (int i = 0; i < 2; i++)
{
printf("\n%c ", i ? 'y' : 'x');
for (int j = 0; j < MATRIX_EDGE_LENGTH; j++)
{
r.weighted[i] += r.sums[i][j] * j;
printf("%3i ", r.sums[i][j]);
}
}
printf("\nWeighted x sum: %i, weighted y sum: %i, scale: %i\n ", r.weighted[0], r.weighted[1], scale);
int avg = scale / (MATRIX_EDGE_LENGTH * MATRIX_EDGE_LENGTH); // average brightness
if (paranoid && (avg < BLINDNESS_LOW_THRESHOLD || avg > BLINDNESS_HIGH_THRESHOLD))
{
// camera is probably blind, return default value and mark it as invalid
float default_offset = origin_at_matrix_center ? 0 : MATRIX_CENTER;
center->x = default_offset;
center->y = default_offset;
return center->valid = false;
}
float origin_offset = origin_at_matrix_center ? -MATRIX_CENTER : 0;
center->x = r.weighted[0] / (float)scale + origin_offset;
center->y = r.weighted[1] / (float)scale + origin_offset;
return center->valid = true;
}
// a simple test
void create_halo(uint8_t buf[], float center_x, float center_y, int halo_radius_sq)
{
printf("\n ");
for (int y = 0; y < MATRIX_EDGE_LENGTH; y++)
{
for (int x = 0; x < MATRIX_EDGE_LENGTH; x++)
{
float dx = x - center_x, dy = y - center_y;
float sdist_sq = halo_radius_sq - dx * dx - dy * dy;
if (sdist_sq < 0)
{
sdist_sq = 0;
}
else if (sdist_sq > 255)
{
sdist_sq = 255;
}
buf[x + y * MATRIX_EDGE_LENGTH] = sdist_sq;
printf("%2.0f ", sdist_sq);
}
printf("\n ");
}
}
void test_trial(float halo_x, float halo_y) {
uint8_t test[MATRIX_EDGE_LENGTH * MATRIX_EDGE_LENGTH] ;
int halo_radius_sq = MATRIX_EDGE_LENGTH * MATRIX_EDGE_LENGTH / 10;
printf("Testing a star halo detector (expected %f, %f)\n", halo_x, halo_y);
create_halo(test, halo_x, halo_y, halo_radius_sq);
struct vector_2d result;
halo_center(test, &result, false, false);
if (!result.valid)
{
printf("Uncertain data: %f, %f (camera is probably blind)\n", result.x, result.y);
} else {
printf("Found center at %f, %f\n", result.x, result.y);
}
printf("Offset is %f, %f\n------------------\n\n", result.x - halo_x, result.y - halo_y);
}
int main()
{
test_trial(8, 8);
test_trial(10, 11);
test_trial(10.1, 11.23);
test_trial(12, 12); // clipped by the camera's matrix edge
test_trial(14, 14); // nearly completely clipped by the camera's matrix edge
test_trial(15, 15); // almost completely clipped by the camera's matrix edge
return 0;
}