#include "RiaImageTools.h" #include "cvfAssert.h" #include #include #include #include //-------------------------------------------------------------------------------------------------- /// Meijster, Roerdink, Hesselink /// A GENERAL ALGORITHM FOR COMPUTING DISTANCE TRANSFORMS IN LINEAR TIME /// http://fab.cba.mit.edu/classes/S62.12/docs/Meijster_distance.pdf /// Currently Euclidean only, but can be easily extended by replacing the lambda functions. //-------------------------------------------------------------------------------------------------- void RiaImageTools::distanceTransform2d(std::vector>& image) { if (image.empty()) { return; } if (image.front().empty()) { return; } const int64_t M = (int64_t)image.size(); const int64_t N = (int64_t)image.front().size(); int64_t infVal = M + N; CVF_ASSERT(infVal <= std::numeric_limits::max()); // First phase std::vector> g(M); #pragma omp parallel for for (int64_t x = 0; x < M; ++x) { g[x].resize(N, infVal); if (image[x][0]) { g[x][0] = 0; } for (int64_t y = 1; y < N - 1; ++y) { if (image[x][y]) { g[x][y] = 0; } else { g[x][y] = 1 + g[x][y - 1]; } } for (int64_t y = N - 2; y >= 0; --y) { if (g[x][y + 1] < g[x][y]) { g[x][y] = 1 + g[x][y + 1]; } } } auto f = [](int64_t x, int64_t i, const std::vector>& g, int64_t y) { return (x - i) * (x - i) + g[i][y] * g[i][y]; }; auto sep = [](int64_t i, int64_t u, const std::vector>& g, int64_t y) { if (i == u) return (int64_t)0; int64_t numerator = u * u - i * i + g[u][y] * g[u][y] - g[i][y] * g[i][y]; int64_t divisor = 2 * (u - i); return numerator / divisor; }; // Second phase #pragma omp parallel for for (int64_t y = 0; y < N; ++y) { int64_t q = 0; std::vector s(std::max(N, M), (int64_t) 0); std::vector t(std::max(N, M), (int64_t) 0); for (int64_t u = 1; u < M - 1; ++u) { while (q >= 0 && f(t[q], s[q], g, y) > f(t[q], u, g, y)) { q--; } if (q < 0) { q = 0; s[0] = u; } else { int64_t w = 1 + sep((int64_t)s[q], u, g, y); if (w < M) { q++; s[q] = u; t[q] = w; } } } for (int64_t u = M - 1; u >= 0; --u) { int64_t fVal = f(u, s[q], g, y); CVF_ASSERT(fVal <= std::numeric_limits::max()); image[u][y] = static_cast(fVal); if (u == t[q]) { q = q - 1; } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaImageTools::makeGrayScale(QImage& image) { for (int i = 0; i < image.height(); i++) { uchar* scanLine = image.scanLine(i); for (int j = 0; j < image.width(); j++) { QRgb* pixel = reinterpret_cast(scanLine + j * 4); int gray = qGray(*pixel); int alpha = qAlpha(*pixel); *pixel = QColor(gray, gray, gray, alpha).rgba(); } } }