mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge branch 4.x
This commit is contained in:
@@ -27,17 +27,17 @@ struct Board::Impl {
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
virtual void matchImagePoints(InputArray detectedCorners, InputArray detectedIds, OutputArray _objPoints,
|
||||
virtual void matchImagePoints(InputArrayOfArrays detectedCorners, InputArray detectedIds, OutputArray _objPoints,
|
||||
OutputArray imgPoints) const;
|
||||
|
||||
virtual void generateImage(Size outSize, OutputArray img, int marginSize, int borderBits) const;
|
||||
};
|
||||
|
||||
void Board::Impl::matchImagePoints(InputArray detectedCorners, InputArray detectedIds, OutputArray _objPoints,
|
||||
OutputArray imgPoints) const {
|
||||
|
||||
CV_Assert(ids.size() == objPoints.size());
|
||||
void Board::Impl::matchImagePoints(InputArrayOfArrays detectedCorners, InputArray detectedIds, OutputArray _objPoints,
|
||||
OutputArray imgPoints) const {
|
||||
CV_Assert(detectedIds.total() == detectedCorners.total());
|
||||
CV_Assert(detectedIds.total() > 0ull);
|
||||
CV_Assert(detectedCorners.depth() == CV_32F);
|
||||
|
||||
size_t nDetectedMarkers = detectedIds.total();
|
||||
|
||||
@@ -48,13 +48,19 @@ void Board::Impl::matchImagePoints(InputArray detectedCorners, InputArray detect
|
||||
imgPnts.reserve(nDetectedMarkers);
|
||||
|
||||
// look for detected markers that belong to the board and get their information
|
||||
Mat detectedIdsMat = detectedIds.getMat();
|
||||
vector<Mat> detectedCornersVecMat;
|
||||
|
||||
detectedCorners.getMatVector(detectedCornersVecMat);
|
||||
CV_Assert((int)detectedCornersVecMat.front().total()*detectedCornersVecMat.front().channels() == 8);
|
||||
|
||||
for(unsigned int i = 0; i < nDetectedMarkers; i++) {
|
||||
int currentId = detectedIds.getMat().ptr< int >(0)[i];
|
||||
int currentId = detectedIdsMat.at<int>(i);
|
||||
for(unsigned int j = 0; j < ids.size(); j++) {
|
||||
if(currentId == ids[j]) {
|
||||
for(int p = 0; p < 4; p++) {
|
||||
objPnts.push_back(objPoints[j][p]);
|
||||
imgPnts.push_back(detectedCorners.getMat(i).ptr<Point2f>(0)[p]);
|
||||
imgPnts.push_back(detectedCornersVecMat[i].ptr<Point2f>(0)[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,7 +163,6 @@ Board::Board():
|
||||
|
||||
Board::Board(InputArrayOfArrays objPoints, const Dictionary &dictionary, InputArray ids):
|
||||
Board(new Board::Impl(dictionary)) {
|
||||
CV_Assert(ids.size() == objPoints.size());
|
||||
CV_Assert(objPoints.total() == ids.total());
|
||||
CV_Assert(objPoints.type() == CV_32FC3 || objPoints.type() == CV_32FC1);
|
||||
|
||||
@@ -213,7 +218,7 @@ void Board::generateImage(Size outSize, OutputArray img, int marginSize, int bor
|
||||
impl->generateImage(outSize, img, marginSize, borderBits);
|
||||
}
|
||||
|
||||
void Board::matchImagePoints(InputArray detectedCorners, InputArray detectedIds, OutputArray objPoints,
|
||||
void Board::matchImagePoints(InputArrayOfArrays detectedCorners, InputArray detectedIds, OutputArray objPoints,
|
||||
OutputArray imgPoints) const {
|
||||
CV_Assert(this->impl);
|
||||
impl->matchImagePoints(detectedCorners, detectedIds, objPoints, imgPoints);
|
||||
@@ -224,7 +229,8 @@ struct GridBoardImpl : public Board::Impl {
|
||||
Board::Impl(_dictionary),
|
||||
size(_size),
|
||||
markerLength(_markerLength),
|
||||
markerSeparation(_markerSeparation)
|
||||
markerSeparation(_markerSeparation),
|
||||
legacyPattern(false)
|
||||
{
|
||||
CV_Assert(size.width*size.height > 0 && markerLength > 0 && markerSeparation > 0);
|
||||
}
|
||||
@@ -235,6 +241,8 @@ struct GridBoardImpl : public Board::Impl {
|
||||
float markerLength;
|
||||
// separation between markers in the grid
|
||||
float markerSeparation;
|
||||
// set pre4.6.0 chessboard pattern behavior (even row count patterns have a white box in the upper left corner)
|
||||
bool legacyPattern;
|
||||
};
|
||||
|
||||
GridBoard::GridBoard() {}
|
||||
@@ -292,7 +300,8 @@ struct CharucoBoardImpl : Board::Impl {
|
||||
Board::Impl(_dictionary),
|
||||
size(_size),
|
||||
squareLength(_squareLength),
|
||||
markerLength(_markerLength)
|
||||
markerLength(_markerLength),
|
||||
legacyPattern(false)
|
||||
{}
|
||||
|
||||
// chessboard size
|
||||
@@ -304,6 +313,9 @@ struct CharucoBoardImpl : Board::Impl {
|
||||
// Physical marker side length (normally in meters)
|
||||
float markerLength;
|
||||
|
||||
// set pre4.6.0 chessboard pattern behavior (even row count patterns have a white box in the upper left corner)
|
||||
bool legacyPattern;
|
||||
|
||||
// vector of chessboard 3D corners precalculated
|
||||
std::vector<Point3f> chessboardCorners;
|
||||
|
||||
@@ -311,16 +323,65 @@ struct CharucoBoardImpl : Board::Impl {
|
||||
std::vector<std::vector<int> > nearestMarkerIdx;
|
||||
std::vector<std::vector<int> > nearestMarkerCorners;
|
||||
|
||||
void createCharucoBoard();
|
||||
void calcNearestMarkerCorners();
|
||||
|
||||
void matchImagePoints(InputArrayOfArrays detectedCorners, InputArray detectedIds,
|
||||
void matchImagePoints(InputArrayOfArrays detectedCharuco, InputArray detectedIds,
|
||||
OutputArray objPoints, OutputArray imgPoints) const override;
|
||||
|
||||
void generateImage(Size outSize, OutputArray img, int marginSize, int borderBits) const override;
|
||||
};
|
||||
|
||||
void CharucoBoardImpl::createCharucoBoard() {
|
||||
float diffSquareMarkerLength = (squareLength - markerLength) / 2;
|
||||
int totalMarkers = (int)(ids.size());
|
||||
// calculate Board objPoints
|
||||
int nextId = 0;
|
||||
objPoints.clear();
|
||||
for(int y = 0; y < size.height; y++) {
|
||||
for(int x = 0; x < size.width; x++) {
|
||||
|
||||
if(legacyPattern && (size.height % 2 == 0)) { // legacy behavior only for even row count patterns
|
||||
if((y + 1) % 2 == x % 2) continue; // black corner, no marker here
|
||||
} else {
|
||||
if(y % 2 == x % 2) continue; // black corner, no marker here
|
||||
}
|
||||
|
||||
vector<Point3f> corners(4);
|
||||
corners[0] = Point3f(x * squareLength + diffSquareMarkerLength,
|
||||
y * squareLength + diffSquareMarkerLength, 0);
|
||||
corners[1] = corners[0] + Point3f(markerLength, 0, 0);
|
||||
corners[2] = corners[0] + Point3f(markerLength, markerLength, 0);
|
||||
corners[3] = corners[0] + Point3f(0, markerLength, 0);
|
||||
objPoints.push_back(corners);
|
||||
// first ids in dictionary
|
||||
if (totalMarkers == 0)
|
||||
ids.push_back(nextId);
|
||||
nextId++;
|
||||
}
|
||||
}
|
||||
if (totalMarkers > 0 && nextId != totalMarkers)
|
||||
CV_Error(cv::Error::StsBadSize, "Size of ids must be equal to the number of markers: "+std::to_string(nextId));
|
||||
|
||||
// now fill chessboardCorners
|
||||
chessboardCorners.clear();
|
||||
for(int y = 0; y < size.height - 1; y++) {
|
||||
for(int x = 0; x < size.width - 1; x++) {
|
||||
Point3f corner;
|
||||
corner.x = (x + 1) * squareLength;
|
||||
corner.y = (y + 1) * squareLength;
|
||||
corner.z = 0;
|
||||
chessboardCorners.push_back(corner);
|
||||
}
|
||||
}
|
||||
rightBottomBorder = Point3f(size.width * squareLength, size.height * squareLength, 0.f);
|
||||
calcNearestMarkerCorners();
|
||||
}
|
||||
|
||||
/** Fill nearestMarkerIdx and nearestMarkerCorners arrays */
|
||||
void CharucoBoardImpl::calcNearestMarkerCorners() {
|
||||
nearestMarkerIdx.clear();
|
||||
nearestMarkerCorners.clear();
|
||||
nearestMarkerIdx.resize(chessboardCorners.size());
|
||||
nearestMarkerCorners.resize(chessboardCorners.size());
|
||||
unsigned int nMarkers = (unsigned int)objPoints.size();
|
||||
@@ -368,25 +429,42 @@ void CharucoBoardImpl::calcNearestMarkerCorners() {
|
||||
}
|
||||
}
|
||||
|
||||
void CharucoBoardImpl::matchImagePoints(InputArrayOfArrays detectedCorners, InputArray detectedIds,
|
||||
OutputArray _objPoints, OutputArray imgPoints) const {
|
||||
if (detectedCorners.kind() == _InputArray::STD_VECTOR_VECTOR ||
|
||||
detectedCorners.isMatVector() || detectedCorners.isUMatVector())
|
||||
Board::Impl::matchImagePoints(detectedCorners, detectedIds, _objPoints, imgPoints);
|
||||
else {
|
||||
CV_Assert(detectedCorners.isMat() || detectedCorners.isVector());
|
||||
size_t nDetected = detectedCorners.total();
|
||||
vector<Point3f> objPnts(nDetected);
|
||||
vector<Point2f> imgPnts(nDetected);
|
||||
for(size_t i = 0ull; i < nDetected; i++) {
|
||||
int pointId = detectedIds.getMat().at<int>((int)i);
|
||||
CV_Assert(pointId >= 0 && pointId < (int)chessboardCorners.size());
|
||||
objPnts[i] = chessboardCorners[pointId];
|
||||
imgPnts[i] = detectedCorners.getMat().at<Point2f>((int)i);
|
||||
}
|
||||
Mat(objPnts).copyTo(_objPoints);
|
||||
Mat(imgPnts).copyTo(imgPoints);
|
||||
void CharucoBoardImpl::matchImagePoints(InputArrayOfArrays detectedCharuco, InputArray detectedIds,
|
||||
OutputArray outObjPoints, OutputArray outImgPoints) const {
|
||||
CV_CheckEQ(detectedIds.total(), detectedCharuco.total(), "Number of corners and ids must be equal");
|
||||
CV_Assert(detectedIds.total() > 0ull);
|
||||
CV_Assert(detectedCharuco.depth() == CV_32F);
|
||||
// detectedCharuco includes charuco corners as vector<Point2f> or Mat.
|
||||
// Python bindings could add extra dimension to detectedCharuco and therefore vector<Mat> case is additionally processed.
|
||||
CV_Assert((detectedCharuco.isMat() || detectedCharuco.isVector() || detectedCharuco.isMatVector() || detectedCharuco.isUMatVector())
|
||||
&& detectedCharuco.depth() == CV_32F);
|
||||
size_t nDetected = detectedCharuco.total();
|
||||
vector<Point3f> objPnts(nDetected);
|
||||
vector<Point2f> imgPnts(nDetected);
|
||||
Mat detectedCharucoMat, detectedIdsMat = detectedIds.getMat();
|
||||
if (!detectedCharuco.isMatVector()) {
|
||||
detectedCharucoMat = detectedCharuco.getMat();
|
||||
CV_Assert(detectedCharucoMat.checkVector(2));
|
||||
}
|
||||
|
||||
std::vector<Mat> detectedCharucoVecMat;
|
||||
if (detectedCharuco.isMatVector()) {
|
||||
detectedCharuco.getMatVector(detectedCharucoVecMat);
|
||||
}
|
||||
|
||||
for(size_t i = 0ull; i < nDetected; i++) {
|
||||
int pointId = detectedIdsMat.at<int>((int)i);
|
||||
CV_Assert(pointId >= 0 && pointId < (int)chessboardCorners.size());
|
||||
objPnts[i] = chessboardCorners[pointId];
|
||||
if (detectedCharuco.isMatVector()) {
|
||||
CV_Assert((int)detectedCharucoVecMat[i].total() * detectedCharucoVecMat[i].channels() == 2);
|
||||
imgPnts[i] = detectedCharucoVecMat[i].ptr<Point2f>(0)[0];
|
||||
}
|
||||
else
|
||||
imgPnts[i] = detectedCharucoMat.ptr<Point2f>(0)[i];
|
||||
}
|
||||
Mat(objPnts).copyTo(outObjPoints);
|
||||
Mat(imgPnts).copyTo(outImgPoints);
|
||||
}
|
||||
|
||||
void CharucoBoardImpl::generateImage(Size outSize, OutputArray img, int marginSize, int borderBits) const {
|
||||
@@ -437,7 +515,11 @@ void CharucoBoardImpl::generateImage(Size outSize, OutputArray img, int marginSi
|
||||
for(int y = 0; y < size.height; y++) {
|
||||
for(int x = 0; x < size.width; x++) {
|
||||
|
||||
if(y % 2 != x % 2) continue; // white corner, dont do anything
|
||||
if(legacyPattern && (size.height % 2 == 0)) { // legacy behavior only for even row count patterns
|
||||
if((y + 1) % 2 != x % 2) continue; // white corner, dont do anything
|
||||
} else {
|
||||
if(y % 2 != x % 2) continue; // white corner, dont do anything
|
||||
}
|
||||
|
||||
double startX, startY;
|
||||
startX = squareSizePixels * double(x);
|
||||
@@ -459,47 +541,9 @@ CharucoBoard::CharucoBoard(const Size& size, float squareLength, float markerLen
|
||||
|
||||
CV_Assert(size.width > 1 && size.height > 1 && markerLength > 0 && squareLength > markerLength);
|
||||
|
||||
vector<vector<Point3f> > objPoints;
|
||||
float diffSquareMarkerLength = (squareLength - markerLength) / 2;
|
||||
int totalMarkers = (int)(ids.total());
|
||||
ids.copyTo(impl->ids);
|
||||
// calculate Board objPoints
|
||||
int nextId = 0;
|
||||
for(int y = 0; y < size.height; y++) {
|
||||
for(int x = 0; x < size.width; x++) {
|
||||
|
||||
if(y % 2 == x % 2) continue; // black corner, no marker here
|
||||
|
||||
vector<Point3f> corners(4);
|
||||
corners[0] = Point3f(x * squareLength + diffSquareMarkerLength,
|
||||
y * squareLength + diffSquareMarkerLength, 0);
|
||||
corners[1] = corners[0] + Point3f(markerLength, 0, 0);
|
||||
corners[2] = corners[0] + Point3f(markerLength, markerLength, 0);
|
||||
corners[3] = corners[0] + Point3f(0, markerLength, 0);
|
||||
objPoints.push_back(corners);
|
||||
// first ids in dictionary
|
||||
if (totalMarkers == 0)
|
||||
impl->ids.push_back(nextId);
|
||||
nextId++;
|
||||
}
|
||||
}
|
||||
if (totalMarkers > 0 && nextId != totalMarkers)
|
||||
CV_Error(cv::Error::StsBadSize, "Size of ids must be equal to the number of markers: "+std::to_string(nextId));
|
||||
impl->objPoints = objPoints;
|
||||
|
||||
// now fill chessboardCorners
|
||||
std::vector<Point3f> & c = static_pointer_cast<CharucoBoardImpl>(impl)->chessboardCorners;
|
||||
for(int y = 0; y < size.height - 1; y++) {
|
||||
for(int x = 0; x < size.width - 1; x++) {
|
||||
Point3f corner;
|
||||
corner.x = (x + 1) * squareLength;
|
||||
corner.y = (y + 1) * squareLength;
|
||||
corner.z = 0;
|
||||
c.push_back(corner);
|
||||
}
|
||||
}
|
||||
impl->rightBottomBorder = Point3f(size.width * squareLength, size.height * squareLength, 0.f);
|
||||
static_pointer_cast<CharucoBoardImpl>(impl)->calcNearestMarkerCorners();
|
||||
static_pointer_cast<CharucoBoardImpl>(impl)->createCharucoBoard();
|
||||
}
|
||||
|
||||
Size CharucoBoard::getChessboardSize() const {
|
||||
@@ -517,22 +561,37 @@ float CharucoBoard::getMarkerLength() const {
|
||||
return static_pointer_cast<CharucoBoardImpl>(impl)->markerLength;
|
||||
}
|
||||
|
||||
void CharucoBoard::setLegacyPattern(bool legacyPattern) {
|
||||
CV_Assert(impl);
|
||||
if (static_pointer_cast<CharucoBoardImpl>(impl)->legacyPattern != legacyPattern)
|
||||
{
|
||||
static_pointer_cast<CharucoBoardImpl>(impl)->legacyPattern = legacyPattern;
|
||||
static_pointer_cast<CharucoBoardImpl>(impl)->createCharucoBoard();
|
||||
}
|
||||
}
|
||||
|
||||
bool CharucoBoard::getLegacyPattern() const {
|
||||
CV_Assert(impl);
|
||||
return static_pointer_cast<CharucoBoardImpl>(impl)->legacyPattern;
|
||||
}
|
||||
|
||||
bool CharucoBoard::checkCharucoCornersCollinear(InputArray charucoIds) const {
|
||||
CV_Assert(impl);
|
||||
Mat charucoIdsMat = charucoIds.getMat();
|
||||
|
||||
unsigned int nCharucoCorners = (unsigned int)charucoIds.getMat().total();
|
||||
unsigned int nCharucoCorners = (unsigned int)charucoIdsMat.total();
|
||||
if (nCharucoCorners <= 2)
|
||||
return true;
|
||||
|
||||
// only test if there are 3 or more corners
|
||||
auto board = static_pointer_cast<CharucoBoardImpl>(impl);
|
||||
CV_Assert(board->chessboardCorners.size() >= charucoIds.getMat().total());
|
||||
CV_Assert(board->chessboardCorners.size() >= charucoIdsMat.total());
|
||||
|
||||
Vec<double, 3> point0(board->chessboardCorners[charucoIds.getMat().at<int>(0)].x,
|
||||
board->chessboardCorners[charucoIds.getMat().at<int>(0)].y, 1);
|
||||
Vec<double, 3> point0(board->chessboardCorners[charucoIdsMat.at<int>(0)].x,
|
||||
board->chessboardCorners[charucoIdsMat.at<int>(0)].y, 1);
|
||||
|
||||
Vec<double, 3> point1(board->chessboardCorners[charucoIds.getMat().at<int>(1)].x,
|
||||
board->chessboardCorners[charucoIds.getMat().at<int>(1)].y, 1);
|
||||
Vec<double, 3> point1(board->chessboardCorners[charucoIdsMat.at<int>(1)].x,
|
||||
board->chessboardCorners[charucoIdsMat.at<int>(1)].y, 1);
|
||||
|
||||
// create a line from the first two points.
|
||||
Vec<double, 3> testLine = point0.cross(point1);
|
||||
@@ -546,8 +605,8 @@ bool CharucoBoard::checkCharucoCornersCollinear(InputArray charucoIds) const {
|
||||
|
||||
double dotProduct;
|
||||
for (unsigned int i = 2; i < nCharucoCorners; i++){
|
||||
testPoint(0) = board->chessboardCorners[charucoIds.getMat().at<int>(i)].x;
|
||||
testPoint(1) = board->chessboardCorners[charucoIds.getMat().at<int>(i)].y;
|
||||
testPoint(0) = board->chessboardCorners[charucoIdsMat.at<int>(i)].x;
|
||||
testPoint(1) = board->chessboardCorners[charucoIdsMat.at<int>(i)].y;
|
||||
|
||||
// if testPoint is on testLine, dotProduct will be zero (or very, very close)
|
||||
dotProduct = testPoint.dot(testLine);
|
||||
|
||||
@@ -965,7 +965,7 @@ void ArucoDetector::detectMarkers(InputArray _image, OutputArrayOfArrays _corner
|
||||
/// STEP 3, Optional : Corner refinement :: use contour container
|
||||
if (detectorParams.cornerRefinementMethod == CORNER_REFINE_CONTOUR){
|
||||
|
||||
if (!_ids.empty()) {
|
||||
if (!ids.empty()) {
|
||||
|
||||
// do corner refinement using the contours for each detected markers
|
||||
parallel_for_(Range(0, (int)candidates.size()), [&](const Range& range) {
|
||||
|
||||
@@ -129,25 +129,21 @@ struct CharucoDetector::CharucoDetectorImpl {
|
||||
// approximated pose estimation using marker corners
|
||||
Mat approximatedRvec, approximatedTvec;
|
||||
Mat objPoints, imgPoints; // object and image points for the solvePnP function
|
||||
printf("before board.matchImagePoints(markerCorners, markerIds, objPoints, imgPoints);\n");
|
||||
board.matchImagePoints(markerCorners, markerIds, objPoints, imgPoints);
|
||||
printf("after board.matchImagePoints(markerCorners, markerIds, objPoints, imgPoints);\n");
|
||||
Board simpleBoard(board.getObjPoints(), board.getDictionary(), board.getIds());
|
||||
simpleBoard.matchImagePoints(markerCorners, markerIds, objPoints, imgPoints);
|
||||
if (objPoints.total() < 4ull) // need, at least, 4 corners
|
||||
return;
|
||||
|
||||
solvePnP(objPoints, imgPoints, charucoParameters.cameraMatrix, charucoParameters.distCoeffs, approximatedRvec, approximatedTvec);
|
||||
printf("after solvePnP\n");
|
||||
|
||||
// project chessboard corners
|
||||
vector<Point2f> allChessboardImgPoints;
|
||||
projectPoints(board.getChessboardCorners(), approximatedRvec, approximatedTvec, charucoParameters.cameraMatrix,
|
||||
charucoParameters.distCoeffs, allChessboardImgPoints);
|
||||
printf("after projectPoints\n");
|
||||
// calculate maximum window sizes for subpixel refinement. The size is limited by the distance
|
||||
// to the closes marker corner to avoid erroneous displacements to marker corners
|
||||
vector<Size> subPixWinSizes = getMaximumSubPixWindowSizes(markerCorners, markerIds, allChessboardImgPoints);
|
||||
// filter corners outside the image and subpixel-refine charuco corners
|
||||
printf("before selectAndRefineChessboardCorners\n");
|
||||
selectAndRefineChessboardCorners(allChessboardImgPoints, image, charucoCorners, charucoIds, subPixWinSizes);
|
||||
}
|
||||
|
||||
@@ -292,7 +288,7 @@ void CharucoDetector::setRefineParameters(const RefineParameters& refineParamete
|
||||
|
||||
void CharucoDetector::detectBoard(InputArray image, OutputArray charucoCorners, OutputArray charucoIds,
|
||||
InputOutputArrayOfArrays markerCorners, InputOutputArray markerIds) const {
|
||||
CV_Assert((markerCorners.empty() && markerIds.empty() && !image.empty()) || (markerCorners.size() == markerIds.size()));
|
||||
CV_Assert((markerCorners.empty() && markerIds.empty() && !image.empty()) || (markerCorners.total() == markerIds.total()));
|
||||
vector<vector<Point2f>> tmpMarkerCorners;
|
||||
vector<int> tmpMarkerIds;
|
||||
InputOutputArrayOfArrays _markerCorners = markerCorners.needed() ? markerCorners : tmpMarkerCorners;
|
||||
@@ -321,7 +317,7 @@ void CharucoDetector::detectBoard(InputArray image, OutputArray charucoCorners,
|
||||
void CharucoDetector::detectDiamonds(InputArray image, OutputArrayOfArrays _diamondCorners, OutputArray _diamondIds,
|
||||
InputOutputArrayOfArrays inMarkerCorners, InputOutputArrayOfArrays inMarkerIds) const {
|
||||
CV_Assert(getBoard().getChessboardSize() == Size(3, 3));
|
||||
CV_Assert((inMarkerCorners.empty() && inMarkerIds.empty() && !image.empty()) || (inMarkerCorners.size() == inMarkerIds.size()));
|
||||
CV_Assert((inMarkerCorners.empty() && inMarkerIds.empty() && !image.empty()) || (inMarkerCorners.total() == inMarkerIds.total()));
|
||||
|
||||
vector<vector<Point2f>> tmpMarkerCorners;
|
||||
vector<int> tmpMarkerIds;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCV_DNN
|
||||
#include "opencv2/dnn.hpp"
|
||||
#endif
|
||||
@@ -27,6 +28,8 @@ public:
|
||||
int top_k,
|
||||
int backend_id,
|
||||
int target_id)
|
||||
:divisor(32),
|
||||
strides({8, 16, 32})
|
||||
{
|
||||
net = dnn::readNet(model, config);
|
||||
CV_Assert(!net.empty());
|
||||
@@ -37,18 +40,20 @@ public:
|
||||
inputW = input_size.width;
|
||||
inputH = input_size.height;
|
||||
|
||||
padW = (int((inputW - 1) / divisor) + 1) * divisor;
|
||||
padH = (int((inputH - 1) / divisor) + 1) * divisor;
|
||||
|
||||
scoreThreshold = score_threshold;
|
||||
nmsThreshold = nms_threshold;
|
||||
topK = top_k;
|
||||
|
||||
generatePriors();
|
||||
}
|
||||
|
||||
void setInputSize(const Size& input_size) override
|
||||
{
|
||||
inputW = input_size.width;
|
||||
inputH = input_size.height;
|
||||
generatePriors();
|
||||
padW = ((inputW - 1) / divisor + 1) * divisor;
|
||||
padH = ((inputH - 1) / divisor + 1) * divisor;
|
||||
}
|
||||
|
||||
Size getInputSize() override
|
||||
@@ -97,12 +102,14 @@ public:
|
||||
return 0;
|
||||
}
|
||||
CV_CheckEQ(input_image.size(), Size(inputW, inputH), "Size does not match. Call setInputSize(size) if input size does not match the preset size");
|
||||
// Pad input_image with divisor 32
|
||||
Mat pad_image = padWithDivisor(input_image);
|
||||
|
||||
// Build blob from input image
|
||||
Mat input_blob = dnn::blobFromImage(input_image);
|
||||
Mat input_blob = dnn::blobFromImage(pad_image);
|
||||
|
||||
// Forward
|
||||
std::vector<String> output_names = { "loc", "conf", "iou" };
|
||||
std::vector<String> output_names = { "cls_8", "cls_16", "cls_32", "obj_8", "obj_16", "obj_32", "bbox_8", "bbox_16", "bbox_32", "kps_8", "kps_16", "kps_32" };
|
||||
std::vector<Mat> output_blobs;
|
||||
net.setInput(input_blob);
|
||||
net.forward(output_blobs, output_names);
|
||||
@@ -113,126 +120,70 @@ public:
|
||||
return 1;
|
||||
}
|
||||
private:
|
||||
void generatePriors()
|
||||
{
|
||||
// Calculate shapes of different scales according to the shape of input image
|
||||
Size feature_map_2nd = {
|
||||
int(int((inputW+1)/2)/2), int(int((inputH+1)/2)/2)
|
||||
};
|
||||
Size feature_map_3rd = {
|
||||
int(feature_map_2nd.width/2), int(feature_map_2nd.height/2)
|
||||
};
|
||||
Size feature_map_4th = {
|
||||
int(feature_map_3rd.width/2), int(feature_map_3rd.height/2)
|
||||
};
|
||||
Size feature_map_5th = {
|
||||
int(feature_map_4th.width/2), int(feature_map_4th.height/2)
|
||||
};
|
||||
Size feature_map_6th = {
|
||||
int(feature_map_5th.width/2), int(feature_map_5th.height/2)
|
||||
};
|
||||
|
||||
std::vector<Size> feature_map_sizes;
|
||||
feature_map_sizes.push_back(feature_map_3rd);
|
||||
feature_map_sizes.push_back(feature_map_4th);
|
||||
feature_map_sizes.push_back(feature_map_5th);
|
||||
feature_map_sizes.push_back(feature_map_6th);
|
||||
|
||||
// Fixed params for generating priors
|
||||
const std::vector<std::vector<float>> min_sizes = {
|
||||
{10.0f, 16.0f, 24.0f},
|
||||
{32.0f, 48.0f},
|
||||
{64.0f, 96.0f},
|
||||
{128.0f, 192.0f, 256.0f}
|
||||
};
|
||||
CV_Assert(min_sizes.size() == feature_map_sizes.size()); // just to keep vectors in sync
|
||||
const std::vector<int> steps = { 8, 16, 32, 64 };
|
||||
|
||||
// Generate priors
|
||||
priors.clear();
|
||||
for (size_t i = 0; i < feature_map_sizes.size(); ++i)
|
||||
{
|
||||
Size feature_map_size = feature_map_sizes[i];
|
||||
std::vector<float> min_size = min_sizes[i];
|
||||
|
||||
for (int _h = 0; _h < feature_map_size.height; ++_h)
|
||||
{
|
||||
for (int _w = 0; _w < feature_map_size.width; ++_w)
|
||||
{
|
||||
for (size_t j = 0; j < min_size.size(); ++j)
|
||||
{
|
||||
float s_kx = min_size[j] / inputW;
|
||||
float s_ky = min_size[j] / inputH;
|
||||
|
||||
float cx = (_w + 0.5f) * steps[i] / inputW;
|
||||
float cy = (_h + 0.5f) * steps[i] / inputH;
|
||||
|
||||
Rect2f prior = { cx, cy, s_kx, s_ky };
|
||||
priors.push_back(prior);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat postProcess(const std::vector<Mat>& output_blobs)
|
||||
{
|
||||
// Extract from output_blobs
|
||||
Mat loc = output_blobs[0];
|
||||
Mat conf = output_blobs[1];
|
||||
Mat iou = output_blobs[2];
|
||||
|
||||
// Decode from deltas and priors
|
||||
const std::vector<float> variance = {0.1f, 0.2f};
|
||||
float* loc_v = (float*)(loc.data);
|
||||
float* conf_v = (float*)(conf.data);
|
||||
float* iou_v = (float*)(iou.data);
|
||||
Mat faces;
|
||||
// (tl_x, tl_y, w, h, re_x, re_y, le_x, le_y, nt_x, nt_y, rcm_x, rcm_y, lcm_x, lcm_y, score)
|
||||
// 'tl': top left point of the bounding box
|
||||
// 're': right eye, 'le': left eye
|
||||
// 'nt': nose tip
|
||||
// 'rcm': right corner of mouth, 'lcm': left corner of mouth
|
||||
Mat face(1, 15, CV_32FC1);
|
||||
for (size_t i = 0; i < priors.size(); ++i) {
|
||||
// Get score
|
||||
float clsScore = conf_v[i*2+1];
|
||||
float iouScore = iou_v[i];
|
||||
// Clamp
|
||||
if (iouScore < 0.f) {
|
||||
iouScore = 0.f;
|
||||
for (size_t i = 0; i < strides.size(); ++i) {
|
||||
int cols = int(padW / strides[i]);
|
||||
int rows = int(padH / strides[i]);
|
||||
|
||||
// Extract from output_blobs
|
||||
Mat cls = output_blobs[i];
|
||||
Mat obj = output_blobs[i + strides.size() * 1];
|
||||
Mat bbox = output_blobs[i + strides.size() * 2];
|
||||
Mat kps = output_blobs[i + strides.size() * 3];
|
||||
|
||||
// Decode from predictions
|
||||
float* cls_v = (float*)(cls.data);
|
||||
float* obj_v = (float*)(obj.data);
|
||||
float* bbox_v = (float*)(bbox.data);
|
||||
float* kps_v = (float*)(kps.data);
|
||||
|
||||
// (tl_x, tl_y, w, h, re_x, re_y, le_x, le_y, nt_x, nt_y, rcm_x, rcm_y, lcm_x, lcm_y, score)
|
||||
// 'tl': top left point of the bounding box
|
||||
// 're': right eye, 'le': left eye
|
||||
// 'nt': nose tip
|
||||
// 'rcm': right corner of mouth, 'lcm': left corner of mouth
|
||||
Mat face(1, 15, CV_32FC1);
|
||||
|
||||
for(int r = 0; r < rows; ++r) {
|
||||
for(int c = 0; c < cols; ++c) {
|
||||
size_t idx = r * cols + c;
|
||||
|
||||
// Get score
|
||||
float cls_score = cls_v[idx];
|
||||
float obj_score = obj_v[idx];
|
||||
|
||||
// Clamp
|
||||
cls_score = MIN(cls_score, 1.f);
|
||||
cls_score = MAX(cls_score, 0.f);
|
||||
obj_score = MIN(obj_score, 1.f);
|
||||
obj_score = MAX(obj_score, 0.f);
|
||||
float score = std::sqrt(cls_score * obj_score);
|
||||
face.at<float>(0, 14) = score;
|
||||
|
||||
// Get bounding box
|
||||
float cx = ((c + bbox_v[idx * 4 + 0]) * strides[i]);
|
||||
float cy = ((r + bbox_v[idx * 4 + 1]) * strides[i]);
|
||||
float w = exp(bbox_v[idx * 4 + 2]) * strides[i];
|
||||
float h = exp(bbox_v[idx * 4 + 3]) * strides[i];
|
||||
|
||||
float x1 = cx - w / 2.f;
|
||||
float y1 = cy - h / 2.f;
|
||||
|
||||
face.at<float>(0, 0) = x1;
|
||||
face.at<float>(0, 1) = y1;
|
||||
face.at<float>(0, 2) = w;
|
||||
face.at<float>(0, 3) = h;
|
||||
|
||||
// Get landmarks
|
||||
for(int n = 0; n < 5; ++n) {
|
||||
face.at<float>(0, 4 + 2 * n) = (kps_v[idx * 10 + 2 * n] + c) * strides[i];
|
||||
face.at<float>(0, 4 + 2 * n + 1) = (kps_v[idx * 10 + 2 * n + 1]+ r) * strides[i];
|
||||
}
|
||||
faces.push_back(face);
|
||||
}
|
||||
}
|
||||
else if (iouScore > 1.f) {
|
||||
iouScore = 1.f;
|
||||
}
|
||||
float score = std::sqrt(clsScore * iouScore);
|
||||
face.at<float>(0, 14) = score;
|
||||
|
||||
// Get bounding box
|
||||
float cx = (priors[i].x + loc_v[i*14+0] * variance[0] * priors[i].width) * inputW;
|
||||
float cy = (priors[i].y + loc_v[i*14+1] * variance[0] * priors[i].height) * inputH;
|
||||
float w = priors[i].width * exp(loc_v[i*14+2] * variance[0]) * inputW;
|
||||
float h = priors[i].height * exp(loc_v[i*14+3] * variance[1]) * inputH;
|
||||
float x1 = cx - w / 2;
|
||||
float y1 = cy - h / 2;
|
||||
face.at<float>(0, 0) = x1;
|
||||
face.at<float>(0, 1) = y1;
|
||||
face.at<float>(0, 2) = w;
|
||||
face.at<float>(0, 3) = h;
|
||||
|
||||
// Get landmarks
|
||||
face.at<float>(0, 4) = (priors[i].x + loc_v[i*14+ 4] * variance[0] * priors[i].width) * inputW; // right eye, x
|
||||
face.at<float>(0, 5) = (priors[i].y + loc_v[i*14+ 5] * variance[0] * priors[i].height) * inputH; // right eye, y
|
||||
face.at<float>(0, 6) = (priors[i].x + loc_v[i*14+ 6] * variance[0] * priors[i].width) * inputW; // left eye, x
|
||||
face.at<float>(0, 7) = (priors[i].y + loc_v[i*14+ 7] * variance[0] * priors[i].height) * inputH; // left eye, y
|
||||
face.at<float>(0, 8) = (priors[i].x + loc_v[i*14+ 8] * variance[0] * priors[i].width) * inputW; // nose tip, x
|
||||
face.at<float>(0, 9) = (priors[i].y + loc_v[i*14+ 9] * variance[0] * priors[i].height) * inputH; // nose tip, y
|
||||
face.at<float>(0, 10) = (priors[i].x + loc_v[i*14+10] * variance[0] * priors[i].width) * inputW; // right corner of mouth, x
|
||||
face.at<float>(0, 11) = (priors[i].y + loc_v[i*14+11] * variance[0] * priors[i].height) * inputH; // right corner of mouth, y
|
||||
face.at<float>(0, 12) = (priors[i].x + loc_v[i*14+12] * variance[0] * priors[i].width) * inputW; // left corner of mouth, x
|
||||
face.at<float>(0, 13) = (priors[i].y + loc_v[i*14+13] * variance[0] * priors[i].height) * inputH; // left corner of mouth, y
|
||||
|
||||
faces.push_back(face);
|
||||
}
|
||||
|
||||
if (faces.rows > 1)
|
||||
@@ -265,16 +216,27 @@ private:
|
||||
return faces;
|
||||
}
|
||||
}
|
||||
|
||||
Mat padWithDivisor(InputArray& input_image)
|
||||
{
|
||||
int bottom = padH - inputH;
|
||||
int right = padW - inputW;
|
||||
Mat pad_image;
|
||||
copyMakeBorder(input_image, pad_image, 0, bottom, 0, right, BORDER_CONSTANT, 0);
|
||||
return pad_image;
|
||||
}
|
||||
private:
|
||||
dnn::Net net;
|
||||
|
||||
int inputW;
|
||||
int inputH;
|
||||
int padW;
|
||||
int padH;
|
||||
const int divisor;
|
||||
int topK;
|
||||
float scoreThreshold;
|
||||
float nmsThreshold;
|
||||
int topK;
|
||||
|
||||
std::vector<Rect2f> priors;
|
||||
const std::vector<int> strides;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -571,10 +571,11 @@ bool QRDetect::computeTransformationPoints()
|
||||
{
|
||||
Mat mask = Mat::zeros(bin_barcode.rows + 2, bin_barcode.cols + 2, CV_8UC1);
|
||||
uint8_t next_pixel, future_pixel = 255;
|
||||
int count_test_lines = 0, index = cvRound(localization_points[i].x);
|
||||
for (; index < bin_barcode.cols - 1; index++)
|
||||
int count_test_lines = 0, index_c = max(0, min(cvRound(localization_points[i].x), bin_barcode.cols - 1));
|
||||
const int index_r = max(0, min(cvRound(localization_points[i].y), bin_barcode.rows - 1));
|
||||
for (; index_c < bin_barcode.cols - 1; index_c++)
|
||||
{
|
||||
next_pixel = bin_barcode.ptr<uint8_t>(cvRound(localization_points[i].y))[index + 1];
|
||||
next_pixel = bin_barcode.ptr<uint8_t>(index_r)[index_c + 1];
|
||||
if (next_pixel == future_pixel)
|
||||
{
|
||||
future_pixel = static_cast<uint8_t>(~future_pixel);
|
||||
@@ -582,7 +583,7 @@ bool QRDetect::computeTransformationPoints()
|
||||
if (count_test_lines == 2)
|
||||
{
|
||||
floodFill(bin_barcode, mask,
|
||||
Point(index + 1, cvRound(localization_points[i].y)), 255,
|
||||
Point(index_c + 1, index_r), 255,
|
||||
0, Scalar(), Scalar(), FLOODFILL_MASK_ONLY);
|
||||
break;
|
||||
}
|
||||
@@ -2732,6 +2733,12 @@ bool QRDecode::decodingProcess()
|
||||
|
||||
quirc_data qr_code_data;
|
||||
quirc_decode_error_t errorCode = quirc_decode(&qr_code, &qr_code_data);
|
||||
|
||||
if(errorCode == QUIRC_ERROR_DATA_ECC){
|
||||
quirc_flip(&qr_code);
|
||||
errorCode = quirc_decode(&qr_code, &qr_code_data);
|
||||
}
|
||||
|
||||
if (errorCode != 0) { return false; }
|
||||
|
||||
for (int i = 0; i < qr_code_data.payload_len; i++)
|
||||
|
||||
@@ -332,14 +332,16 @@ void QRCodeEncoderImpl::generateQR(const std::string &input)
|
||||
}
|
||||
total_num = (uint8_t) struct_num - 1;
|
||||
}
|
||||
int segment_len = (int) ceil((int) input.length() / struct_num);
|
||||
|
||||
for (int i = 0; i < struct_num; i++)
|
||||
auto string_itr = input.begin();
|
||||
for (int i = struct_num; i > 0; --i)
|
||||
{
|
||||
sequence_num = (uint8_t) i;
|
||||
int segment_begin = i * segment_len;
|
||||
int segemnt_end = min((i + 1) * segment_len, (int) input.length()) - 1;
|
||||
std::string input_info = input.substr(segment_begin, segemnt_end - segment_begin + 1);
|
||||
size_t segment_begin = string_itr - input.begin();
|
||||
size_t segment_end = (input.end() - string_itr) / i;
|
||||
|
||||
std::string input_info = input.substr(segment_begin, segment_end);
|
||||
string_itr += segment_end;
|
||||
int detected_version = versionAuto(input_info);
|
||||
CV_Assert(detected_version != -1);
|
||||
if (version_level == 0)
|
||||
@@ -349,7 +351,6 @@ void QRCodeEncoderImpl::generateQR(const std::string &input)
|
||||
|
||||
payload.clear();
|
||||
payload.reserve(MAX_PAYLOAD_LEN);
|
||||
final_qrcodes.clear();
|
||||
format = vector<uint8_t> (15, 255);
|
||||
version_reserved = vector<uint8_t> (18, 255);
|
||||
version_size = (21 + (version_level - 1) * 4);
|
||||
@@ -1234,6 +1235,7 @@ void QRCodeEncoderImpl::encode(const String& input, OutputArray output)
|
||||
generateQR(input);
|
||||
CV_Assert(!final_qrcodes.empty());
|
||||
output.assign(final_qrcodes[0]);
|
||||
final_qrcodes.clear();
|
||||
}
|
||||
|
||||
void QRCodeEncoderImpl::encodeStructuredAppend(const String& input, OutputArrayOfArrays output)
|
||||
@@ -1250,6 +1252,7 @@ void QRCodeEncoderImpl::encodeStructuredAppend(const String& input, OutputArrayO
|
||||
{
|
||||
output.getMatRef(i) = final_qrcodes[i];
|
||||
}
|
||||
final_qrcodes.clear();
|
||||
}
|
||||
|
||||
Ptr<QRCodeEncoder> QRCodeEncoder::create(const QRCodeEncoder::Params& parameters)
|
||||
|
||||
Reference in New Issue
Block a user