interpolation.cpp 4.8 KB

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