Skip to content

Commit c471967

Browse files
author
AleksandrPanov
committed
implemented cv::Algorithm - read/write, added read/write to RefineParameters, added write to DetectorParameters
1 parent 0f4cea3 commit c471967

File tree

4 files changed

+132
-85
lines changed

4 files changed

+132
-85
lines changed

modules/aruco/include/opencv2/aruco/dictionary.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,6 @@ class CV_EXPORTS_W Dictionary {
6666
CV_PROP_RW int maxCorrectionBits; // maximum number of bits that can be corrected
6767

6868

69-
/**
70-
*/
7169
Dictionary(const Mat &_bytesList = Mat(), int _markerSize = 0, int _maxcorr = 0);
7270

7371

modules/aruco/include/opencv2/aruco_detector.hpp

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,15 @@ struct CV_EXPORTS_W DetectorParameters {
9393
}
9494

9595
/**
96-
* @brief Read a new set of DetectorParameters from FileStorage.
96+
* @brief Read a new set of DetectorParameters from FileNode (use FileStorage.root()).
9797
*/
9898
CV_WRAP bool readDetectorParameters(const FileNode& fn);
9999

100+
/**
101+
* @brief Write a set of DetectorParameters to FileStorage
102+
*/
103+
CV_WRAP bool writeDetectorParameters(const Ptr<FileStorage>& fs);
104+
100105
/// minimum window size for adaptive thresholding before finding contours (default 3).
101106
CV_PROP_RW int adaptiveThreshWinSizeMin;
102107

@@ -214,6 +219,9 @@ struct CV_EXPORTS_W DetectorParameters {
214219

215220
/// range [0,1], eq (2) from paper. The parameter tau_i has a direct influence on the processing speed.
216221
CV_PROP_RW float minMarkerLengthRatioOriginalImg;
222+
223+
private:
224+
bool readWrite(const Ptr<FileNode>& readNode = nullptr, const Ptr<FileStorage>& writeStorage = nullptr);
217225
};
218226

219227
struct CV_EXPORTS_W RefineParameters {
@@ -226,14 +234,22 @@ struct CV_EXPORTS_W RefineParameters {
226234
RefineParameters(float _minRepDistance, float _errorCorrectionRate, bool _checkAllOrders):
227235
minRepDistance(_minRepDistance), errorCorrectionRate(_errorCorrectionRate), checkAllOrders(_checkAllOrders) {}
228236

229-
CV_WRAP static Ptr<RefineParameters> create() {
230-
return makePtr<RefineParameters>();
231-
}
232-
233-
CV_WRAP static Ptr<RefineParameters> create(float _minRepDistance, float _errorCorrectionRate, bool _checkAllOrders) {
237+
CV_WRAP static Ptr<RefineParameters> create(float _minRepDistance = 10.f, float _errorCorrectionRate = 3.f,
238+
bool _checkAllOrders = true) {
234239
return makePtr<RefineParameters>(_minRepDistance, _errorCorrectionRate, _checkAllOrders);
235240
}
236241

242+
243+
/**
244+
* @brief Read a new set of RefineParameters from FileNode (use FileStorage.root()).
245+
*/
246+
CV_WRAP bool readRefineParameters(const FileNode& fn);
247+
248+
/**
249+
* @brief Write a set of RefineParameters to FileStorage
250+
*/
251+
CV_WRAP bool writeRefineParameters(const Ptr<FileStorage>& fs);
252+
237253
/// minRepDistance minimum distance between the corners of the rejected candidate and the reprojected marker in
238254
/// order to consider it as a correspondence.
239255
CV_PROP_RW float minRepDistance;
@@ -243,9 +259,11 @@ struct CV_EXPORTS_W RefineParameters {
243259
/// checkAllOrders consider the four posible corner orders in the rejectedCorners array.
244260
// * If it set to false, only the provided corner order is considered (default true).
245261
CV_PROP_RW bool checkAllOrders;
262+
private:
263+
bool readWrite(const Ptr<FileNode>& readNode = nullptr, const Ptr<FileStorage>& writeStorage = nullptr);
246264
};
247265

248-
class CV_EXPORTS_W ArucoDetector
266+
class CV_EXPORTS_W ArucoDetector : public Algorithm
249267
{
250268
public:
251269
/// dictionary indicates the type of markers that will be searched
@@ -319,6 +337,30 @@ class CV_EXPORTS_W ArucoDetector
319337
InputOutputArray detectedIds, InputOutputArrayOfArrays rejectedCorners,
320338
InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(),
321339
OutputArray recoveredIdxs = noArray());
340+
341+
/** @brief Stores algorithm parameters in a file storage
342+
*/
343+
virtual void write(FileStorage& fs) const override {
344+
Ptr<FileStorage> pfs = makePtr<FileStorage>(fs);
345+
dictionary->writeDictionary(pfs);
346+
params->writeDetectorParameters(pfs);
347+
348+
}
349+
350+
/** @brief simplified API for language bindings
351+
* @overload
352+
*/
353+
CV_WRAP void write(const String& fileName) const {
354+
FileStorage fs(fileName, FileStorage::WRITE);
355+
write(fs);
356+
}
357+
358+
/** @brief Reads algorithm parameters from a file storage
359+
*/
360+
CV_WRAP virtual void read(const FileNode& fn) override {
361+
dictionary->readDictionary(fn);
362+
params->readDetectorParameters(fn);
363+
}
322364
};
323365

324366
/**

modules/aruco/src/aruco_detector.cpp

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,80 @@ namespace aruco {
1515

1616
using namespace std;
1717

18-
template<typename T>
19-
static inline bool readParameter(const FileNode& node, T& parameter)
20-
{
21-
if (!node.empty()) {
22-
node >> parameter;
23-
return true;
24-
}
25-
return false;
18+
bool DetectorParameters::readWrite(const Ptr<FileNode>& readNode, const Ptr<FileStorage>& writeStorage) {
19+
CV_Assert(!readNode.empty() || !writeStorage.empty());
20+
bool check = false;
21+
22+
check |= readWriteParameter("adaptiveThreshWinSizeMin", this->adaptiveThreshWinSizeMin, readNode, writeStorage);
23+
check |= readWriteParameter("adaptiveThreshWinSizeMax", this->adaptiveThreshWinSizeMax, readNode, writeStorage);
24+
check |= readWriteParameter("adaptiveThreshWinSizeStep", this->adaptiveThreshWinSizeStep, readNode, writeStorage);
25+
check |= readWriteParameter("adaptiveThreshConstant", this->adaptiveThreshConstant, readNode, writeStorage);
26+
check |= readWriteParameter("minMarkerPerimeterRate", this->minMarkerPerimeterRate, readNode, writeStorage);
27+
check |= readWriteParameter("maxMarkerPerimeterRate", this->maxMarkerPerimeterRate, readNode, writeStorage);
28+
check |= readWriteParameter("polygonalApproxAccuracyRate", this->polygonalApproxAccuracyRate,
29+
readNode, writeStorage);
30+
check |= readWriteParameter("minCornerDistanceRate", this->minCornerDistanceRate, readNode, writeStorage);
31+
check |= readWriteParameter("minDistanceToBorder", this->minDistanceToBorder, readNode, writeStorage);
32+
check |= readWriteParameter("minMarkerDistanceRate", this->minMarkerDistanceRate, readNode, writeStorage);
33+
check |= readWriteParameter("cornerRefinementMethod", this->cornerRefinementMethod, readNode, writeStorage);
34+
check |= readWriteParameter("cornerRefinementWinSize", this->cornerRefinementWinSize, readNode, writeStorage);
35+
check |= readWriteParameter("cornerRefinementMaxIterations", this->cornerRefinementMaxIterations,
36+
readNode, writeStorage);
37+
check |= readWriteParameter("cornerRefinementMinAccuracy", this->cornerRefinementMinAccuracy,
38+
readNode, writeStorage);
39+
check |= readWriteParameter("markerBorderBits", this->markerBorderBits, readNode, writeStorage);
40+
check |= readWriteParameter("perspectiveRemovePixelPerCell", this->perspectiveRemovePixelPerCell,
41+
readNode, writeStorage);
42+
check |= readWriteParameter("perspectiveRemoveIgnoredMarginPerCell", this->perspectiveRemoveIgnoredMarginPerCell,
43+
readNode, writeStorage);
44+
check |= readWriteParameter("maxErroneousBitsInBorderRate", this->maxErroneousBitsInBorderRate,
45+
readNode, writeStorage);
46+
check |= readWriteParameter("minOtsuStdDev", this->minOtsuStdDev, readNode, writeStorage);
47+
check |= readWriteParameter("errorCorrectionRate", this->errorCorrectionRate, readNode, writeStorage);
48+
// new aruco 3 functionality
49+
check |= readWriteParameter("useAruco3Detection", this->useAruco3Detection, readNode, writeStorage);
50+
check |= readWriteParameter("minSideLengthCanonicalImg", this->minSideLengthCanonicalImg, readNode, writeStorage);
51+
check |= readWriteParameter("minMarkerLengthRatioOriginalImg", this->minMarkerLengthRatioOriginalImg,
52+
readNode, writeStorage);
53+
return check;
54+
}
55+
56+
bool DetectorParameters::readDetectorParameters(const FileNode& fn) {
57+
if(fn.empty())
58+
return false;
59+
Ptr<FileNode> pfn = makePtr<FileNode>(fn);
60+
return readWrite(pfn);
2661
}
2762

28-
bool DetectorParameters::readDetectorParameters(const FileNode& fn)
63+
bool DetectorParameters::writeDetectorParameters(const Ptr<FileStorage>& fs)
2964
{
65+
if (fs.empty() && !fs->isOpened())
66+
return false;
67+
return readWrite(nullptr, fs);
68+
}
69+
70+
bool RefineParameters::readWrite(const Ptr<FileNode>& readNode, const Ptr<FileStorage>& writeStorage) {
71+
CV_Assert(!readNode.empty() || !writeStorage.empty());
72+
bool check = false;
73+
74+
check |= readWriteParameter("minRepDistance", this->minRepDistance, readNode, writeStorage);
75+
check |= readWriteParameter("errorCorrectionRate", this->errorCorrectionRate, readNode, writeStorage);
76+
check |= readWriteParameter("checkAllOrders", this->checkAllOrders, readNode, writeStorage);
77+
return check;
78+
}
79+
80+
bool RefineParameters::readRefineParameters(const FileNode &fn) {
3081
if(fn.empty())
31-
return true;
32-
bool checkRead = false;
33-
checkRead |= readParameter(fn["adaptiveThreshWinSizeMin"], this->adaptiveThreshWinSizeMin);
34-
checkRead |= readParameter(fn["adaptiveThreshWinSizeMax"], this->adaptiveThreshWinSizeMax);
35-
checkRead |= readParameter(fn["adaptiveThreshWinSizeStep"], this->adaptiveThreshWinSizeStep);
36-
checkRead |= readParameter(fn["adaptiveThreshConstant"], this->adaptiveThreshConstant);
37-
checkRead |= readParameter(fn["minMarkerPerimeterRate"], this->minMarkerPerimeterRate);
38-
checkRead |= readParameter(fn["maxMarkerPerimeterRate"], this->maxMarkerPerimeterRate);
39-
checkRead |= readParameter(fn["polygonalApproxAccuracyRate"], this->polygonalApproxAccuracyRate);
40-
checkRead |= readParameter(fn["minCornerDistanceRate"], this->minCornerDistanceRate);
41-
checkRead |= readParameter(fn["minDistanceToBorder"], this->minDistanceToBorder);
42-
checkRead |= readParameter(fn["minMarkerDistanceRate"], this->minMarkerDistanceRate);
43-
checkRead |= readParameter(fn["cornerRefinementMethod"], this->cornerRefinementMethod);
44-
checkRead |= readParameter(fn["cornerRefinementWinSize"], this->cornerRefinementWinSize);
45-
checkRead |= readParameter(fn["cornerRefinementMaxIterations"], this->cornerRefinementMaxIterations);
46-
checkRead |= readParameter(fn["cornerRefinementMinAccuracy"], this->cornerRefinementMinAccuracy);
47-
checkRead |= readParameter(fn["markerBorderBits"], this->markerBorderBits);
48-
checkRead |= readParameter(fn["perspectiveRemovePixelPerCell"], this->perspectiveRemovePixelPerCell);
49-
checkRead |= readParameter(fn["perspectiveRemoveIgnoredMarginPerCell"], this->perspectiveRemoveIgnoredMarginPerCell);
50-
checkRead |= readParameter(fn["maxErroneousBitsInBorderRate"], this->maxErroneousBitsInBorderRate);
51-
checkRead |= readParameter(fn["minOtsuStdDev"], this->minOtsuStdDev);
52-
checkRead |= readParameter(fn["errorCorrectionRate"], this->errorCorrectionRate);
53-
// new aruco 3 functionality
54-
checkRead |= readParameter(fn["useAruco3Detection"], this->useAruco3Detection);
55-
checkRead |= readParameter(fn["minSideLengthCanonicalImg"], this->minSideLengthCanonicalImg);
56-
checkRead |= readParameter(fn["minMarkerLengthRatioOriginalImg"], this->minMarkerLengthRatioOriginalImg);
57-
return checkRead;
82+
return false;
83+
Ptr<FileNode> pfn = makePtr<FileNode>(fn);
84+
return readWrite(pfn);
5885
}
5986

87+
bool RefineParameters::writeRefineParameters(const Ptr<FileStorage> &fs) {
88+
if(fs.empty())
89+
return false;
90+
return readWrite(nullptr, fs);
91+
}
6092

6193
/**
6294
* @brief Threshold input image using adaptive thresholding
@@ -163,7 +195,7 @@ static void _reorderCandidatesCorners(vector< vector< Point2f > > &candidates) {
163195
/**
164196
* @brief to make sure that the corner's order of both candidates (default/white) is the same
165197
*/
166-
static vector< Point2f > alignContourOrder( Point2f corner, vector< Point2f > candidate){
198+
static vector<Point2f> alignContourOrder(Point2f corner, vector< Point2f > candidate) {
167199
uint8_t r=0;
168200
double min = cv::norm( Vec2f( corner - candidate[0] ), NORM_L2SQR);
169201
for(uint8_t pos=1; pos < 4; pos++) {
@@ -478,8 +510,7 @@ static int _getBorderErrors(const Mat &bits, int markerSize, int borderSize) {
478510
static uint8_t _identifyOneCandidate(const Ptr<Dictionary>& dictionary, InputArray _image,
479511
const vector<Point2f>& _corners, int& idx,
480512
const Ptr<DetectorParameters>& params, int& rotation,
481-
const float scale = 1.f)
482-
{
513+
const float scale = 1.f) {
483514
CV_DbgAssert(_corners.size() == 4);
484515
CV_DbgAssert(_image.getMat().total() != 0);
485516
CV_DbgAssert(params->markerBorderBits > 0);
@@ -1017,7 +1048,6 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Ptr<Board> &_
10171048
InputOutputArrayOfArrays _detectedCorners, InputOutputArray _detectedIds,
10181049
InputOutputArrayOfArrays _rejectedCorners, InputArray _cameraMatrix,
10191050
InputArray _distCoeffs, OutputArray _recoveredIdxs) {
1020-
10211051
CV_Assert(refineParams->minRepDistance > 0);
10221052

10231053
if(_detectedIds.total() == 0 || _rejectedCorners.total() == 0) return;
@@ -1177,12 +1207,9 @@ void ArucoDetector::refineDetectedMarkers(InputArray _image, const Ptr<Board> &_
11771207
}
11781208
}
11791209

1180-
/**
1181-
*/
1210+
11821211
void drawDetectedMarkers(InputOutputArray _image, InputArrayOfArrays _corners,
11831212
InputArray _ids, Scalar borderColor) {
1184-
1185-
11861213
CV_Assert(_image.getMat().total() != 0 &&
11871214
(_image.getMat().channels() == 1 || _image.getMat().channels() == 3));
11881215
CV_Assert((_corners.total() == _ids.total()) || _ids.total() == 0);

modules/aruco/src/dictionary.cpp

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@ or tort (including negligence or otherwise) arising in any way out of
3636
the use of this software, even if advised of the possibility of such damage.
3737
*/
3838

39-
#include "precomp.hpp"
40-
#include "opencv2/aruco/dictionary.hpp"
41-
#include <opencv2/core.hpp>
4239
#include <opencv2/imgproc.hpp>
40+
#include "opencv2/core/hal/hal.hpp"
41+
42+
#include "precomp.hpp"
43+
#include "aruco_utils.hpp"
4344
#include "predefined_dictionaries.hpp"
4445
#include "apriltag/predefined_dictionaries_apriltag.hpp"
45-
#include "opencv2/core/hal/hal.hpp"
46+
#include <opencv2/aruco/dictionary.hpp>
4647

4748
namespace cv {
4849
namespace aruco {
@@ -72,40 +73,27 @@ Ptr<Dictionary> Dictionary::create(int nMarkers, int markerSize, int randomSeed)
7273

7374
Ptr<Dictionary> Dictionary::create(int nMarkers, int markerSize,
7475
const Ptr<Dictionary> &baseDictionary, int randomSeed) {
75-
7676
return generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed);
7777
}
7878

7979

80-
template<typename T>
81-
static inline bool readParameter(const FileNode& node, T& parameter)
82-
{
83-
if (!node.empty()) {
84-
node >> parameter;
85-
return true;
86-
}
87-
return false;
88-
}
89-
90-
91-
bool Dictionary::readDictionary(const cv::FileNode& fn)
92-
{
80+
bool Dictionary::readDictionary(const cv::FileNode& fn) {
9381
int nMarkers = 0, _markerSize = 0;
94-
if (fn.empty() || !readParameter(fn["nmarkers"], nMarkers) || !readParameter(fn["markersize"], _markerSize))
82+
if (fn.empty() || !readParameter("nmarkers", nMarkers, fn) || !readParameter("markersize", _markerSize, fn))
9583
return false;
9684
Mat bytes(0, 0, CV_8UC1), marker(_markerSize, _markerSize, CV_8UC1);
9785
std::string markerString;
9886
for (int i = 0; i < nMarkers; i++) {
9987
std::ostringstream ostr;
10088
ostr << i;
101-
if (!readParameter(fn["marker_" + ostr.str()], markerString))
89+
if (!readParameter("marker_" + ostr.str(), markerString, fn))
10290
return false;
10391
for (int j = 0; j < (int) markerString.size(); j++)
10492
marker.at<unsigned char>(j) = (markerString[j] == '0') ? 0 : 1;
10593
bytes.push_back(Dictionary::getByteListFromBits(marker));
10694
}
10795
int _maxCorrectionBits = 0;
108-
readParameter(fn["maxCorrectionBits"], _maxCorrectionBits);
96+
readParameter("maxCorrectionBits", _maxCorrectionBits, fn);
10997
*this = Dictionary(bytes, _markerSize, _maxCorrectionBits);
11098
return true;
11199
}
@@ -134,9 +122,7 @@ Ptr<Dictionary> Dictionary::get(int dict) {
134122
}
135123

136124

137-
bool Dictionary::identify(const Mat &onlyBits, int &idx, int &rotation,
138-
double maxCorrectionRate) const {
139-
125+
bool Dictionary::identify(const Mat &onlyBits, int &idx, int &rotation, double maxCorrectionRate) const {
140126
CV_Assert(onlyBits.rows == markerSize && onlyBits.cols == markerSize);
141127

142128
int maxCorrectionRecalculed = int(double(maxCorrectionBits) * maxCorrectionRate);
@@ -198,7 +184,6 @@ int Dictionary::getDistanceToId(InputArray bits, int id, bool allRotations) cons
198184

199185

200186
void Dictionary::drawMarker(int id, int sidePixels, OutputArray _img, int borderBits) const {
201-
202187
CV_Assert(sidePixels >= (markerSize + 2*borderBits));
203188
CV_Assert(id < bytesList.rows);
204189
CV_Assert(borderBits > 0);
@@ -220,7 +205,6 @@ void Dictionary::drawMarker(int id, int sidePixels, OutputArray _img, int border
220205
}
221206

222207

223-
224208
Mat Dictionary::getByteListFromBits(const Mat &bits) {
225209
// integer ceil
226210
int nbytes = (bits.cols * bits.rows + 8 - 1) / 8;
@@ -293,8 +277,7 @@ Mat Dictionary::getBitsFromByteList(const Mat &byteList, int markerSize) {
293277
}
294278

295279

296-
Ptr<Dictionary> getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name)
297-
{
280+
Ptr<Dictionary> getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name) {
298281
// DictionaryData constructors calls
299282
// moved out of globals so construted on first use, which allows lazy-loading of opencv dll
300283
static const Dictionary DICT_ARUCO_DATA = Dictionary(Mat(1024, (5 * 5 + 7) / 8, CV_8UC4, (uchar*)DICT_ARUCO_BYTES), 5, 0);
@@ -415,8 +398,7 @@ static int _getSelfDistance(const Mat &marker) {
415398
return minHamming;
416399
}
417400

418-
/**
419-
*/
401+
420402
Ptr<Dictionary> generateCustomDictionary(int nMarkers, int markerSize,
421403
const Ptr<Dictionary> &baseDictionary, int randomSeed) {
422404
RNG rng((uint64)(randomSeed));
@@ -507,8 +489,6 @@ Ptr<Dictionary> generateCustomDictionary(int nMarkers, int markerSize,
507489
}
508490

509491

510-
/**
511-
*/
512492
Ptr<Dictionary> generateCustomDictionary(int nMarkers, int markerSize, int randomSeed) {
513493
Ptr<Dictionary> baseDictionary = makePtr<Dictionary>();
514494
return generateCustomDictionary(nMarkers, markerSize, baseDictionary, randomSeed);

0 commit comments

Comments
 (0)