/** * Lubricant Detecter * Copyright (C) 2021 Carl Klemm * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 3 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "uvosunwrap/unwrap.h" #include #include #include #include #include #include #include #include #include "matutils.h" #include "drawing.h" #include "log.h" static void sortIntoRemapMaps(const std::vector& points, cv::Mat& xMat, cv::Mat& yMat, cv::Point2i& topLeftCoordinate) { if(points.size() < 6) { 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 : points) { Log(Log::DEBUG)<<"point: "< xMax) xMax = point.coordinate.x; else if(point.coordinate.x < xMin) xMin = point.coordinate.x; if(point.coordinate.y > yMax) yMax = point.coordinate.y; else if(point.coordinate.y < yMin) yMin = point.coordinate.y; } topLeftCoordinate.x = xMin; topLeftCoordinate.y = yMin; size_t xGridSize = xMax-xMin+1; size_t yGridSize = yMax-yMin+1; xMat.create(cv::Size(xGridSize, yGridSize), CV_32FC1); yMat.create(cv::Size(xGridSize, yGridSize), CV_32FC1); xMat = -1; yMat = -1; Log(Log::DEBUG)<<"Grid: "<(y); float* coly = yMat.ptr(y); for(int x = 0; x < xMat.cols; x++) { for(size_t i = 0; i < points.size(); ++i) { if(points[i].coordinate == cv::Point2i(x+xMin,y+yMin)) { colx[x] = points[i].point.x; coly[x] = points[i].point.y; break; } } } } } bool createRemapMap(const cv::Mat& image, RemapMap& out, const std::vector& points, bool verbose) { sortIntoRemapMaps(points, out.xMat, out.yMat, out.topLeftCoordinate); Log(Log::DEBUG)<<__func__<<": xMat raw\n"<>map.xMat; fs["ymat"]>>map.yMat; fs["origin"]>>map.topLeftCoordinate; return map; } RemapedImage applyRemap(const cv::Mat& image, const RemapMap &map) { RemapedImage out; cv::Mat xMapResized; cv::Mat yMapResized; const cv::Size outputSize(map.outputCellSize*map.xMat.cols,map.outputCellSize*map.xMat.rows); cv::resize(map.xMat, xMapResized, outputSize, cv::INTER_LINEAR); cv::resize(map.yMat, yMapResized, outputSize, cv::INTER_LINEAR); 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.image, xMapRed, yMapRed, cv::INTER_LINEAR); out.origin = cv::Point2i(map.topLeftCoordinate.x*map.outputCellSize, map.topLeftCoordinate.y*map.outputCellSize); return out; } cv::Mat simpleStich(const std::vector& images) { if(images.size() < 1) return cv::Mat(); cv::Size outputSize(0,0); for(auto& image : images) { if(outputSize.width < image.image.cols+image.origin.x) outputSize.width = image.image.cols+image.origin.x; if(outputSize.height < image.image.rows+image.origin.y) outputSize.height = image.image.rows+image.origin.y; Log(Log::DEBUG)<<"image: "<& images, bool seamAdjust) { std::vector masks(images.size()); std::vector corners(images.size()); std::vector sizes(images.size()); for (size_t i = 0; i < images.size(); i++) { masks[i].create(images[i].image.size(), CV_8U); masks[i].setTo(cv::Scalar::all(255)); corners[i] = images[i].origin; sizes[i] = images[i].image.size(); } if(seamAdjust) { std::vector images32f(images.size()); std::vector masksUmat(images.size()); for (size_t i = 0; i < images.size(); i++) { images[i].image.convertTo(images32f[i], CV_32F); masks[i].copyTo(masksUmat[i]); } cv::detail::VoronoiSeamFinder seamFinder; seamFinder.find(images32f, corners, masksUmat); for (size_t i = 0; i < images.size(); i++) { masksUmat[i].copyTo(masks[i]); masksUmat[i].release(); images32f[i].release(); } images32f.clear(); masksUmat.clear(); } cv::Ptr blender; blender = cv::detail::Blender::createDefault(cv::detail::Blender::Blender::MULTI_BAND, false); cv::detail::MultiBandBlender* mb = dynamic_cast(blender.get()); mb->setNumBands(5); blender->prepare(corners, sizes); for (size_t i = 0; i < images.size(); i++) { blender->feed(images[i].image, masks[i], corners[i]); } cv::Mat result; cv::Mat result_mask; blender->blend(result, result_mask); return result; }