Compare commits
No commits in common. "0f5ae63b7550dadecf198228b5fda3957fb595f9" and "8b643b03d3e43d0111a155e3e9119aaa36b9b098" have entirely different histories.
0f5ae63b75
...
8b643b03d3
|
@ -35,13 +35,12 @@ struct Config
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
bool interactive = false;
|
bool interactive = false;
|
||||||
bool simpleStich = false;
|
bool simpleStich = false;
|
||||||
float kFactor = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *argp_program_version = "0.2";
|
const char *argp_program_version = "0.2";
|
||||||
const char *argp_program_bug_address = "<carl@uvos.xyz>";
|
const char *argp_program_bug_address = "<carl@uvos.xyz>";
|
||||||
static char doc[] = "Program to determine the lubricant thikness on a curved surface.\n\
|
static char doc[] = "Program to determine the lubricant thikness on a curved surface.\n\
|
||||||
Possible operations: apply create curve mkcurve mkboard show";
|
Possible operations: apply create curve mkcurve mkboard";
|
||||||
static char args_doc[] = "[OPERATION] IMAGE1 IMAGE2 ...";
|
static char args_doc[] = "[OPERATION] IMAGE1 IMAGE2 ...";
|
||||||
|
|
||||||
static struct argp_option options[] =
|
static struct argp_option options[] =
|
||||||
|
@ -57,7 +56,6 @@ static struct argp_option options[] =
|
||||||
{"interactive", 'i', 0, 0, "interactivly process multiple commands" },
|
{"interactive", 'i', 0, 0, "interactivly process multiple commands" },
|
||||||
{"simpe-stich", 'a', 0, 0, "Use non blending sticher" },
|
{"simpe-stich", 'a', 0, 0, "Use non blending sticher" },
|
||||||
{"curve", 'c', "File Name", 0, "curve file name" },
|
{"curve", 'c', "File Name", 0, "curve file name" },
|
||||||
{"kfactor", 'k', "Value", 0, "set the kfactor" },
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,7 +78,7 @@ error_t parse_opt (int key, char *arg, struct argp_state *state)
|
||||||
config->norm.assign(arg);
|
config->norm.assign(arg);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
config->minSize=strtod(arg, nullptr);
|
config->minSize=atol(arg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
config->harris = true;
|
config->harris = true;
|
||||||
|
@ -100,9 +98,6 @@ error_t parse_opt (int key, char *arg, struct argp_state *state)
|
||||||
case 'c':
|
case 'c':
|
||||||
config->curve.assign(arg);
|
config->curve.assign(arg);
|
||||||
break;
|
break;
|
||||||
case 'k':
|
|
||||||
config->kFactor=strtod(arg, nullptr);
|
|
||||||
break;
|
|
||||||
case ARGP_KEY_ARG:
|
case ARGP_KEY_ARG:
|
||||||
config->commandsFiles = &state->argv[state->next-1];
|
config->commandsFiles = &state->argv[state->next-1];
|
||||||
state->next = state->argc;
|
state->next = state->argc;
|
||||||
|
|
|
@ -20,76 +20,19 @@
|
||||||
#include "uvosunwrap/charuco.h"
|
#include "uvosunwrap/charuco.h"
|
||||||
#include <opencv2/aruco/charuco.hpp>
|
#include <opencv2/aruco/charuco.hpp>
|
||||||
#include <opencv2/highgui.hpp>
|
#include <opencv2/highgui.hpp>
|
||||||
#include "uvosunwrap/log.h"
|
|
||||||
|
static constexpr unsigned int X_BOARD_SIZE = 18;
|
||||||
|
static constexpr unsigned int Y_BOARD_SIZE = 10;
|
||||||
|
|
||||||
|
|
||||||
void createCharucoBoard(unsigned int size, const std::string& fileName)
|
void createCharucoBoard(unsigned int size, const std::string& fileName)
|
||||||
{
|
{
|
||||||
cv::Ptr<cv::aruco::CharucoBoard> board =
|
cv::Ptr<cv::aruco::CharucoBoard> board =
|
||||||
cv::aruco::CharucoBoard::create(X_BOARD_SIZE, Y_BOARD_SIZE, 0.03f, 0.02f,
|
cv::aruco::CharucoBoard::create(X_BOARD_SIZE, Y_BOARD_SIZE, 0.03f, 0.02f,
|
||||||
cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_250 ));
|
cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_250 ));
|
||||||
cv::Mat charucoImage;
|
cv::Mat charucoImage;
|
||||||
double cellSize = size/(double)Y_BOARD_SIZE;
|
board->draw(cv::Size((size*18)/10, size), charucoImage, 0, 1);
|
||||||
board->draw(cv::Size((size*X_BOARD_SIZE)/Y_BOARD_SIZE, size), charucoImage, 0, 1);
|
cv::imwrite(fileName, charucoImage);
|
||||||
cv::Mat charucoImageWithBorder =
|
|
||||||
cv::Mat::zeros(cv::Size(cellSize*(X_BOARD_SIZE+1), cellSize*(Y_BOARD_SIZE+2)), CV_8UC1);
|
|
||||||
cv::Rect roi(cellSize, cellSize, charucoImage.cols, charucoImage.rows);
|
|
||||||
charucoImage.copyTo(charucoImageWithBorder(roi));
|
|
||||||
cv::imwrite(fileName, charucoImageWithBorder);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void seamAjust(std::vector<DetectedPoint>& detections)
|
|
||||||
{
|
|
||||||
int xMin = std::numeric_limits<int>::max();
|
|
||||||
int xMax = std::numeric_limits<int>::min();
|
|
||||||
|
|
||||||
for(auto& point : detections)
|
|
||||||
{
|
|
||||||
if(point.coordinate.x > xMax)
|
|
||||||
xMax = point.coordinate.x;
|
|
||||||
else if(point.coordinate.x < xMin)
|
|
||||||
xMin = point.coordinate.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(xMax - xMin < static_cast<int>(X_BOARD_SIZE/2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Log(Log::DEBUG)<<"Image contains seam";
|
|
||||||
|
|
||||||
int rightMostPoint = 0;
|
|
||||||
bool extantCol[X_BOARD_SIZE] = {0};
|
|
||||||
for(auto& point : detections)
|
|
||||||
{
|
|
||||||
if(!extantCol[point.coordinate.x])
|
|
||||||
extantCol[point.coordinate.x] = true;
|
|
||||||
if(point.coordinate.x > rightMostPoint)
|
|
||||||
rightMostPoint = point.coordinate.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int leftCoordinate = 0;
|
|
||||||
int maxDeadrange = 0;
|
|
||||||
int deadRange = 0;
|
|
||||||
for(unsigned int i = 0; i < X_BOARD_SIZE-1; ++i)
|
|
||||||
{
|
|
||||||
if(!extantCol[i])
|
|
||||||
{
|
|
||||||
++deadRange;
|
|
||||||
if(extantCol[i+1] && maxDeadrange < deadRange)
|
|
||||||
{
|
|
||||||
leftCoordinate = i+1;
|
|
||||||
maxDeadrange = deadRange;
|
|
||||||
deadRange = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(Log::DEBUG)<<"Left coordinate before seam "<<leftCoordinate
|
|
||||||
<<" right most "<<rightMostPoint;
|
|
||||||
|
|
||||||
for(auto& point : detections)
|
|
||||||
{
|
|
||||||
if(point.coordinate.x < leftCoordinate)
|
|
||||||
point.coordinate.x = point.coordinate.x + rightMostPoint + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DetectedPoint> detectCharucoPoints(cv::Mat image, bool verbose)
|
std::vector<DetectedPoint> detectCharucoPoints(cv::Mat image, bool verbose)
|
||||||
|
@ -143,8 +86,6 @@ std::vector<DetectedPoint> detectCharucoPoints(cv::Mat image, bool verbose)
|
||||||
detections.push_back(DetectedPoint(charucoCorners[i], coordiante));
|
detections.push_back(DetectedPoint(charucoCorners[i], coordiante));
|
||||||
}
|
}
|
||||||
|
|
||||||
seamAjust(detections);
|
|
||||||
|
|
||||||
return detections;
|
return detections;
|
||||||
}
|
}
|
||||||
return std::vector<DetectedPoint>();
|
return std::vector<DetectedPoint>();
|
||||||
|
|
57
src/main.cpp
57
src/main.cpp
|
@ -42,7 +42,6 @@ enum {
|
||||||
APPLY_MAP,
|
APPLY_MAP,
|
||||||
APPLY_CURVE,
|
APPLY_CURVE,
|
||||||
CREATE_CURVE,
|
CREATE_CURVE,
|
||||||
SHOW_IMAGE,
|
|
||||||
EXIT
|
EXIT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,8 +59,6 @@ int selectOperation(char** opt)
|
||||||
return CREATE_CURVE;
|
return CREATE_CURVE;
|
||||||
else if(strcmp(opt[0], "mkboard" ) == 0)
|
else if(strcmp(opt[0], "mkboard" ) == 0)
|
||||||
return CREATE_CHARUCO;
|
return CREATE_CHARUCO;
|
||||||
else if(strcmp(opt[0], "show" ) == 0)
|
|
||||||
return SHOW_IMAGE;
|
|
||||||
else if(strcmp(opt[0], "exit" ) == 0)
|
else if(strcmp(opt[0], "exit" ) == 0)
|
||||||
return EXIT;
|
return EXIT;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -95,7 +92,7 @@ cv::Mat openImageYml(char* fileName)
|
||||||
cv::FileStorage matf(fileName, cv::FileStorage::READ);
|
cv::FileStorage matf(fileName, cv::FileStorage::READ);
|
||||||
matf["image"]>>image;
|
matf["image"]>>image;
|
||||||
|
|
||||||
if(matf.isOpened() && !image.data)
|
if(matf.isOpened() && (!image.data || image.type() != CV_32FC1))
|
||||||
{
|
{
|
||||||
Log(Log::WARN)<<fileName<<" dose not contain a valid image";
|
Log(Log::WARN)<<fileName<<" dose not contain a valid image";
|
||||||
matf.release();
|
matf.release();
|
||||||
|
@ -118,19 +115,13 @@ std::vector<cv::Mat> loadImages(char** fileNames)
|
||||||
cv::Mat tmpImage;
|
cv::Mat tmpImage;
|
||||||
const std::string str(fileNames[i]);
|
const std::string str(fileNames[i]);
|
||||||
if(str.find(".mat") != std::string::npos)
|
if(str.find(".mat") != std::string::npos)
|
||||||
{
|
openImageYml(fileNames[i]);
|
||||||
Log(Log::DEBUG)<<__func__<<": "<<fileNames[i]<<" as YAML image";
|
else
|
||||||
tmpImage = openImageYml(fileNames[i]);
|
tmpImage = openImageImg(fileNames[i]);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log(Log::DEBUG)<<__func__<<": "<<fileNames[i]<<" as png image";
|
|
||||||
tmpImage = openImageImg(fileNames[i]);
|
|
||||||
}
|
|
||||||
if(tmpImage.data)
|
if(tmpImage.data)
|
||||||
images.push_back(tmpImage);
|
images.push_back(tmpImage);
|
||||||
else
|
else
|
||||||
Log(Log::WARN)<<"can not read image "<<i<<" from "<<fileNames[i];
|
Log(Log::WARN)<<"can not read image "<<i<<" from "<<fileNames[i]<<'\n';
|
||||||
}
|
}
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +129,7 @@ std::vector<cv::Mat> loadImages(char** fileNames)
|
||||||
int perfromOperation(int operation, char** fileNames, const Config& config)
|
int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
{
|
{
|
||||||
std::vector<cv::Mat> inImages;
|
std::vector<cv::Mat> inImages;
|
||||||
if(operation == CREATE_MAP || operation == APPLY_MAP || operation == APPLY_CURVE || operation == SHOW_IMAGE)
|
if(operation == CREATE_MAP || operation == APPLY_MAP || operation == APPLY_CURVE)
|
||||||
{
|
{
|
||||||
inImages = loadImages(fileNames);
|
inImages = loadImages(fileNames);
|
||||||
|
|
||||||
|
@ -152,7 +143,7 @@ int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
if(operation == CREATE_CHARUCO)
|
if(operation == CREATE_CHARUCO)
|
||||||
{
|
{
|
||||||
std::string fileName = config.output.empty() ? "out.png" : config.output;
|
std::string fileName = config.output.empty() ? "out.png" : config.output;
|
||||||
createCharucoBoard(config.size*X_BOARD_SIZE, fileName);
|
createCharucoBoard(config.size*14, fileName);
|
||||||
Log(Log::INFO)<<"Exported charuco map of size "<<config.size*14<<" to "<<fileName;
|
Log(Log::INFO)<<"Exported charuco map of size "<<config.size*14<<" to "<<fileName;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -211,10 +202,7 @@ int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
map.outputCellSize = config.size;
|
map.outputCellSize = config.size;
|
||||||
|
|
||||||
if(!map.xMat.data)
|
if(!map.xMat.data)
|
||||||
{
|
|
||||||
Log(Log::ERROR)<<"could not load remap map from "<<std::string(fileNames[i])+".mat";
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
RemapedImage norm;
|
RemapedImage norm;
|
||||||
if(!config.norm.empty())
|
if(!config.norm.empty())
|
||||||
|
@ -222,7 +210,7 @@ int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
cv::Mat tmp = cv::imread(config.norm);
|
cv::Mat tmp = cv::imread(config.norm);
|
||||||
if(!tmp.data)
|
if(!tmp.data)
|
||||||
{
|
{
|
||||||
Log(Log::WARN)<<"could not open normalize file "<<config.norm;
|
Log(Log::WARN)<<"could not open normalize file " <<config.norm;
|
||||||
}
|
}
|
||||||
norm = applyRemap(tmp, map);
|
norm = applyRemap(tmp, map);
|
||||||
if(config.verbose)
|
if(config.verbose)
|
||||||
|
@ -242,15 +230,6 @@ int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
{
|
{
|
||||||
cv::imshow( "Viewer", remaped.image );
|
cv::imshow( "Viewer", remaped.image );
|
||||||
cv::waitKey(0);
|
cv::waitKey(0);
|
||||||
cv::imshow( "Viewer", remaped.angle);
|
|
||||||
cv::waitKey(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
applyKfactor(remaped.image, remaped.angle, config.kFactor);
|
|
||||||
if(config.verbose)
|
|
||||||
{
|
|
||||||
cv::imshow("Viewer", remaped.image );
|
|
||||||
cv::waitKey(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remapedImages.push_back(remaped);
|
remapedImages.push_back(remaped);
|
||||||
|
@ -282,23 +261,17 @@ int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
|
|
||||||
cv::FileStorage fs(config.curve, cv::FileStorage::READ);
|
cv::FileStorage fs(config.curve, cv::FileStorage::READ);
|
||||||
cv::Mat curve;
|
cv::Mat curve;
|
||||||
fs["cal"]>>curve;
|
fs["curve"]>>curve;
|
||||||
if(!curve.data || curve.type() != CV_32FC1 || curve.rows != 2 || curve.cols < 3)
|
if(!curve.data || curve.type() != CV_32FC1 || curve.rows != 2 || curve.cols < 3)
|
||||||
{
|
{
|
||||||
Log(Log::INFO)<<"invalid curve";
|
Log(Log::INFO)<<"invalid curve";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inImages[0].channels() > 1)
|
cvtColor(inImages[0], inImages[0], cv::COLOR_BGR2GRAY);
|
||||||
cvtColor(inImages[0], inImages[0], cv::COLOR_BGR2GRAY);
|
|
||||||
if(inImages[0].type() != CV_32FC1)
|
|
||||||
inImages[0].convertTo(inImages[0], CV_32F);
|
inImages[0].convertTo(inImages[0], CV_32F);
|
||||||
|
|
||||||
Log(Log::DEBUG)<<"applyCurve";
|
|
||||||
applyCurve(inImages[0], curve);
|
applyCurve(inImages[0], curve);
|
||||||
cv::FileStorage fsO("out.mat", cv::FileStorage::WRITE);
|
|
||||||
fsO<<"image"<<inImages[0];
|
|
||||||
fsO.release();
|
|
||||||
}
|
}
|
||||||
else if(operation == CREATE_CURVE)
|
else if(operation == CREATE_CURVE)
|
||||||
{
|
{
|
||||||
|
@ -350,16 +323,6 @@ int perfromOperation(int operation, char** fileNames, const Config& config)
|
||||||
|
|
||||||
std::cout<<"Curve saved to "<<(!config.output.empty() ? config.output : "curve.mat")<<'\n';
|
std::cout<<"Curve saved to "<<(!config.output.empty() ? config.output : "curve.mat")<<'\n';
|
||||||
}
|
}
|
||||||
else if(operation == SHOW_IMAGE)
|
|
||||||
{
|
|
||||||
cv::namedWindow("Show Image", cv::WINDOW_NORMAL );
|
|
||||||
for(size_t i = 0; i < inImages.size(); ++i)
|
|
||||||
{
|
|
||||||
cv::imshow("Show Image", inImages[i]);
|
|
||||||
cv::waitKey(0);
|
|
||||||
}
|
|
||||||
cv::destroyWindow("Show Image");
|
|
||||||
}
|
|
||||||
else if(operation == EXIT)
|
else if(operation == EXIT)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -178,7 +178,7 @@ bool findClosest(size_t& index, const cv::Point2f point, const std::vector<cv::P
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void interpolateMissingOnX(cv::Mat& mat)
|
void interpolateMissing(cv::Mat& mat)
|
||||||
{
|
{
|
||||||
assert(mat.type() == CV_32FC1);
|
assert(mat.type() == CV_32FC1);
|
||||||
|
|
||||||
|
@ -223,48 +223,34 @@ void interpolateMissingOnX(cv::Mat& mat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void interpolateMissingOnY(cv::Mat& mat)
|
void fillMissing(cv::Mat& mat)
|
||||||
{
|
{
|
||||||
assert(mat.type() == CV_32FC1);
|
assert(mat.type() == CV_32FC1);
|
||||||
|
|
||||||
for(int x = 0; x < mat.cols; ++x)
|
bool finished = true;
|
||||||
|
for(int y = 0; y < mat.rows; y++)
|
||||||
{
|
{
|
||||||
for(int y = 0; y < mat.rows; y++)
|
float* col = mat.ptr<float>(y);
|
||||||
|
for(int x = 0; x < mat.cols; ++x)
|
||||||
{
|
{
|
||||||
if(mat.at<float>(y,x) < 0)
|
if(col[x] < 0 && col[x] > -2)
|
||||||
{
|
{
|
||||||
int closestA = -1;
|
if(y > 0 && mat.at<float>(y-1,x) >= 0)
|
||||||
int closestB = -1;
|
|
||||||
int dist = std::numeric_limits<int>::max();
|
|
||||||
for(int i = 0; i < mat.rows; i++)
|
|
||||||
{
|
{
|
||||||
if(i != closestA && mat.at<float>(i,x) >= 0 && abs(i-y) <= dist)
|
col[x] = mat.at<float>(y-1,x);
|
||||||
{
|
finished = false;
|
||||||
closestB = closestA;
|
|
||||||
closestA = i;
|
|
||||||
dist = abs(i-y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(closestA < 0 || closestB < 0)
|
else if(y < mat.rows-1 && mat.at<float>(y+1,x) >= 0)
|
||||||
{
|
{
|
||||||
closestA = -1;
|
col[x] = mat.at<float>(y+1,x);
|
||||||
closestB = -1;
|
finished = false;
|
||||||
dist = std::numeric_limits<int>::max();
|
|
||||||
for(int i = mat.rows-1; i >= 0; --i)
|
|
||||||
{
|
|
||||||
if(i != closestA && mat.at<float>(i,x) >= 0 && abs(i-y) <= dist)
|
|
||||||
{
|
|
||||||
closestB = closestA;
|
|
||||||
closestA = i;
|
|
||||||
dist = abs(i-y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
float slope = (mat.at<float>(closestB,x) - mat.at<float>(closestA,x))/(closestB-closestA);
|
if(col[x] > 0 && ((x+1 < mat.cols && col[x] > col[x+1]) || (x > 0 && col[x] < col[x-1])))
|
||||||
mat.at<float>(y,x) = mat.at<float>(closestA,x) - (closestA-y)*slope;
|
col[x] = -2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!finished) fillMissing(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi)
|
bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi)
|
||||||
|
@ -301,25 +287,66 @@ bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeSparseCols(cv::Mat& mat, float reject, bool front)
|
bool deleteEmptyCols(cv::Mat& mat)
|
||||||
|
{
|
||||||
|
assert(mat.type() == CV_32FC1);
|
||||||
|
|
||||||
|
std::vector<size_t> cols;
|
||||||
|
cols.reserve(mat.cols);
|
||||||
|
|
||||||
|
for(int x = 0; x < mat.cols; x++)
|
||||||
|
{
|
||||||
|
bool empty = true;
|
||||||
|
for(int y = 0; y < mat.rows; y++)
|
||||||
|
{
|
||||||
|
if(mat.at<float>(x,y) > 0)
|
||||||
|
{
|
||||||
|
empty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty)
|
||||||
|
cols.push_back(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mat.cols < static_cast<long int>(cols.size()))
|
||||||
|
{
|
||||||
|
cv::Mat tmp(cv::Size(cols.size(), mat.rows), CV_32FC1);
|
||||||
|
|
||||||
|
for(auto& col : cols)
|
||||||
|
{
|
||||||
|
cv::Rect roi(cv::Point2i(col, 0), cv::Size(1, mat.rows));
|
||||||
|
mat.copyTo(tmp(roi));
|
||||||
|
}
|
||||||
|
mat.release();
|
||||||
|
mat = tmp;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSparseCols(cv::Mat& mat, bool front)
|
||||||
{
|
{
|
||||||
assert(mat.type() == CV_32FC1);
|
assert(mat.type() == CV_32FC1);
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(int y = 0; y < mat.rows; ++y)
|
for(int y = 0; y < mat.rows; ++y)
|
||||||
{
|
{
|
||||||
if((front && mat.at<float>(y,0) >= 0) || (!front && mat.at<float>(y,mat.cols-1) >= 0))
|
if(front && mat.at<float>(y,0) >= 0) ++count;
|
||||||
++count;
|
else if(mat.at<float>(y,mat.cols-1) >= 0) ++count;
|
||||||
}
|
}
|
||||||
cv::Rect roi;
|
cv::Rect roi;
|
||||||
bool rej = (count < mat.rows*reject);
|
bool rej = (count < mat.rows/2);
|
||||||
roi.x=front ? rej : 0;
|
roi.x=front ? rej : 0;
|
||||||
roi.y=0;
|
roi.y=0;
|
||||||
roi.width = mat.cols - rej;
|
roi.width = mat.cols - rej;
|
||||||
roi.height = mat.rows;
|
roi.height = mat.rows;
|
||||||
mat = mat(roi);
|
mat = mat(roi);
|
||||||
if(rej)
|
if(rej)
|
||||||
removeSparseCols(mat, reject, front);
|
removeSparseCols(mat, front);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float linInterpolate(float A, float B, float x)
|
static float linInterpolate(float A, float B, float x)
|
||||||
|
|
|
@ -37,13 +37,15 @@ bool findClosest(size_t& index, const cv::Point2f point, const std::vector<cv::P
|
||||||
|
|
||||||
void thompsonTauTest(const std::vector<float>& in, std::vector<size_t>& outliers, float criticalValue);
|
void thompsonTauTest(const std::vector<float>& in, std::vector<size_t>& outliers, float criticalValue);
|
||||||
|
|
||||||
void interpolateMissingOnX(cv::Mat& mat);
|
void interpolateMissing(cv::Mat& mat);
|
||||||
|
|
||||||
void interpolateMissingOnY(cv::Mat& mat);
|
void fillMissing(cv::Mat& mat);
|
||||||
|
|
||||||
bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi);
|
bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi);
|
||||||
|
|
||||||
void removeSparseCols(cv::Mat& mat, float reject, bool front);
|
bool deleteEmptyCols(cv::Mat& mat);
|
||||||
|
|
||||||
|
void removeSparseCols(cv::Mat& mat, bool front);
|
||||||
|
|
||||||
bool bilinearResize(const cv::Mat& inImage, cv::Mat& outImage, cv::Size size);
|
bool bilinearResize(const cv::Mat& inImage, cv::Mat& outImage, cv::Size size);
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ static void sortIntoRemapMaps(const std::vector<DetectedPoint>& points, cv::Mat&
|
||||||
xMat = -1;
|
xMat = -1;
|
||||||
yMat = -1;
|
yMat = -1;
|
||||||
|
|
||||||
Log(Log::DEBUG)<<__func__<<"Grid: "<<xGridSize<<'x'<<yGridSize;
|
Log(Log::DEBUG)<<"Grid: "<<xGridSize<<'x'<<yGridSize;
|
||||||
|
|
||||||
for(int y = 0; y < xMat.rows; y++)
|
for(int y = 0; y < xMat.rows; y++)
|
||||||
{
|
{
|
||||||
|
@ -97,20 +97,22 @@ bool createRemapMap(const cv::Mat& image, RemapMap& out, const std::vector<Detec
|
||||||
Log(Log::DEBUG)<<__func__<<": xMat raw\n"<<out.xMat;
|
Log(Log::DEBUG)<<__func__<<": xMat raw\n"<<out.xMat;
|
||||||
|
|
||||||
int cols = out.xMat.cols;
|
int cols = out.xMat.cols;
|
||||||
removeSparseCols(out.xMat, 0.75,true);
|
removeSparseCols(out.xMat, true);
|
||||||
out.topLeftCoordinate.x += cols-out.xMat.cols;
|
out.topLeftCoordinate.x += cols-out.xMat.cols;
|
||||||
removeSparseCols(out.xMat, 0.75, false);
|
removeSparseCols(out.xMat, false);
|
||||||
removeSparseCols(out.yMat, 0.75, true);
|
removeSparseCols(out.yMat, true);
|
||||||
removeSparseCols(out.yMat, 0.75, false);
|
removeSparseCols(out.yMat, false);
|
||||||
Log(Log::DEBUG)<<__func__<<": xMat rejcted\n"<<out.xMat;
|
Log(Log::DEBUG)<<__func__<<": xMat rejcted\n"<<out.xMat;
|
||||||
|
fillMissing(out.xMat);
|
||||||
Log(Log::DEBUG)<<__func__<<": xMat filled\n"<<out.xMat;
|
Log(Log::DEBUG)<<__func__<<": xMat filled\n"<<out.xMat;
|
||||||
interpolateMissingOnY(out.xMat);
|
interpolateMissing(out.xMat);
|
||||||
interpolateMissingOnY(out.yMat);
|
interpolateMissing(out.yMat);
|
||||||
|
|
||||||
sanityCheckMap(out.xMat, 0, image.cols-1, -1, -1);
|
sanityCheckMap(out.xMat, 0, image.cols-1, -1, -1);
|
||||||
sanityCheckMap(out.yMat, 0, image.rows-1, -1, -1);
|
sanityCheckMap(out.yMat, 0, image.rows-1, -1, -1);
|
||||||
interpolateMissingOnY(out.xMat);
|
fillMissing(out.xMat);
|
||||||
interpolateMissingOnY(out.yMat);
|
interpolateMissing(out.xMat);
|
||||||
|
interpolateMissing(out.yMat);
|
||||||
sanityCheckMap(out.xMat, 0, image.cols-1, 0, image.cols-1);
|
sanityCheckMap(out.xMat, 0, image.cols-1, 0, image.cols-1);
|
||||||
sanityCheckMap(out.yMat, 0, image.rows-1, 0, image.rows-1);
|
sanityCheckMap(out.yMat, 0, image.rows-1, 0, image.rows-1);
|
||||||
|
|
||||||
|
@ -157,82 +159,17 @@ RemapMap loadRemapMap(const std::string& fileName)
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyKfactor(cv::Mat& image, const cv::Mat& angleMat, float kFactor)
|
|
||||||
{
|
|
||||||
assert(image.type() == CV_8UC1 && angleMat.type() == CV_32FC1);
|
|
||||||
for(int y = 0; y < image.rows; y++)
|
|
||||||
{
|
|
||||||
uint8_t* colx = image.ptr<uint8_t>(y);
|
|
||||||
const float* anglex = angleMat.ptr<float>(y);
|
|
||||||
for(int x = 0; x < image.cols; x++)
|
|
||||||
{
|
|
||||||
int value = colx[x]*(1-(anglex[x]*kFactor));
|
|
||||||
if(value < 0)
|
|
||||||
value = 0;
|
|
||||||
else if(value > 255)
|
|
||||||
value = 255;
|
|
||||||
colx[x] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void generateAngleMats(const cv::Mat& xMat, const cv::Mat& yMat, cv::Mat& greatestAngle)
|
|
||||||
{
|
|
||||||
std::cout<<xMat<<std::endl;
|
|
||||||
greatestAngle.create(xMat.rows-1, xMat.cols-1, CV_32FC1);
|
|
||||||
double max = 0;
|
|
||||||
for(int y = 0; y < xMat.rows-1; y++)
|
|
||||||
{
|
|
||||||
for(int x = 0; x < xMat.cols-1; x++)
|
|
||||||
{
|
|
||||||
cv::Point2f pA(xMat.at<float>(y,x), yMat.at<float>(y,x));
|
|
||||||
cv::Point2f pB(xMat.at<float>(y,x+1), yMat.at<float>(y,x+1));
|
|
||||||
cv::Point2f pC(xMat.at<float>(y+1,x), yMat.at<float>(y+1,x));
|
|
||||||
double normX = cv::norm(pA-pB);
|
|
||||||
double normY = cv::norm(pA-pC);
|
|
||||||
|
|
||||||
if(normX > max)
|
|
||||||
max = normX;
|
|
||||||
if(normY > max)
|
|
||||||
max = normY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int y = 0; y < xMat.rows-1; y++)
|
|
||||||
{
|
|
||||||
for(int x = 0; x < xMat.cols-1; x++)
|
|
||||||
{
|
|
||||||
cv::Point2f pA(xMat.at<float>(y,x), yMat.at<float>(y,x));
|
|
||||||
cv::Point2f pB(xMat.at<float>(y,x+1), yMat.at<float>(y,x+1));
|
|
||||||
cv::Point2f pC(xMat.at<float>(y+1,x), yMat.at<float>(y+1,x));
|
|
||||||
double normX = cv::norm(pA-pB);
|
|
||||||
double normY = cv::norm(pA-pC);
|
|
||||||
|
|
||||||
greatestAngle.at<float>(y,x) = 1-(std::min(normX, normY)/max);
|
|
||||||
|
|
||||||
if(y == 0)
|
|
||||||
Log(Log::DEBUG)<<greatestAngle.at<float>(y,x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RemapedImage applyRemap(const cv::Mat& image, const RemapMap &map)
|
RemapedImage applyRemap(const cv::Mat& image, const RemapMap &map)
|
||||||
{
|
{
|
||||||
RemapedImage out;
|
RemapedImage out;
|
||||||
cv::Mat xMapResized;
|
cv::Mat xMapResized;
|
||||||
cv::Mat yMapResized;
|
cv::Mat yMapResized;
|
||||||
const cv::Size outputSize(map.outputCellSize*map.xMat.cols,map.outputCellSize*map.xMat.rows);
|
const cv::Size outputSize(map.outputCellSize*map.xMat.cols,map.outputCellSize*map.xMat.rows);
|
||||||
cv::Rect noBorderRoi(map.outputCellSize/2, map.outputCellSize/2,
|
|
||||||
outputSize.width-map.outputCellSize, outputSize.height-map.outputCellSize);
|
|
||||||
|
|
||||||
generateAngleMats(map.xMat, map.yMat, out.angle);
|
|
||||||
cv::Mat angleResized;
|
|
||||||
cv::resize(out.angle, angleResized, outputSize, cv::INTER_LINEAR);
|
|
||||||
out.angle = angleResized(noBorderRoi);
|
|
||||||
|
|
||||||
cv::resize(map.xMat, xMapResized, outputSize, cv::INTER_LINEAR);
|
cv::resize(map.xMat, xMapResized, outputSize, cv::INTER_LINEAR);
|
||||||
cv::resize(map.yMat, yMapResized, outputSize, cv::INTER_LINEAR);
|
cv::resize(map.yMat, yMapResized, outputSize, cv::INTER_LINEAR);
|
||||||
|
cv::Rect noBorderRoi(map.outputCellSize/2, map.outputCellSize/2,
|
||||||
|
outputSize.width-map.outputCellSize, outputSize.height-map.outputCellSize);
|
||||||
cv::Mat xMapRed = xMapResized(noBorderRoi);
|
cv::Mat xMapRed = xMapResized(noBorderRoi);
|
||||||
cv::Mat yMapRed = yMapResized(noBorderRoi);
|
cv::Mat yMapRed = yMapResized(noBorderRoi);
|
||||||
cv::remap(image, out.image, xMapRed, yMapRed, cv::INTER_LINEAR);
|
cv::remap(image, out.image, xMapRed, yMapRed, cv::INTER_LINEAR);
|
||||||
|
@ -261,10 +198,10 @@ cv::Mat simpleStich(const std::vector<RemapedImage>& images)
|
||||||
if(topLeft.y > image.origin.y)
|
if(topLeft.y > image.origin.y)
|
||||||
topLeft.y = image.origin.y;
|
topLeft.y = image.origin.y;
|
||||||
|
|
||||||
Log(Log::DEBUG)<<__func__<<"image: "<<image.image.rows<<'x'<<image.image.cols<<" at "<<image.origin.x<<'x'<<image.origin.y;
|
Log(Log::DEBUG)<<"image: "<<image.image.rows<<'x'<<image.image.cols<<" at "<<image.origin.x<<'x'<<image.origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(Log::DEBUG)<<__func__<<"outputSize: "<<outputSize;
|
Log(Log::DEBUG)<<"outputSize: "<<outputSize;
|
||||||
|
|
||||||
cv::Mat out(outputSize, images[0].image.type(), cv::Scalar::all(0));
|
cv::Mat out(outputSize, images[0].image.type(), cv::Scalar::all(0));
|
||||||
|
|
||||||
|
@ -282,13 +219,9 @@ cv::Mat simpleStich(const std::vector<RemapedImage>& images)
|
||||||
|
|
||||||
cv::Mat stich(std::vector<RemapedImage>& images, bool seamAdjust)
|
cv::Mat stich(std::vector<RemapedImage>& images, bool seamAdjust)
|
||||||
{
|
{
|
||||||
assert(images.size() > 0);
|
|
||||||
|
|
||||||
for(auto& image : images)
|
for(auto& image : images)
|
||||||
assert(image.image.type() == CV_8UC3 || image.image.type() == CV_8UC1);
|
assert(image.image.type() == CV_8UC3 || image.image.type() == CV_8UC1);
|
||||||
|
|
||||||
Log(Log::DEBUG)<<__func__<<" got "<<images.size()<<" of type "<<images[0].image.type()<<" size "<<images[0].image.size();
|
|
||||||
|
|
||||||
for(auto& image : images)
|
for(auto& image : images)
|
||||||
{
|
{
|
||||||
if(image.image.type() == CV_8UC1)
|
if(image.image.type() == CV_8UC1)
|
||||||
|
|
|
@ -23,9 +23,6 @@
|
||||||
#include <opencv2/core/ocl.hpp>
|
#include <opencv2/core/ocl.hpp>
|
||||||
#include "detectedpoint.h"
|
#include "detectedpoint.h"
|
||||||
|
|
||||||
static constexpr unsigned int X_BOARD_SIZE = 20;
|
|
||||||
static constexpr unsigned int Y_BOARD_SIZE = 12;
|
|
||||||
|
|
||||||
void createCharucoBoard(unsigned int size, const std::string& fileName);
|
void createCharucoBoard(unsigned int size, const std::string& fileName);
|
||||||
|
|
||||||
std::vector<DetectedPoint> detectCharucoPoints(cv::Mat image, bool verbose = true);
|
std::vector<DetectedPoint> detectCharucoPoints(cv::Mat image, bool verbose = true);
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
struct RemapedImage
|
struct RemapedImage
|
||||||
{
|
{
|
||||||
cv::Mat image;
|
cv::Mat image;
|
||||||
cv::Mat angle;
|
|
||||||
cv::Point2i origin;
|
cv::Point2i origin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +44,5 @@ bool createRemapMap(const cv::Mat& image, RemapMap& out, const std::vector<Detec
|
||||||
|
|
||||||
RemapedImage applyRemap(const cv::Mat& image, const RemapMap &map);
|
RemapedImage applyRemap(const cv::Mat& image, const RemapMap &map);
|
||||||
|
|
||||||
void applyKfactor(cv::Mat& image ,const cv::Mat& angleMat, float kFactor);
|
|
||||||
|
|
||||||
cv::Mat stich(std::vector<RemapedImage>& images, bool seamAdjust = false);
|
cv::Mat stich(std::vector<RemapedImage>& images, bool seamAdjust = false);
|
||||||
cv::Mat simpleStich(const std::vector<RemapedImage>& images);
|
cv::Mat simpleStich(const std::vector<RemapedImage>& images);
|
||||||
|
|
Loading…
Reference in a new issue