interpolation.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #include <Arduino.h>
  2. float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
  3. void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f);
  4. void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
  5. void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
  6. float cubicInterpolate(float p[], float x);
  7. float bicubicInterpolate(float p[], float x, float y);
  8. void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols,
  9. float *dest, uint8_t dest_rows, uint8_t dest_cols);
  10. float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y) {
  11. if (x < 0) x = 0;
  12. if (y < 0) y = 0;
  13. if (x >= cols) x = cols - 1;
  14. if (y >= rows) y = rows - 1;
  15. return p[y * cols + x];
  16. }
  17. void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f) {
  18. if ((x < 0) || (x >= cols)) return;
  19. if ((y < 0) || (y >= rows)) return;
  20. p[y * cols + x] = f;
  21. }
  22. // src is a grid src_rows * src_cols
  23. // dest is a pre-allocated grid, dest_rows*dest_cols
  24. void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols,
  25. float *dest, uint8_t dest_rows, uint8_t dest_cols) {
  26. float mu_x = (src_cols - 1.0) / (dest_cols - 1.0);
  27. float mu_y = (src_rows - 1.0) / (dest_rows - 1.0);
  28. float adj_2d[16]; // matrix for storing adjacents
  29. for (uint8_t y_idx=0; y_idx < dest_rows; y_idx++) {
  30. for (uint8_t x_idx=0; x_idx < dest_cols; x_idx++) {
  31. float x = x_idx * mu_x;
  32. float y = y_idx * mu_y;
  33. //Serial.print("("); Serial.print(y_idx); Serial.print(", "); Serial.print(x_idx); Serial.print(") = ");
  34. //Serial.print("("); Serial.print(y); Serial.print(", "); Serial.print(x); Serial.print(") = ");
  35. get_adjacents_2d(src, adj_2d, src_rows, src_cols, x, y);
  36. /*
  37. Serial.print("[");
  38. for (uint8_t i=0; i<16; i++) {
  39. Serial.print(adj_2d[i]); Serial.print(", ");
  40. }
  41. Serial.println("]");
  42. */
  43. float frac_x = x - (int)x; // we only need the ~delta~ between the points
  44. float frac_y = y - (int)y; // we only need the ~delta~ between the points
  45. float out = bicubicInterpolate(adj_2d, frac_x, frac_y);
  46. //Serial.print("\tInterp: "); Serial.println(out);
  47. set_point(dest, dest_rows, dest_cols, x_idx, y_idx, out);
  48. }
  49. }
  50. }
  51. // p is a list of 4 points, 2 to the left, 2 to the right
  52. float cubicInterpolate(float p[], float x) {
  53. 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]))));
  54. /*
  55. Serial.print("interpolating: [");
  56. Serial.print(p[0],2); Serial.print(", ");
  57. Serial.print(p[1],2); Serial.print(", ");
  58. Serial.print(p[2],2); Serial.print(", ");
  59. Serial.print(p[3],2); Serial.print("] w/"); Serial.print(x); Serial.print(" = ");
  60. Serial.println(r);
  61. */
  62. return r;
  63. }
  64. // p is a 16-point 4x4 array of the 2 rows & columns left/right/above/below
  65. float bicubicInterpolate(float p[], float x, float y) {
  66. float arr[4] = {0,0,0,0};
  67. arr[0] = cubicInterpolate(p+0, x);
  68. arr[1] = cubicInterpolate(p+4, x);
  69. arr[2] = cubicInterpolate(p+8, x);
  70. arr[3] = cubicInterpolate(p+12, x);
  71. return cubicInterpolate(arr, y);
  72. }
  73. // src is rows*cols and dest is a 4-point array passed in already allocated!
  74. void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y) {
  75. //Serial.print("("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.println(")");
  76. // pick two items to the left
  77. dest[0] = get_point(src, rows, cols, x-1, y);
  78. dest[1] = get_point(src, rows, cols, x, y);
  79. // pick two items to the right
  80. dest[2] = get_point(src, rows, cols, x+1, y);
  81. dest[3] = get_point(src, rows, cols, x+2, y);
  82. }
  83. // src is rows*cols and dest is a 16-point array passed in already allocated!
  84. void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y) {
  85. //Serial.print("("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.println(")");
  86. float arr[4];
  87. for (int8_t delta_y = -1; delta_y < 3; delta_y++) { // -1, 0, 1, 2
  88. float *row = dest + 4 * (delta_y+1); // index into each chunk of 4
  89. for (int8_t delta_x = -1; delta_x < 3; delta_x++) { // -1, 0, 1, 2
  90. row[delta_x+1] = get_point(src, rows, cols, x+delta_x, y+delta_y);
  91. }
  92. }
  93. }