41 #include <opencv2/core.hpp> 42 #include <opencv2/imgproc.hpp> 45 #include "opencv2/core/hal/hal.hpp" 57 maxCorrectionBits = _dictionary->maxCorrectionBits;
58 bytesList = _dictionary->bytesList.clone();
66 maxCorrectionBits = _maxcorr;
67 bytesList = _bytesList;
75 return create(nMarkers, markerSize, baseDictionary, randomSeed);
81 Ptr<Dictionary> Dictionary::create(
int nMarkers,
int markerSize,
98 double maxCorrectionRate)
const {
100 CV_Assert(onlyBits.rows == markerSize && onlyBits.cols == markerSize);
102 int maxCorrectionRecalculed = int(
double(maxCorrectionBits) * maxCorrectionRate);
105 Mat candidateBytes = getByteListFromBits(onlyBits);
110 for(
int m = 0; m < bytesList.rows; m++) {
111 int currentMinDistance = markerSize * markerSize + 1;
112 int currentRotation = -1;
113 for(
unsigned int r = 0; r < 4; r++) {
114 int currentHamming = cv::hal::normHamming(
115 bytesList.ptr(m)+r*candidateBytes.cols,
116 candidateBytes.ptr(),
117 candidateBytes.cols);
119 if(currentHamming < currentMinDistance) {
120 currentMinDistance = currentHamming;
126 if(currentMinDistance <= maxCorrectionRecalculed) {
128 rotation = currentRotation;
141 CV_Assert(
id >= 0 &&
id < bytesList.rows);
143 unsigned int nRotations = 4;
144 if(!allRotations) nRotations = 1;
146 Mat candidateBytes = getByteListFromBits(bits.getMat());
147 int currentMinDistance = int(bits.total() * bits.total());
148 for(
unsigned int r = 0; r < nRotations; r++) {
149 int currentHamming = cv::hal::normHamming(
150 bytesList.ptr(
id) + r*candidateBytes.cols,
151 candidateBytes.ptr(),
152 candidateBytes.cols);
154 if(currentHamming < currentMinDistance) {
155 currentMinDistance = currentHamming;
158 return currentMinDistance;
168 CV_Assert(sidePixels >= (markerSize + 2*borderBits));
169 CV_Assert(
id < bytesList.rows);
170 CV_Assert(borderBits > 0);
172 _img.create(sidePixels, sidePixels, CV_8UC1);
175 Mat tinyMarker(markerSize + 2 * borderBits, markerSize + 2 * borderBits, CV_8UC1,
177 Mat innerRegion = tinyMarker.rowRange(borderBits, tinyMarker.rows - borderBits)
178 .colRange(borderBits, tinyMarker.cols - borderBits);
180 Mat bits = 255 * getBitsFromByteList(bytesList.rowRange(
id,
id + 1),
markerSize);
181 CV_Assert(innerRegion.total() == bits.total());
182 bits.copyTo(innerRegion);
185 cv::resize(tinyMarker, _img.getMat(), _img.getMat().size(), 0, 0, INTER_NEAREST);
196 int nbytes = (bits.cols * bits.rows + 8 - 1) / 8;
198 Mat candidateByteList(1, nbytes, CV_8UC4, Scalar::all(0));
199 unsigned char currentBit = 0;
203 uchar* rot0 = candidateByteList.ptr();
204 uchar* rot1 = candidateByteList.ptr() + 1*nbytes;
205 uchar* rot2 = candidateByteList.ptr() + 2*nbytes;
206 uchar* rot3 = candidateByteList.ptr() + 3*nbytes;
208 for(
int row = 0; row < bits.rows; row++) {
209 for(
int col = 0; col < bits.cols; col++) {
211 rot0[currentByte] <<= 1;
212 rot1[currentByte] <<= 1;
213 rot2[currentByte] <<= 1;
214 rot3[currentByte] <<= 1;
216 rot0[currentByte] |= bits.at<uchar>(row, col);
217 rot1[currentByte] |= bits.at<uchar>(col, bits.cols - 1 - row);
218 rot2[currentByte] |= bits.at<uchar>(bits.rows - 1 - row, bits.cols - 1 - col);
219 rot3[currentByte] |= bits.at<uchar>(bits.rows - 1 - col, row);
221 if(currentBit == 8) {
228 return candidateByteList;
237 CV_Assert(byteList.total() > 0 &&
238 byteList.total() >= (
unsigned int)markerSize * markerSize / 8 &&
239 byteList.total() <= (
unsigned int)markerSize * markerSize / 8 + 1);
240 Mat bits(markerSize, markerSize, CV_8UC1, Scalar::all(0));
242 unsigned char base2List[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
243 int currentByteIdx = 0;
245 unsigned char currentByte = byteList.ptr()[0];
247 for(
int row = 0; row < bits.rows; row++) {
248 for(
int col = 0; col < bits.cols; col++) {
249 if(currentByte >= base2List[currentBit]) {
250 bits.at<
unsigned char >(row, col) = 1;
251 currentByte -= base2List[currentBit];
254 if(currentBit == 8) {
256 currentByte = byteList.ptr()[currentByteIdx];
259 if(8 * (currentByteIdx + 1) > (
int)bits.total())
260 currentBit = 8 * (currentByteIdx + 1) - (int)bits.total();
366 Mat marker(markerSize, markerSize, CV_8UC1, Scalar::all(0));
369 unsigned char bit = (
unsigned char) (rng.uniform(0,2));
370 marker.at<
unsigned char >(i, j) = bit;
385 int minHamming = (int)marker.total() + 1;
386 for(
int r = 1; r < 4; r++) {
387 int currentHamming = cv::hal::normHamming(bytes.ptr(), bytes.ptr() + bytes.cols*r, bytes.cols);
388 if(currentHamming < minHamming) minHamming = currentHamming;
396 const Ptr<Dictionary> &baseDictionary,
int randomSeed) {
397 RNG rng((uint64)(randomSeed));
399 Ptr<Dictionary> out = makePtr<Dictionary>();
406 int C = (int)std::floor(
float(markerSize * markerSize) / 4.f);
407 int tau = 2 * (int)std::floor(
float(C) * 4.f / 3.f);
410 if(baseDictionary->bytesList.rows > 0) {
411 CV_Assert(baseDictionary->markerSize == markerSize);
412 out->bytesList = baseDictionary->bytesList.clone();
414 int minDistance = markerSize * markerSize + 1;
415 for(
int i = 0; i < out->bytesList.rows; i++) {
416 Mat markerBytes = out->bytesList.rowRange(i, i + 1);
419 for(
int j = i + 1; j < out->bytesList.rows; j++) {
420 minDistance =
min(minDistance, out->getDistanceToId(markerBits, j));
431 const int maxUnproductiveIterations = 5000;
432 int unproductiveIterations = 0;
434 while(out->bytesList.rows < nMarkers) {
438 int minDistance = selfDistance;
442 if(selfDistance >= bestTau) {
443 for(
int i = 0; i < out->bytesList.rows; i++) {
444 int currentDistance = out->getDistanceToId(currentMarker, i);
445 minDistance =
min(currentDistance, minDistance);
446 if(minDistance <= bestTau) {
453 if(minDistance >= tau) {
454 unproductiveIterations = 0;
457 out->bytesList.push_back(bytes);
459 unproductiveIterations++;
462 if(minDistance > bestTau) {
463 bestTau = minDistance;
464 bestMarker = currentMarker;
468 if(unproductiveIterations == maxUnproductiveIterations) {
469 unproductiveIterations = 0;
473 out->bytesList.push_back(bytes);
479 out->maxCorrectionBits = (tau - 1) / 2;
488 Ptr<Dictionary> baseDictionary = makePtr<Dictionary>();
const Dictionary DICT_4X4_50_DATA
const Dictionary DICT_4X4_250_DATA
6x6 bits, minimum hamming distance between any two codes = 11, 587 codes
const Dictionary DICT_7X7_100_DATA
const Dictionary DICT_6X6_250_DATA
5x5 bits, minimum hamming distance between any two codes = 9, 35 codes
const Dictionary DICT_5X5_250_DATA
const Dictionary DICT_4X4_100_DATA
const Dictionary DICT_5X5_50_DATA
4x4 bits, minimum hamming distance between any two codes = 5, 30 codes
CV_WRAP void drawMarker(int id, int sidePixels, OutputArray _img, int borderBits=1) const
Draw a canonical marker image.
static CV_WRAP Mat getByteListFromBits(const Mat &bits)
Transform matrix of bits to list of bytes in the 4 rotations.
int getDistanceToId(InputArray bits, int id, bool allRotations=true) const
Returns the distance of the input bits to the specific id. If allRotations is true, the four posible bits rotation are considered.
static CV_WRAP Mat getBitsFromByteList(const Mat &byteList, int markerSize)
Transform list of bytes to matrix of bits.
CV_EXPORTS Ptr< Dictionary > getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name)
Returns one of the predefined dictionaries defined in PREDEFINED_DICTIONARY_NAME. ...
const Dictionary DICT_6X6_100_DATA
const Dictionary DICT_5X5_100_DATA
PREDEFINED_DICTIONARY_NAME
Predefined markers dictionaries/sets Each dictionary indicates the number of bits and the number of m...
const Dictionary DICT_APRILTAG_36h11_DATA
static int _getSelfDistance(const Mat &marker)
Calculate selfDistance of the codification of a marker Mat. Self distance is the Hamming distance of ...
const Dictionary DICT_7X7_50_DATA
Ptr< Dictionary > generateCustomDictionary(int nMarkers, int markerSize, const Ptr< Dictionary > &baseDictionary, int randomSeed)
const Dictionary DICT_5X5_1000_DATA
bool identify(const Mat &onlyBits, int &idx, int &rotation, double maxCorrectionRate) const
Given a matrix of bits. Returns whether if marker is identified or not. It returns by reference the c...
const Dictionary DICT_6X6_50_DATA
const Dictionary DICT_6X6_1000_DATA
double min(double a, double b)
static Mat _generateRandomMarker(int markerSize, RNG &rng)
Generates a random marker Mat of size markerSize x markerSize.
Dictionary(const Mat &_bytesList=Mat(), int _markerSize=0, int _maxcorr=0)
const Dictionary DICT_4X4_1000_DATA
const Dictionary DICT_APRILTAG_16h5_DATA
6x6 bits, minimum hamming distance between any two codes = 10, 2320 codes
const Dictionary DICT_7X7_250_DATA
const Dictionary DICT_ARUCO_DATA
static CV_WRAP Ptr< Dictionary > get(int dict)
int const Ptr< Dictionary > & baseDictionary
const Dictionary DICT_7X7_1000_DATA
Dictionary/Set of markers. It contains the inner codification.
const Dictionary DICT_APRILTAG_36h10_DATA
const Dictionary DICT_APRILTAG_25h9_DATA