36 Dictionary HighlyReliableMarkers::_D;
37 HighlyReliableMarkers::BalancedBinaryTree HighlyReliableMarkers::_binaryTree;
38 unsigned int HighlyReliableMarkers::_n, HighlyReliableMarkers::_ncellsBorder, HighlyReliableMarkers::_correctionDistance;
39 int HighlyReliableMarkers::_swidth;
44 MarkerCode::MarkerCode(
unsigned int n) {
46 for (
unsigned int i = 0; i < 4; i++) {
47 _bits[i].resize(n * n);
48 for (
unsigned int j = 0; j < _bits[i].size(); j++)
59 for (
unsigned int i = 0; i < 4; i++) {
60 _bits[i] = MC.
_bits[i];
70 void MarkerCode::set(
unsigned int pos,
bool val,
bool updateIds) {
72 if (
get(pos) != val) {
73 for (
unsigned int i = 0; i < 4; i++) {
74 unsigned int y = pos / n(), x = pos % n();
88 unsigned int rotPos = y * n() + x;
89 _bits[i][rotPos] = val;
93 _ids[i] += (
unsigned int)pow(
float(2), float(rotPos));
95 _ids[i] -= (
unsigned int)pow(
float(2), float(rotPos));
104 unsigned int MarkerCode::selfDistance(
unsigned int &minRot)
const {
105 unsigned int res = _bits[0].size();
106 for (
unsigned int i = 1; i < 4; i++) {
107 unsigned int hammdist = hammingDistance(_bits[0], _bits[i]);
108 if (hammdist < res) {
119 unsigned int MarkerCode::distance(
const MarkerCode &m,
unsigned int &minRot)
const {
120 unsigned int res = _bits[0].size();
121 for (
unsigned int i = 0; i < 4; i++) {
122 unsigned int hammdist = hammingDistance(_bits[0], m.
getRotation(i));
123 if (hammdist < res) {
134 void MarkerCode::fromString(std::string s) {
135 for (
unsigned int i = 0; i < s.length(); i++) {
145 std::string MarkerCode::toString()
const {
148 for (
unsigned int i = 0; i < size(); i++) {
160 cv::Mat MarkerCode::getImg(
unsigned int pixSize)
const {
161 const unsigned int borderSize = 1;
162 unsigned int nrows = n() + 2 * borderSize;
163 if (pixSize % nrows != 0)
164 pixSize = pixSize + nrows - pixSize % nrows;
165 unsigned int cellSize = pixSize / nrows;
166 cv::Mat img(pixSize, pixSize, CV_8U, cv::Scalar::all(0));
168 for (
unsigned int i = 0; i < n(); i++) {
169 for (
unsigned int j = 0; j < n(); j++) {
170 if (_bits[0][i * n() + j] != 0) {
172 for (
unsigned int k = 0; k < cellSize; k++) {
173 for (
unsigned int l = 0; l < cellSize; l++) {
174 img.at< uchar >((i + borderSize) * cellSize + k, (j + borderSize) * cellSize + l) = 255;
186 unsigned int MarkerCode::hammingDistance(
const std::vector< bool > &m1,
const std::vector< bool > &m2)
const {
187 unsigned int res = 0;
188 for (
unsigned int i = 0; i < m1.size(); i++)
199 bool Dictionary::fromFile(std::string filename) {
200 cv::FileStorage fs(filename, cv::FileStorage::READ);
201 int nmarkers, markersize;
204 fs[
"nmarkers"] >> nmarkers;
205 fs[
"markersize"] >> markersize;
209 for (
int i = 0; i < nmarkers; i++) {
211 fs[
"marker_" + toStr(i)] >> s;
222 bool Dictionary::toFile(std::string filename) {
223 cv::FileStorage fs(filename, cv::FileStorage::WRITE);
225 fs <<
"nmarkers" << (int)size();
226 fs <<
"markersize" << (int)((*
this)[0].n());
227 fs <<
"tau0" << (int)(this->tau0);
229 for (
unsigned int i = 0; i < size(); i++) {
230 std::string
s = ((*this)[i]).toString();
231 fs <<
"marker_" + toStr(i) << s;
239 unsigned int Dictionary::distance(
const MarkerCode &m,
unsigned int &minMarker,
unsigned int &minRot) {
240 unsigned int res = m.
size();
241 for (
unsigned int i = 0; i < size(); i++) {
242 unsigned int minRotAux;
243 unsigned int distance = (*this)[i].distance(m, minRotAux);
244 if (distance < res) {
256 unsigned int Dictionary::minimunDistance() {
259 unsigned int minDist = (*this)[0].size();
261 for (
unsigned int i = 0; i < size(); i++) {
263 minDist = std::min(minDist, (*
this)[i].selfDistance());
266 for (
unsigned int j = i + 1; j < size(); j++) {
267 minDist = std::min(minDist, (*
this)[i].distance((*
this)[j]));
278 bool HighlyReliableMarkers::loadDictionary(
Dictionary D,
float correctionDistanceRate) {
283 _ncellsBorder = (_D[0].n() + 2);
284 _correctionDistance = correctionDistanceRate * ((D.
tau0-1)/2);
285 cerr <<
"aruco :: _correctionDistance = " << _correctionDistance << endl;
286 _binaryTree.loadDictionary(&D);
290 bool HighlyReliableMarkers::loadDictionary(std::string filename,
float correctionDistance) {
293 return loadDictionary(D, correctionDistance);
299 int HighlyReliableMarkers::detect(
const cv::Mat &in,
int &nRotations) {
301 assert(in.rows == in.cols);
303 if (in.type() == CV_8UC1)
306 cv::cvtColor(in, grey, CV_BGR2GRAY);
308 cv::threshold(grey, grey, 125, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
309 _swidth = grey.rows / _ncellsBorder;
319 for (
unsigned int i = 0; i < 4; i++) {
320 if (_binaryTree.findId(candidate.
getId(i), orgPos)) {
339 unsigned int minMarker, minRot;
340 if (_D.distance(candidate, minMarker, minRot) <= _correctionDistance) {
352 bool HighlyReliableMarkers::checkBorders(cv::Mat grey) {
353 for (
int y = 0; y < _ncellsBorder; y++) {
354 int inc = _ncellsBorder - 1;
355 if (y == 0 || y == _ncellsBorder - 1)
357 for (
int x = 0; x < _ncellsBorder; x += inc) {
358 int Xstart = (x) * (_swidth);
359 int Ystart = (y) * (_swidth);
360 cv::Mat square = grey(cv::Rect(Xstart, Ystart, _swidth, _swidth));
361 int nZ = cv::countNonZero(square);
362 if (nZ > (_swidth * _swidth) / 2) {
372 MarkerCode HighlyReliableMarkers::getMarkerCode(
const cv::Mat &grey) {
374 for (
int y = 0; y < _n; y++) {
375 for (
int x = 0; x < _n; x++) {
376 int Xstart = (x + 1) * (_swidth);
377 int Ystart = (y + 1) * (_swidth);
378 cv::Mat square = grey(cv::Rect(Xstart, Ystart, _swidth, _swidth));
379 int nZ = countNonZero(square);
380 if (nZ > (_swidth * _swidth) / 2)
381 candidate.
set(y * _n + x, 1);
391 void HighlyReliableMarkers::BalancedBinaryTree::loadDictionary(
Dictionary *D) {
394 for (
unsigned int i = 0; i < D->size(); i++) {
395 _orderD.push_back(std::pair< unsigned int, unsigned int >((*D)[i].getId(), i));
397 std::sort(_orderD.begin(), _orderD.end());
400 unsigned int levels = 0;
401 while (pow(
float(2),
float(levels)) <= _orderD.size())
406 std::vector< bool > visited;
407 visited.resize(_orderD.size(),
false);
410 unsigned int rootIdx = _orderD.
size() / 2;
411 visited[rootIdx] =
true;
417 std::vector< std::pair< unsigned int, unsigned int > > intervals;
419 intervals.push_back(std::pair< unsigned int, unsigned int >(0, rootIdx));
420 intervals.push_back(std::pair< unsigned int, unsigned int >(rootIdx, _orderD.size()));
424 _binaryTree.resize(_orderD.size());
427 if (!visited[(0 + rootIdx) / 2])
428 _binaryTree[rootIdx].first = (0 + rootIdx) / 2;
430 _binaryTree[rootIdx].first = -1;
431 if (!visited[(rootIdx + _orderD.size()) / 2])
432 _binaryTree[rootIdx].second = (rootIdx + _orderD.size()) / 2;
434 _binaryTree[rootIdx].second = -1;
437 for (
unsigned int i = 1; i < levels; i++) {
438 unsigned int nintervals = intervals.size();
439 for (
unsigned int j = 0; j < nintervals; j++) {
441 unsigned int lowerBound, higherBound;
442 lowerBound = intervals.back().first;
443 higherBound = intervals.back().second;
444 intervals.pop_back();
447 unsigned int center = (higherBound + lowerBound) / 2;
450 if (!visited[center])
451 visited[center] =
true;
456 unsigned int lowerChild = (lowerBound + center) / 2;
457 unsigned int higherChild = (center + higherBound) / 2;
460 if (!visited[lowerChild]) {
461 intervals.insert(intervals.begin(), std::pair< unsigned int, unsigned int >(lowerBound, center));
462 _binaryTree[center].first = lowerChild;
464 _binaryTree[center].first = -1;
467 if (!visited[higherChild]) {
468 intervals.insert(intervals.begin(), std::pair< unsigned int, unsigned int >(center, higherBound));
469 _binaryTree[center].second = higherChild;
471 _binaryTree[center].second = -1;
486 bool HighlyReliableMarkers::BalancedBinaryTree::findId(
unsigned int id,
unsigned int &orgPos) {
489 unsigned int posId = _orderD[pos].first;
491 orgPos = _orderD[pos].second;
493 }
else if (posId <
id)
494 pos = _binaryTree[pos].second;
496 pos = _binaryTree[pos].first;
unsigned int size() const
void fromString(std::string s)
bool fromFile(std::string filename)
std::vector< bool > _bits[4]
const std::vector< bool > & getRotation(unsigned int rot) const
void set(unsigned int pos, bool val, bool updateIds=true)
unsigned int getId(unsigned int rot=0) const