Compare commits

...

10 commits

8 changed files with 246 additions and 101 deletions

View file

@ -35,12 +35,13 @@ 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"; Possible operations: apply create curve mkcurve mkboard show";
static char args_doc[] = "[OPERATION] IMAGE1 IMAGE2 ..."; static char args_doc[] = "[OPERATION] IMAGE1 IMAGE2 ...";
static struct argp_option options[] = static struct argp_option options[] =
@ -56,6 +57,7 @@ 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 }
}; };
@ -78,7 +80,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=atol(arg); config->minSize=strtod(arg, nullptr);
break; break;
case 'r': case 'r':
config->harris = true; config->harris = true;
@ -98,6 +100,9 @@ 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;

View file

@ -20,19 +20,76 @@
#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;
board->draw(cv::Size((size*18)/10, size), charucoImage, 0, 1); double cellSize = size/(double)Y_BOARD_SIZE;
cv::imwrite(fileName, charucoImage); board->draw(cv::Size((size*X_BOARD_SIZE)/Y_BOARD_SIZE, size), charucoImage, 0, 1);
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)
@ -86,6 +143,8 @@ 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>();

View file

@ -42,6 +42,7 @@ enum {
APPLY_MAP, APPLY_MAP,
APPLY_CURVE, APPLY_CURVE,
CREATE_CURVE, CREATE_CURVE,
SHOW_IMAGE,
EXIT EXIT
}; };
@ -59,6 +60,8 @@ 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;
@ -92,7 +95,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 || image.type() != CV_32FC1)) if(matf.isOpened() && !image.data)
{ {
Log(Log::WARN)<<fileName<<" dose not contain a valid image"; Log(Log::WARN)<<fileName<<" dose not contain a valid image";
matf.release(); matf.release();
@ -115,13 +118,19 @@ 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]); {
else Log(Log::DEBUG)<<__func__<<": "<<fileNames[i]<<" as YAML image";
tmpImage = openImageImg(fileNames[i]); tmpImage = openImageYml(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]<<'\n'; Log(Log::WARN)<<"can not read image "<<i<<" from "<<fileNames[i];
} }
return images; return images;
} }
@ -129,7 +138,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) if(operation == CREATE_MAP || operation == APPLY_MAP || operation == APPLY_CURVE || operation == SHOW_IMAGE)
{ {
inImages = loadImages(fileNames); inImages = loadImages(fileNames);
@ -143,7 +152,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*14, fileName); createCharucoBoard(config.size*X_BOARD_SIZE, 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;
} }
@ -202,7 +211,10 @@ 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())
@ -210,7 +222,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)
@ -230,6 +242,15 @@ 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);
@ -261,17 +282,23 @@ 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["curve"]>>curve; fs["cal"]>>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;
} }
cvtColor(inImages[0], inImages[0], cv::COLOR_BGR2GRAY); if(inImages[0].channels() > 1)
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)
{ {
@ -323,6 +350,16 @@ 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;

View file

@ -178,7 +178,7 @@ bool findClosest(size_t& index, const cv::Point2f point, const std::vector<cv::P
return found; return found;
} }
void interpolateMissing(cv::Mat& mat) void interpolateMissingOnX(cv::Mat& mat)
{ {
assert(mat.type() == CV_32FC1); assert(mat.type() == CV_32FC1);
@ -223,34 +223,48 @@ void interpolateMissing(cv::Mat& mat)
} }
} }
void fillMissing(cv::Mat& mat) void interpolateMissingOnY(cv::Mat& mat)
{ {
assert(mat.type() == CV_32FC1); assert(mat.type() == CV_32FC1);
bool finished = true; for(int x = 0; x < mat.cols; ++x)
for(int y = 0; y < mat.rows; y++)
{ {
float* col = mat.ptr<float>(y); for(int y = 0; y < mat.rows; y++)
for(int x = 0; x < mat.cols; ++x)
{ {
if(col[x] < 0 && col[x] > -2) if(mat.at<float>(y,x) < 0)
{ {
if(y > 0 && mat.at<float>(y-1,x) >= 0) int closestA = -1;
int closestB = -1;
int dist = std::numeric_limits<int>::max();
for(int i = 0; i < mat.rows; i++)
{ {
col[x] = mat.at<float>(y-1,x); if(i != closestA && mat.at<float>(i,x) >= 0 && abs(i-y) <= dist)
finished = false; {
closestB = closestA;
closestA = i;
dist = abs(i-y);
}
} }
else if(y < mat.rows-1 && mat.at<float>(y+1,x) >= 0) if(closestA < 0 || closestB < 0)
{ {
col[x] = mat.at<float>(y+1,x); closestA = -1;
finished = false; closestB = -1;
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);
}
}
} }
if(col[x] > 0 && ((x+1 < mat.cols && col[x] > col[x+1]) || (x > 0 && col[x] < col[x-1]))) float slope = (mat.at<float>(closestB,x) - mat.at<float>(closestA,x))/(closestB-closestA);
col[x] = -2; mat.at<float>(y,x) = mat.at<float>(closestA,x) - (closestA-y)*slope;
} }
} }
} }
if(!finished) fillMissing(mat);
} }
bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi) bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi)
@ -287,66 +301,25 @@ bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi)
return true; return true;
} }
bool deleteEmptyCols(cv::Mat& mat) void removeSparseCols(cv::Mat& mat, float reject, bool front)
{
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) ++count; if((front && mat.at<float>(y,0) >= 0) || (!front && mat.at<float>(y,mat.cols-1) >= 0))
else if(mat.at<float>(y,mat.cols-1) >= 0) ++count; ++count;
} }
cv::Rect roi; cv::Rect roi;
bool rej = (count < mat.rows/2); bool rej = (count < mat.rows*reject);
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, front); removeSparseCols(mat, reject, front);
} }
static float linInterpolate(float A, float B, float x) static float linInterpolate(float A, float B, float x)

