#include float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y); void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f); void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y); void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y); float cubicInterpolate(float p[], float x); float bicubicInterpolate(float p[], float x, float y); void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols, float *dest, uint8_t dest_rows, uint8_t dest_cols); float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y) { if (x < 0) x = 0; if (y < 0) y = 0; if (x >= cols) x = cols - 1; if (y >= rows) y = rows - 1; return p[y * cols + x]; } void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f) { if ((x < 0) || (x >= cols)) return; if ((y < 0) || (y >= rows)) return; p[y * cols + x] = f; } // src is a grid src_rows * src_cols // dest is a pre-allocated grid, dest_rows*dest_cols void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols, float *dest, uint8_t dest_rows, uint8_t dest_cols) { float mu_x = (src_cols - 1.0) / (dest_cols - 1.0); float mu_y = (src_rows - 1.0) / (dest_rows - 1.0); float adj_2d[16]; // matrix for storing adjacents for (uint8_t y_idx = 0; y_idx < dest_rows; y_idx++) { for (uint8_t x_idx = 0; x_idx < dest_cols; x_idx++) { float x = x_idx * mu_x; float y = y_idx * mu_y; // Serial.print("("); Serial.print(y_idx); Serial.print(", "); // Serial.print(x_idx); Serial.print(") = "); Serial.print("("); // Serial.print(y); Serial.print(", "); Serial.print(x); // Serial.print(") = "); get_adjacents_2d(src, adj_2d, src_rows, src_cols, x, y); /* Serial.print("["); for (uint8_t i=0; i<16; i++) { Serial.print(adj_2d[i]); Serial.print(", "); } Serial.println("]"); */ float frac_x = x - (int)x; // we only need the ~delta~ between the points float frac_y = y - (int)y; // we only need the ~delta~ between the points float out = bicubicInterpolate(adj_2d, frac_x, frac_y); // Serial.print("\tInterp: "); Serial.println(out); set_point(dest, dest_rows, dest_cols, x_idx, y_idx, out); } } } // p is a list of 4 points, 2 to the left, 2 to the right float cubicInterpolate(float p[], float x) { float r = p[1] + (0.5 * x * (p[2] - p[0] + x * (2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3] + x * (3.0 * (p[1] - p[2]) + p[3] - p[0])))); /* Serial.print("interpolating: ["); Serial.print(p[0],2); Serial.print(", "); Serial.print(p[1],2); Serial.print(", "); Serial.print(p[2],2); Serial.print(", "); Serial.print(p[3],2); Serial.print("] w/"); Serial.print(x); Serial.print(" = "); Serial.println(r); */ return r; } // p is a 16-point 4x4 array of the 2 rows & columns left/right/above/below float bicubicInterpolate(float p[], float x, float y) { float arr[4] = {0, 0, 0, 0}; arr[0] = cubicInterpolate(p + 0, x); arr[1] = cubicInterpolate(p + 4, x); arr[2] = cubicInterpolate(p + 8, x); arr[3] = cubicInterpolate(p + 12, x); return cubicInterpolate(arr, y); } // src is rows*cols and dest is a 4-point array passed in already allocated! void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y) { // Serial.print("("); Serial.print(x); Serial.print(", "); Serial.print(y); // Serial.println(")"); // pick two items to the left dest[0] = get_point(src, rows, cols, x - 1, y); dest[1] = get_point(src, rows, cols, x, y); // pick two items to the right dest[2] = get_point(src, rows, cols, x + 1, y); dest[3] = get_point(src, rows, cols, x + 2, y); } // src is rows*cols and dest is a 16-point array passed in already allocated! void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y) { // Serial.print("("); Serial.print(x); Serial.print(", "); Serial.print(y); // Serial.println(")"); float arr[4]; for (int8_t delta_y = -1; delta_y < 3; delta_y++) { // -1, 0, 1, 2 float *row = dest + 4 * (delta_y + 1); // index into each chunk of 4 for (int8_t delta_x = -1; delta_x < 3; delta_x++) { // -1, 0, 1, 2 row[delta_x + 1] = get_point(src, rows, cols, x + delta_x, y + delta_y); } } }