#include "unwrap.h" #include #include #include #include #include #include #include "matutils.h" #include "drawing.h" #include "log.h" struct DisplacmentMap { std::vector< std::vector > destination; std::vector< std::vector > source; }; static std::vector< std::vector > sortPointsIntoRows(std::vector& points) { if(points.size() < 6) return std::vector< std::vector >(); cv::Point2f topLeft(*getTopLeft(points)); cv::Point2f bottomRight(*getBottomRight(points)); Log(Log::DEBUG)<<"topLeft "< bottomRight.x+fuzz || points[i].y > bottomRight.y+fuzz) points.erase(points.begin()+i); } std::sort(points.begin(), points.end(), [](const cv::Point2f& a, const cv::Point2f& b){return a.y < b.y;}); double accumulator = points[0].y+points[1].y; size_t accuCount = 2; float sigDist = (bottomRight.y-topLeft.y) / 20; std::vector< std::vector > result(1); result.back().push_back(points[0]); result.back().push_back(points[1]); for(size_t i = 2; i < points.size(); ++i) { if( points[i].y - accumulator/accuCount > sigDist ) { if(points.size() - i - 3 < 0) break; else { accumulator = points[i+1].y+points[i+2].y; accuCount = 2; } result.push_back(std::vector()); } result.back().push_back(points[i]); accumulator += points[i].y; ++accuCount; } for(auto& row : result) std::sort(row.begin(), row.end(), [](const cv::Point2f& a, const cv::Point2f& b){return a.x < b.x;}); return result; } static float detimineXPitch(const std::vector& row, float fuzz = 1.3f) { std::vector xRowDists; for(size_t i = 0; i < row.size()-1; ++i) xRowDists.push_back(abs(row[i+1].x-row[i].x)); float xMinDist = *std::min(xRowDists.begin(), xRowDists.end()); Log(Log::DEBUG)<<__func__<<": xMinDist "< fitEllipses(std::vector< std::vector >& rows, bool remove = true) { if(rows.empty()) return std::vector(); std::vector ellipses; ellipses.reserve(rows.size()); for(size_t i = 0; i < rows.size(); ++i) { if(rows[i].size() > 4) ellipses.push_back(cv::fitEllipse(rows[i])); else { rows.erase(rows.begin()+i); i--; } } return ellipses; } static void thompsonTauTest(const std::vector& in, std::vector& outliers, float criticalValue) { float mean = 0; size_t n = 0; for(size_t i = 0; i < in.size(); ++i) { bool found = false; for(size_t j = 0; j < outliers.size() && !found; ++j) if(outliers[j]==i) found = true; if(!found) { mean+=in[i]; ++n; } } mean/=n; float sd = 0; for(size_t i = 0; i < in.size(); ++i) { bool found = false; for(size_t j = 0; j < outliers.size() && !found; ++j) if(outliers[j]==i) found = true; if(!found) sd+=pow(in[i]-mean,2); } sd = sqrt(sd/(n-1)); float rej = (criticalValue*(n-1))/(sqrt(n)*sqrt(n-2+criticalValue)); bool removed = false; for(size_t i = 0; i < in.size() && !removed; ++i) { bool found = false; for(size_t j = 0; j < outliers.size() && !found; ++j) if(outliers[j]==i) found = true; if(!found) { if(abs((in[i]-mean)/sd) > rej) { Log(Log::DEBUG)<<__func__<<": "< >& rows, std::vector& elipses) { if(rows.size() != elipses.size() && elipses.size() > 1) return false; for(size_t i = 0; i < elipses.size(); ++i) { float angDiff = fmod(elipses[i].angle,90); if(angDiff < 90-5 && angDiff > 5) { elipses.erase(elipses.begin()+i); rows.erase(rows.begin()+i); --i; } } std::vector widths; std::vector heights; for(auto& elipse : elipses) { widths.push_back(elipse.size.width); heights.push_back(elipse.size.height); } std::vector outliersW; std::vector outliersH; thompsonTauTest(widths, outliersW, 2); thompsonTauTest(heights, outliersH, 2); std::vector< std::vector > rowsReduced; std::vector elipsesReduced; for(size_t i = 0; i < elipses.size(); ++i) { bool found = false; for(size_t j = 0; j < outliersW.size() && !found; ++j) if(outliersW[j]==i) found = true; for(size_t j = 0; j < outliersH.size() && !found; ++j) if(outliersH[j]==i) found = true; if(!found) { rowsReduced.push_back(rows[i]); elipsesReduced.push_back(elipses[i]); } } elipses = elipsesReduced; rows = rowsReduced; return true; } static DisplacmentMap calcDisplacementMap(const std::vector< std::vector >& rows, const std::vector& elipses) { if(rows.size() < 2 || rows.size() != elipses.size()) { Log(Log::ERROR)<<__func__<<": rows < 2 or rows != elipses"; return DisplacmentMap(); } DisplacmentMap displacmentmap; displacmentmap.destination.assign(rows.size(), std::vector()); displacmentmap.source = rows; for(size_t i = 0; i < displacmentmap.destination.size(); ++i) { displacmentmap.destination[i].reserve(rows[i].size()); } float meanYdist = 0; size_t j = 0; while(j < elipses.size()-1) { meanYdist += elipses[j+1].center.y-elipses[j].center.y; ++j; } meanYdist = meanYdist/elipses.size(); Log(Log::DEBUG)<<__func__<<": meanYdist "<& row = rows[rowCnt]; const cv::RotatedRect& elipse = elipses[rowCnt]; cv::Rect_ boundingRect = elipse.boundingRect2f(); Log(Log::DEBUG)<<__func__<<": Proc row "<(y,0) >= 0) ++front; if(mat.at(y,mat.cols-1) >= 0) ++back; } Log(Log::DEBUG)<<__func__<<" front: "<::max(); float xMeanMin = 0; float xMax = std::numeric_limits::min(); for(auto& row: map.destination ) { xMeanMin+=row.front().x; if(xMin > row.front().x ) xMin = row.front().x; if(xMax < row.back().x) xMax = row.back().x; } xMeanMin = xMeanMin / map.destination.size(); Log(Log::DEBUG)<<__func__<<": Grid: xMin "<(std::lround(abs((xMax-xMin)/xMeanDist))+1); xMat = cv::Mat::zeros(cv::Size(xGridSize, map.destination.size()), CV_32FC1); yMat = cv::Mat::zeros(cv::Size(xGridSize, map.destination.size()), CV_32FC1); Log(Log::DEBUG)<<"Grid: "<(y); float* coly = yMat.ptr(y); for(int x = 0; x < xMat.cols; x++) { size_t xIndex = 0; size_t yIndex = 0; bool found = findClosest(xIndex, yIndex, cv::Point2f((x)*xMeanDist+xMin, (y)*yMeanDist), map.destination, (2*xMeanDist)/5, (2*yMeanDist)/5); Log(Log::DEBUG)<<__func__<<": found: "<& points, const std::vector& coordinates, cv::Mat& xMat, cv::Mat& yMat) { if(points.size() < 6 || coordinates.size() != points.size()) { Log(Log::ERROR)<<__func__<<": at least 6 points are needed"; return; } int xMin = std::numeric_limits::max(); int xMax = std::numeric_limits::min(); int yMin = std::numeric_limits::max(); int yMax = std::numeric_limits::min(); for(auto& point : coordinates) { Log(Log::DEBUG)<<"point: "< xMax) xMax = point.x; else if(point.x < xMin) xMin = point.x; if(point.y > yMax) yMax = point.y; else if(point.y < yMin) yMin = point.y; } size_t xGridSize = xMax-xMin+1; size_t yGridSize = yMax-yMin+1; xMat = cv::Mat::zeros(cv::Size(xGridSize, yGridSize), CV_32FC1); yMat = cv::Mat::zeros(cv::Size(xGridSize, yGridSize), CV_32FC1); Log(Log::DEBUG)<<"Grid: "<(y); float* coly = yMat.ptr(y); for(int x = 0; x < xMat.cols; x++) { colx[x] = -1; coly[x] = -1; for(size_t i = 0; i < coordinates.size(); ++i) { if(coordinates[i] == cv::Point2i(x+xMin,y+yMin)) { colx[x] = points[i].x; coly[x] = points[i].y; break; } } } } Log(Log::DEBUG)<<__func__<<": xMat raw\n"< points, const std::vector& coordinates, const std::string& fileName, bool verbose) { cv::Mat xMat; cv::Mat yMat; if(coordinates.empty()) { std::vector< std::vector > rows = sortPointsIntoRows(points); Log(Log::INFO)<<"Found "< ellipses = fitEllipses(rows); Log(Log::INFO)<<"Found "<(0,mat.cols/2); float centerLeft = mat.at(mat.rows/2,0); float centerBottom = mat.at(mat.rows-1,mat.cols/2); float centerRight = mat.at(mat.rows/2,mat.cols-1); int left = 0; int right = mat.cols-1; int top = 0; int bottom = mat.rows-1; for(; left < mat.cols && mat.at(mat.rows/2,left) == centerLeft; ++left); for(; top < mat.rows && mat.at(top,mat.cols/2) == centerTop; ++top); for(; right > left && mat.at(mat.rows/2,right) == centerRight; --right); for(; bottom > top && mat.at(bottom,mat.cols/2) == centerBottom; --bottom); roi.x=left; roi.y=top; roi.width = right-left; roi.height = bottom-top; return true; } void applyRemap(cv::Mat& image, cv::Mat& out, const cv::Mat& xmap, const cv::Mat& ymap, unsigned int outputSize) { cv::Mat xMapResized; cv::Mat yMapResized; cv::resize(xmap, xMapResized, cv::Size(outputSize,outputSize*(xmap.rows/(double)xmap.cols)), cv::INTER_CUBIC); cv::resize(ymap, yMapResized, cv::Size(outputSize,outputSize*(xmap.rows/(double)xmap.cols)), cv::INTER_CUBIC); cv::Rect roi; cv::Mat xMapRed; cv::Mat yMapRed; if(!findDeadSpace(xMapResized, roi)) { xMapRed = xMapResized(roi); yMapRed = yMapResized(roi); } else { xMapRed = xMapResized; yMapRed = yMapResized; } cv::remap(image, out, xMapRed, yMapRed, cv::INTER_LINEAR); }