View file

@ -37,15 +37,13 @@ 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 interpolateMissing(cv::Mat& mat); void interpolateMissingOnX(cv::Mat& mat);
void fillMissing(cv::Mat& mat); void interpolateMissingOnY(cv::Mat& mat);
bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi); bool findDeadSpace(const cv::Mat& mat, cv::Rect& roi);
bool deleteEmptyCols(cv::Mat& mat); void removeSparseCols(cv::Mat& mat, float reject, bool front);
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);

View file

@ -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)<<"Grid: "<<xGridSize<<'x'<<yGridSize; Log(Log::DEBUG)<<__func__<<"Grid: "<<xGridSize<<'x'<<yGridSize;
for(int y = 0; y < xMat.rows; y++) for(int y = 0; y < xMat.rows; y++)
{ {
@ -97,22 +97,20 @@ 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, true); removeSparseCols(out.xMat, 0.75,true);
out.topLeftCoordinate.x += cols-out.xMat.cols; out.topLeftCoordinate.x += cols-out.xMat.cols;
removeSparseCols(out.xMat, false); removeSparseCols(out.xMat, 0.75, false);
removeSparseCols(out.yMat, true); removeSparseCols(out.yMat, 0.75, true);
removeSparseCols(out.yMat, false); removeSparseCols(out.yMat, 0.75, 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;
interpolateMissing(out.xMat); interpolateMissingOnY(out.xMat);
interpolateMissing(out.yMat); interpolateMissingOnY(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);
fillMissing(out.xMat); interpolateMissingOnY(out.xMat);
interpolateMissing(out.xMat); interpolateMissingOnY(out.yMat);
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);
@ -159,17 +157,82 @@ 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);
@ -198,10 +261,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)<<"image: "<<image.image.rows<<'x'<<image.image.cols<<" at "<<image.origin.x<<'x'<<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)<<"outputSize: "<<outputSize; Log(Log::DEBUG)<<__func__<<"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));
@ -219,9 +282,13 @@ 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)

View file

@ -23,6 +23,9 @@
#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);

View file

@ -25,6 +25,7 @@
struct RemapedImage struct RemapedImage
{ {
cv::Mat image; cv::Mat image;
cv::Mat angle;
cv::Point2i origin; cv::Point2i origin;
}; };
@ -44,5 +45,7 @@ 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);