add charuco point detection method

This commit is contained in:
2020-11-10 02:05:51 +01:00
parent 38680f029c
commit d4d7418cb2
8 changed files with 301 additions and 132 deletions

View File

@ -5,7 +5,6 @@
#include <math.h>
#include <vector>
#include <algorithm>
#include <opencv2/features2d.hpp>
#include <iostream>
#include "matutils.h"
@ -29,7 +28,7 @@ static std::vector< std::vector<cv::Point2f > > sortPointsIntoRows(std::vector<c
Log(Log::DEBUG)<<"topLeft "<<topLeft.x<<' '<<topLeft.y;
Log(Log::DEBUG)<<"bottomRight "<<bottomRight.x<<' '<<bottomRight.y;
float fuzz = (bottomRight.x-topLeft.x)*0.01f;
float fuzz = (bottomRight.x-topLeft.x)*0.05f;
for(size_t i = 0; i < points.size(); ++i)
{
@ -352,115 +351,145 @@ static void generateRemapMaps(const DisplacmentMap& map, cv::Mat& xMat, cv::Mat&
Log(Log::INFO)<<__func__<<": yMat \n"<<yMat;
}
static std::vector<cv::Point2f> detectPoints(cv::Mat& image, const cv::Mat& mask,
int blockSize = 5, int apature = 5, float detectorParameter = 0.01,
float minSize = 7, bool verbose = false)
static void generateRemapMaps(const std::vector<cv::Point2f>& points, const std::vector<cv::Point2i>& coordinates, cv::Mat& xMat, cv::Mat& yMat)
{
cv::Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
//detect corners
cv::Mat corners;
cv::cornerHarris(gray, corners, blockSize, apature, detectorParameter);
cv::normalize(corners, corners, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs( corners, corners );
cv::threshold(corners, corners, 50, 255, cv::THRESH_BINARY);
cv::Mat cornersMasked;
if(mask.size == corners.size) corners.copyTo(cornersMasked, mask);
else corners.copyTo(cornersMasked);
if(verbose)
if(points.size() < 6 || coordinates.size() != points.size())
{
cv::imshow( "Viewer", cornersMasked );
cv::waitKey(0);
Log(Log::ERROR)<<__func__<<": at least 6 points are needed";
return;
}
//get middle of corners
cv::SimpleBlobDetector::Params blobParams;
blobParams.filterByArea = true;
blobParams.minArea = minSize;
blobParams.maxArea = 500;
blobParams.filterByColor = false;
blobParams.blobColor = 255;
blobParams.filterByInertia = false;
blobParams.filterByConvexity = false;
cv::Ptr<cv::SimpleBlobDetector> blobDetector = cv::SimpleBlobDetector::create(blobParams);
std::vector<cv::KeyPoint> keypoints;
blobDetector->detect(cornersMasked, keypoints);
int xMin = std::numeric_limits<int>::max();
int xMax = std::numeric_limits<int>::min();
int yMin = std::numeric_limits<int>::max();
int yMax = std::numeric_limits<int>::min();
std::vector<cv::Point2f> points;
cv::KeyPoint::convert(keypoints, points);
for(auto& point : coordinates)
{
Log(Log::DEBUG)<<"point: "<<point.x<<'x'<<point.y;
if(point.x > 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;
}
return points;
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: "<<xGridSize<<'x'<<yGridSize;
for(int y = 0; y < xMat.rows; y++)
{
float* colx = xMat.ptr<float>(y);
float* coly = yMat.ptr<float>(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"<<xMat;
removeSparseCollums(xMat);
removeSparseCollums(yMat);
Log(Log::DEBUG)<<__func__<<": xMat rejcted\n"<<xMat;
fillMissing(xMat);
Log(Log::DEBUG)<<__func__<<": xMat filled\n"<<xMat;
interpolateMissing(xMat);
Log(Log::DEBUG)<<__func__<<": yMat raw \n"<<yMat;
interpolateMissing(yMat);
Log(Log::INFO)<<__func__<<": xMat \n"<<xMat;
Log(Log::INFO)<<__func__<<": yMat \n"<<yMat;
}
bool createRemapMap(cv::Mat& image, const std::string& fileName, const cv::Mat& mask,
int blockSize, int apature, float detectorParameter, float minSize,
bool verbose)
bool createRemapMap(cv::Mat& image, std::vector<cv::Point2f> points, const std::vector<cv::Point2i>& coordinates,
const std::string& fileName, bool verbose)
{
std::vector<cv::Point2f > points = detectPoints(image, mask, blockSize, apature, detectorParameter, minSize, verbose);
if(verbose) std::cout<<"Found "<<points.size()<<" points\n";
if(points.size() < 8)
{
Log(Log::ERROR)<<"Error creating map, insufficant points detected";
return false;
}
std::vector< std::vector<cv::Point2f > > rows = sortPointsIntoRows(points);
if(verbose) std::cout<<"Found "<<rows.size()<<" rows\n";
if(rows.size() < 2)
{
Log(Log::ERROR)<<"Error creating map, insufficant rows detected";
return false;
}
std::vector< cv::RotatedRect > ellipses = fitEllipses(rows);
if(verbose) Log(Log::INFO)<<"Found "<<ellipses.size()<<" ellipses. rows reduced to "<<rows.size();
if(ellipses.size() < 3)
{
Log(Log::ERROR)<<"Error creating map, insufficant ellipses detected";
return false;
}
if(verbose)
{
cv::Mat pointsMat = cv::Mat::zeros(image.size(), CV_8UC3);
drawRows(pointsMat, rows);
drawEllipses(pointsMat, ellipses);
cv::imshow( "Viewer", pointsMat );
cv::waitKey(0);
}
sanityCheckElipses(rows, ellipses);
if(verbose)
{
cv::Mat pointsMat = cv::Mat::zeros(image.size(), CV_8UC3);
drawRows(pointsMat, rows);
drawEllipses(pointsMat, ellipses);
cv::imshow( "Viewer", pointsMat );
cv::waitKey(0);
}
DisplacmentMap dispMap = calcDisplacementMap(rows, ellipses);
if(dispMap.destination.size() < 2)
{
Log(Log::ERROR)<<"Error creating map, unable to calculate destination points";
return false;
}
cv::Mat dispPointsDest = cv::Mat::zeros(cv::Size(cv::Size(1000,1000)), CV_8UC3);
drawRows(dispPointsDest, dispMap.destination);
if(verbose)
{
cv::imshow( "Viewer", dispPointsDest );
cv::waitKey(0);
}
cv::Mat xMat;
cv::Mat yMat;
generateRemapMaps(dispMap, xMat, yMat);
if(coordinates.empty())
{
std::vector< std::vector<cv::Point2f > > rows = sortPointsIntoRows(points);
Log(Log::INFO)<<"Found "<<rows.size()<<" rows";
if(rows.size() < 2)
{
Log(Log::ERROR)<<"Error creating map, insufficant rows detected";
return false;
}
if(verbose)
{
cv::Mat pointsMat = cv::Mat::zeros(image.size(), CV_8UC3);
drawRows(pointsMat, rows);
cv::imshow( "Viewer", pointsMat );
cv::waitKey(0);
}
std::vector< cv::RotatedRect > ellipses = fitEllipses(rows);
Log(Log::INFO)<<"Found "<<ellipses.size()<<" ellipses. rows reduced to "<<rows.size();
if(ellipses.size() < 3)
{
Log(Log::ERROR)<<"Error creating map, insufficant ellipses detected";
return false;
}
if(verbose)
{
cv::Mat pointsMat = cv::Mat::zeros(image.size(), CV_8UC3);
drawRows(pointsMat, rows);
drawEllipses(pointsMat, ellipses);
cv::imshow( "Viewer", pointsMat );
cv::waitKey(0);
}
sanityCheckElipses(rows, ellipses);
if(verbose)
{
cv::Mat pointsMat = cv::Mat::zeros(image.size(), CV_8UC3);
drawRows(pointsMat, rows);
drawEllipses(pointsMat, ellipses);
cv::imshow( "Viewer", pointsMat );
cv::waitKey(0);
}
DisplacmentMap dispMap = calcDisplacementMap(rows, ellipses);
if(dispMap.destination.size() < 2)
{
Log(Log::ERROR)<<"Error creating map, unable to calculate destination points";
return false;
}
cv::Mat dispPointsDest = cv::Mat::zeros(cv::Size(cv::Size(1000,1000)), CV_8UC3);
drawRows(dispPointsDest, dispMap.destination);
if(verbose)
{
cv::imshow( "Viewer", dispPointsDest );
cv::waitKey(0);
}
generateRemapMaps(dispMap, xMat, yMat);
}
else
{
generateRemapMaps(points, coordinates, xMat, yMat);
}
sanityCheckMap(xMat, 0, image.cols-1, -1, -1);
sanityCheckMap(yMat, 0, image.rows-1, -1, -1);
fillMissing(xMat);
@ -525,7 +554,7 @@ void applyRemap(cv::Mat& image, cv::Mat& out, const cv::Mat& xmap, const cv::Mat
cv::Rect roi;
cv::Mat xMapRed;
cv::Mat yMapRed;
if(findDeadSpace(xMapResized, roi))
if(!findDeadSpace(xMapResized, roi))
{
xMapRed = xMapResized(roi);
yMapRed = yMapResized(roi);