2
0

interpolation-error-correction.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #include "interpolation-error-correction.h"
  2. #include <vector>
  3. #include <utility>
  4. #include "arithmetics.hpp"
  5. #include "equation-solver.h"
  6. #include "bitmap-interpolation.hpp"
  7. #include <set> // TEMP
  8. #ifdef _DEBUG
  9. #define dPrintf printf
  10. #else
  11. #define dPrintf(...)
  12. #endif
  13. namespace msdfgen {
  14. // TODO EXPOSE
  15. static double simpleSignedDistance(const Shape &shape, const msdfgen::Point2 &p) {
  16. double dummy;
  17. msdfgen::SignedDistance minDistance;
  18. for (const msdfgen::Contour &contour : shape.contours)
  19. for (const msdfgen::EdgeHolder &edge : contour.edges) {
  20. msdfgen::SignedDistance distance = edge->signedDistance(p, dummy);
  21. if (distance < minDistance)
  22. minDistance = distance;
  23. }
  24. return minDistance.distance;
  25. }
  26. static bool isHotspot(float am, float bm, float xm) {
  27. return (am > .5f && bm > .5f && xm < .5f) || (am < .5f && bm < .5f && xm > .5f); // only at edge
  28. return clamp(median(am, bm, xm)) != clamp(xm); // anywhere
  29. }
  30. static int findLinearChannelHotspots(double t[1], const float *a, const float *b, float dA, float dB) {
  31. int found = 0;
  32. double x = (double) dA/(dA-dB);
  33. if (x > 0 && x < 1) {
  34. float am = median(a[0], a[1], a[2]);
  35. float bm = median(b[0], b[1], b[2]);
  36. float xm = median(
  37. mix(a[0], b[0], x),
  38. mix(a[1], b[1], x),
  39. mix(a[2], b[2], x)
  40. );
  41. if (isHotspot(am, bm, xm))
  42. t[found++] = x;
  43. }
  44. return found;
  45. }
  46. static int findDiagonalChannelHotspots(double t[2], const float *a, const float *b, const float *c, const float *d, float dA, float dB, float dC, float dD) {
  47. int found = 0;
  48. double x[2];
  49. int solutions = solveQuadratic(x, (dD-dC)-(dB-dA), dC+dB-2*dA, dA);
  50. for (int i = 0; i < solutions; ++i)
  51. if (x[i] > 0 && x[i] < 1) {
  52. float am = median(a[0], a[1], a[2]);
  53. float bm = median(b[0], b[1], b[2]);
  54. float xm = median(
  55. mix(mix(a[0], b[0], x[i]), mix(c[0], d[0], x[i]), x[i]),
  56. mix(mix(a[1], b[1], x[i]), mix(c[1], d[1], x[i]), x[i]),
  57. mix(mix(a[2], b[2], x[i]), mix(c[2], d[2], x[i]), x[i])
  58. );
  59. if (isHotspot(am, bm, xm))
  60. t[found++] = x[i];
  61. }
  62. return found;
  63. }
  64. static int findLinearHotspots(double t[3], const float *a, const float *b) {
  65. int found = 0;
  66. found += findLinearChannelHotspots(t+found, a, b, a[1]-a[0], b[1]-b[0]);
  67. found += findLinearChannelHotspots(t+found, a, b, a[2]-a[1], b[2]-b[1]);
  68. found += findLinearChannelHotspots(t+found, a, b, a[0]-a[2], b[0]-b[2]);
  69. return found;
  70. }
  71. static int findDiagonalHotspots(double t[6], const float *a, const float *b, const float *c, const float *d) {
  72. int found = 0;
  73. found += findDiagonalChannelHotspots(t+found, a, b, c, d, a[1]-a[0], b[1]-b[0], c[1]-c[0], d[1]-d[0]);
  74. found += findDiagonalChannelHotspots(t+found, a, b, c, d, a[2]-a[1], b[2]-b[1], c[2]-c[1], d[2]-d[1]);
  75. found += findDiagonalChannelHotspots(t+found, a, b, c, d, a[0]-a[2], b[0]-b[2], c[0]-c[2], d[0]-d[2]);
  76. return found;
  77. }
  78. template <int N>
  79. void findHotspots(std::vector<Point2> &hotspots, const BitmapConstRef<float, N> &sdf) {
  80. // All hotspots intersect either the horizontal, vertical, or diagonal line that connects neighboring texels
  81. // Horizontal:
  82. for (int y = 0; y < sdf.height; ++y) {
  83. const float *left = sdf(0, y);
  84. const float *right = sdf(1, y);
  85. for (int x = 0; x < sdf.width-1; ++x) {
  86. double t[3];
  87. int found = findLinearHotspots(t, left, right);
  88. for (int i = 0; i < found; ++i)
  89. hotspots.push_back(Point2(x+.5+t[i], y+.5));
  90. left += N, right += N;
  91. }
  92. }
  93. // Vertical:
  94. for (int y = 0; y < sdf.height-1; ++y) {
  95. const float *bottom = sdf(0, y);
  96. const float *top = sdf(0, y+1);
  97. for (int x = 0; x < sdf.width; ++x) {
  98. double t[3];
  99. int found = findLinearHotspots(t, bottom, top);
  100. for (int i = 0; i < found; ++i)
  101. hotspots.push_back(Point2(x+.5, y+.5+t[i]));
  102. bottom += N, top += N;
  103. }
  104. }
  105. // Diagonal:
  106. for (int y = 0; y < sdf.height-1; ++y) {
  107. const float *lb = sdf(0, y);
  108. const float *rb = sdf(1, y);
  109. const float *lt = sdf(0, y+1);
  110. const float *rt = sdf(1, y+1);
  111. for (int x = 0; x < sdf.width-1; ++x) {
  112. double t[6];
  113. int found = 0;
  114. found = findDiagonalHotspots(t, lb, rb, lt, rt);
  115. for (int i = 0; i < found; ++i)
  116. hotspots.push_back(Point2(x+.5+t[i], y+.5+t[i]));
  117. found = findDiagonalHotspots(t, lt, rt, lb, rb);
  118. for (int i = 0; i < found; ++i)
  119. hotspots.push_back(Point2(x+.5+t[i], y+1.5-t[i]));
  120. lb += N, rb += N, lt += N, rt += N;
  121. }
  122. }
  123. }
  124. template <int N>
  125. static void msdfInterpolationErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
  126. const float gray[] = { .5f, .5f, .5f, 1.f };
  127. std::vector<Point2> hotspots;
  128. findHotspots(hotspots, BitmapConstRef<float, N>(sdf));
  129. dPrintf("Found %d hotspots (%.3fx texels)\n", (int) hotspots.size(), (double) hotspots.size()/(sdf.width*sdf.height));
  130. //std::vector<std::pair<int, int> > artifacts;
  131. //artifacts.reserve(hotspots.size());
  132. std::set<std::pair<int, int> > artifacts;
  133. for (std::vector<Point2>::const_iterator hotspot = hotspots.begin(); hotspot != hotspots.end(); ++hotspot) {
  134. Point2 pos = *hotspot/scale-translate;
  135. double distance = simpleSignedDistance(shape, pos);
  136. float sd = float(distance/range+.5);
  137. float *subject = sdf((int) hotspot->x, (int) hotspot->y);
  138. float texel[N];
  139. memcpy(texel, subject, N*sizeof(float));
  140. float msd[N];
  141. interpolate(msd, BitmapConstRef<float, N>(sdf), *hotspot);
  142. float oldSsd = median(msd[0], msd[1], msd[2]);
  143. float med = median(subject[0], subject[1], subject[2]);
  144. subject[0] = med, subject[1] = med, subject[2] = med;
  145. interpolate(msd, BitmapConstRef<float, N>(sdf), *hotspot);
  146. float newSsd = median(msd[0], msd[1], msd[2]);
  147. memcpy(subject, texel, N*sizeof(float));
  148. dPrintf("Real sd = %f, old = %f, new = %f\n", sd, oldSsd, newSsd);
  149. //memcpy(sdf((int) hotspot->x, (int) hotspot->y), gray, N*sizeof(float));
  150. bool significant = fabsf(newSsd-sd) < fabsf(oldSsd-sd);
  151. significant = (newSsd-.5f)*(oldSsd-.5f) < 0;
  152. significant = fabsf(newSsd-sd) < fabsf(oldSsd-sd);
  153. if (significant)
  154. artifacts.insert(std::make_pair((int) hotspot->x, (int) hotspot->y));
  155. //artifacts.push_back(std::make_pair((int) hotspot->x, (int) hotspot->y));
  156. }
  157. dPrintf("Found %d artifacts (%.2f%% hotspots, %.2f%% texels)\n", (int) artifacts.size(), 100.*artifacts.size()/hotspots.size(), 100.*artifacts.size()/(sdf.width*sdf.height));
  158. for (std::set<std::pair<int, int> >::const_iterator artifact = artifacts.begin(); artifact != artifacts.end(); ++artifact) {
  159. float *pixel = sdf(artifact->first, artifact->second);
  160. float med = median(pixel[0], pixel[1], pixel[2]);
  161. pixel[0] = med, pixel[1] = med, pixel[2] = med;
  162. }
  163. }
  164. void msdfInterpolationErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
  165. msdfInterpolationErrorCorrectionInner(sdf, shape, range, scale, translate, overlapSupport);
  166. }
  167. void msdfInterpolationErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
  168. msdfInterpolationErrorCorrectionInner(sdf, shape, range, scale, translate, overlapSupport);
  169. }
  170. }