dictionary_based.cpp
Go to the documentation of this file.
1 
29 #include "dictionary_based.h"
30 
31 #include <opencv2/imgproc/imgproc.hpp>
32 #include <bitset>
33 #include <cmath>
34 #include "aruco_cvversioning.h"
35 namespace aruco
36 {
37 void DictionaryBased::setParams(const Dictionary& dic, float max_correction_rate)
38 {
39  _nsubdivisions = sqrt(dic.nbits()) + 2;
40  nbits_dict.clear();
41  dicttypename = dic.getName();
42  if (dic.getType() == Dictionary::ALL_DICTS)
43  {
44  for (auto& dt : Dictionary::getDicTypes())
45  if (dt != "ALL_DICTS" && dt != "CUSTOM")
46  vdic.push_back(Dictionary ::loadPredefined(dt));
47  }
48  else
49  vdic.push_back(dic);
50 
51  //
52  for (auto& dic : vdic)
53  nbits_dict[dic.nbits()].push_back(&dic);
54 
55  _max_correction_rate = std::max(0.f, std::min(1.0f, max_correction_rate));
56 }
57 
58 std::string DictionaryBased::getName() const
59 {
60  return dicttypename;
61 }
62 
63 void DictionaryBased::toMat(uint64_t code, int nbits_sq, cv::Mat& out)
64 {
65  out.create(nbits_sq, nbits_sq, CV_8UC1);
66  std::bitset<64> bs(code);
67  int curbit = 0;
68  for (int r = 0; r < nbits_sq; r++)
69  {
70  uchar* pr = out.ptr<uchar>(r);
71  for (int c = 0; c < nbits_sq; c++)
72  pr[c] = bs[curbit];
73  }
74 }
75 
76 int hamm_distance(uint64_t a, uint64_t b)
77 {
78  return static_cast<int>(std::bitset<64>(a ^ b).count());
79 }
80 
81 bool DictionaryBased::detect(const cv::Mat& in, int& marker_id, int& nRotations,
82  std::string& additionalInfo)
83 {
84  assert(in.rows == in.cols);
85 
86  cv::Mat grey;
87  if (in.type() == CV_8UC1)
88  grey = in;
89  else
90  cv::cvtColor(in, grey, CV_BGR2GRAY);
91  // threshold image
92  cv::threshold(grey, grey, 125, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
93 
94 
95  std::map<uint32_t, std::vector<uint64_t> > nbits_ids;
96  // for each
97  for (auto& bitsids : nbits_dict)
98  {
99  int nbits = bitsids.first;
100  std::vector<uint64_t> ids;
101  getInnerCode(grey, nbits, ids);
102  if (ids.size() > 0)
103  {
104  if (ids[0] != 0)
105  {
106  nbits_ids[nbits] = ids;
107  }
108  }
109  }
110  // how many are there?
111 
112  if (nbits_ids.size() == 0)
113  return false;
114  // check if any dictionary recognizes it
115  for (auto nbits : nbits_ids)
116  {
117  const auto& ids = nbits.second;
118  // check in every dictionary
119  for (auto& dic : nbits_dict[nbits.first])
120  {
121  // try a perfecf match
122  for (int rot = 0; rot < 4; rot++)
123  if (dic->is(ids[rot]))
124  {
125  // std::cout<<"MATCH:"<<dic->getName()<<" "<<ids[rot]<<std::endl;
126  nRotations = rot; // how many rotations are and its id
127  marker_id = dic->at(ids[rot]);
128  additionalInfo = dic->getName();
129  return true;
130  }
131 
132  // try with some error/correction if allowed
133  if (_max_correction_rate > 0)
134  { // find distance to map elements
135  int _maxCorrectionAllowed =
136  static_cast<int>(static_cast<float>(dic->tau()) * _max_correction_rate);
137 
138  int min_dist = 100000000;
139  bool found = false;
140  for (auto ci : dic->getMapCode())
141  {
142  for (int i = 0; i < 4; i++)
143  {
144  int curr_dist = hamm_distance(ci.first, ids[i]);
145  if (curr_dist < _maxCorrectionAllowed && curr_dist < min_dist)
146  {
147  found = true;
148  min_dist = curr_dist;
149  marker_id = ci.second;
150  nRotations = i;
151  additionalInfo = dic->getName();
152  }
153  }
154  }
155  return found;
156  }
157  }
158  }
159 
160 
161  return false;
162 }
163 
164 
165 bool DictionaryBased::getInnerCode(const cv::Mat& thres_img, int total_nbits,
166  std::vector<uint64_t>& ids)
167 {
168  int bits_noborder = static_cast<int>(std::sqrt(total_nbits));
169  int bits_withborder = bits_noborder + 2;
170  // Markers are divided in (bits_a+2)x(bits_a+2) regions, of which the inner
171  // bits_axbits_a belongs to marker info the external border shoould be entirely black
172  cv::Mat nonZeros(bits_withborder, bits_withborder, CV_32SC1);
173  cv::Mat nValues(bits_withborder, bits_withborder, CV_32SC1);
174  nonZeros.setTo(cv::Scalar::all(0));
175  nValues.setTo(cv::Scalar::all(0));
176  for (int y = 0; y < thres_img.rows; y++)
177  {
178  const uchar* ptr = thres_img.ptr<uchar>(y);
179  int my = float(bits_withborder) * float(y) / float(thres_img.rows);
180  for (int x = 0; x < thres_img.cols; x++)
181  {
182  int mx = float(bits_withborder) * float(x) / float(thres_img.cols);
183  if (ptr[x] > 125)
184  nonZeros.at<int>(my, mx)++;
185  nValues.at<int>(my, mx)++;
186  }
187  }
188  cv::Mat binaryCode(bits_withborder, bits_withborder, CV_8UC1);
189  // now, make the theshold
190  for (int y = 0; y < bits_withborder; y++)
191  for (int x = 0; x < bits_withborder; x++)
192  {
193  if (nonZeros.at<int>(y, x) > nValues.at<int>(y, x) / 2)
194  binaryCode.at<uchar>(y, x) = 1;
195  else
196  binaryCode.at<uchar>(y, x) = 0;
197  }
198 
199  // check if border is completely black
200  for (int y = 0; y < bits_withborder; y++)
201  {
202  int inc = bits_withborder - 1;
203  if (y == 0 || y == bits_withborder - 1)
204  inc = 1; // for first and last row, check the whole border
205  for (int x = 0; x < bits_withborder; x += inc)
206  if (binaryCode.at<uchar>(y, x) != 0)
207  return false;
208  }
209 
210  // take the inner code
211 
212  cv::Mat _bits(bits_noborder, bits_noborder, CV_8UC1);
213  for (int y = 0; y < bits_noborder; y++)
214  for (int x = 0; x < bits_noborder; x++)
215  _bits.at<uchar>(y, x) = binaryCode.at<uchar>(y + 1, x + 1);
216 
217  // now, get the 64bits ids
218 
219  int nr = 0;
220  do
221  {
222  ids.push_back(touulong(_bits));
223  _bits = rotate(_bits);
224  nr++;
225  } while (nr < 4);
226  return true;
227 }
228 
229 
230 // bool DictionaryBased::getInnerCode(const cv::Mat& thres_img, int total_nbits,
231 // std::vector<uint64_t>& ids)
232 // {
233 // auto toInt=[](float v){return int(v+0.5);};
234 // int bits_a = static_cast<int>(std::sqrt(total_nbits));
235 // int bits_a2 = bits_a + 2;
236 // // Markers are divided in (bits_a+2)x(bits_a+2) regions, of which the inner
237 // bits_axbits_a belongs to marker
238 // // info
239 // // the external border shoould be entirely black
240 
241 // float swidth = float(thres_img.rows) / float(bits_a2);
242 // for (int y = 0; y < bits_a2; y++)
243 // {
244 // int inc = bits_a2 - 1;
245 // if (y == 0 || y == bits_a2 - 1)
246 // inc = 1; // for first and last row, check the whole border
247 // for (int x = 0; x < bits_a2; x += inc)
248 // {
249 // cv::Mat square = thres_img(cv::Rect( toInt(float(x) * swidth ), toInt(float(y)
250 // * swidth), swidth, swidth)); if (cv::countNonZero(square) > (swidth * swidth) / 2)
251 // return false; // can not be a marker because the border element is not black!
252 // }
253 // }
254 
255 // // now,
256 // // get information(for each inner square, determine if it is black or white)
257 
258 // // now,
259 // cv::Mat _bits = cv::Mat::zeros(bits_a, bits_a, CV_8UC1);
260 // // get information(for each inner square, determine if it is black or white)
261 
262 // for (int y = 0; y < bits_a; y++)
263 // {
264 // for (int x = 0; x < bits_a; x++)
265 // {
266 // int Xstart = toInt(float(x + 1) * swidth);
267 // int Ystart = toInt(float(y + 1) * swidth);
268 // cv::Mat square = thres_img(cv::Rect(Xstart, Ystart, swidth, swidth));
269 // int nZ = cv::countNonZero(square);
270 // if (nZ > (swidth * swidth) / 2)
271 // _bits.at<uchar>(y, x) = 1;
272 // }
273 // }
274 // // now, get the 64bits ids
275 
276 // int nr = 0;
277 // do
278 // {
279 // ids.push_back(touulong(_bits));
280 // _bits = rotate(_bits);
281 // nr++;
282 // } while (nr < 4);
283 // return true;
284 // }
285 
286 // convert matrix of (0,1)s in a 64 bit value
287 uint64_t DictionaryBased::touulong(const cv::Mat& code)
288 {
289  std::bitset<64> bits;
290  int bidx = 0;
291  for (int y = code.rows - 1; y >= 0; y--)
292  for (int x = code.cols - 1; x >= 0; x--)
293  bits[bidx++] = code.at<uchar>(y, x);
294  return bits.to_ullong();
295 }
296 cv::Mat DictionaryBased::rotate(const cv::Mat& in)
297 {
298  cv::Mat out;
299  in.copyTo(out);
300  for (int i = 0; i < in.rows; i++)
301  {
302  for (int j = 0; j < in.cols; j++)
303  {
304  out.at<uchar>(i, j) = in.at<uchar>(in.cols - j - 1, i);
305  }
306  }
307  return out;
308 }
309 } // namespace aruco
aruco::DictionaryBased::toMat
void toMat(uint64_t code, int nbits_sq, cv::Mat &out)
Definition: dictionary_based.cpp:63
aruco::Dictionary::nbits
uint32_t nbits() const
Definition: dictionary.h:81
aruco::DictionaryBased::setParams
void setParams(const Dictionary &dic, float max_correction_rate)
Definition: dictionary_based.cpp:37
aruco::DictionaryBased::dicttypename
std::string dicttypename
Definition: dictionary_based.h:63
aruco::Dictionary::getName
std::string getName() const
Definition: dictionary.h:91
aruco::Dictionary
Definition: dictionary.h:41
aruco::DictionaryBased::getName
virtual std::string getName() const
Definition: dictionary_based.cpp:58
aruco::Dictionary::ALL_DICTS
@ ALL_DICTS
Definition: dictionary.h:47
f
f
aruco::DictionaryBased::rotate
cv::Mat rotate(const cv::Mat &in)
Definition: dictionary_based.cpp:296
aruco::DictionaryBased::_nsubdivisions
int _nsubdivisions
Definition: dictionary_based.h:61
aruco::DictionaryBased::_max_correction_rate
float _max_correction_rate
Definition: dictionary_based.h:62
aruco::Dictionary::loadPredefined
static Dictionary loadPredefined(DICT_TYPES type)
Definition: dictionary.cpp:113
aruco::DictionaryBased::vdic
std::vector< Dictionary > vdic
Definition: dictionary_based.h:59
aruco::DictionaryBased::getInnerCode
bool getInnerCode(const cv::Mat &thres_img, int total_nbits, std::vector< uint64_t > &ids)
Definition: dictionary_based.cpp:165
aruco::DictionaryBased::touulong
uint64_t touulong(const cv::Mat &code)
Definition: dictionary_based.cpp:287
dictionary_based.h
aruco::Dictionary::getType
DICT_TYPES getType() const
Definition: dictionary.h:70
aruco
Definition: cameraparameters.h:24
aruco::DictionaryBased::detect
virtual bool detect(const cv::Mat &in, int &marker_id, int &nRotations, std::string &additionalInfo)
Definition: dictionary_based.cpp:81
aruco_cvversioning.h
aruco::Dictionary::getDicTypes
static std::vector< std::string > getDicTypes()
Definition: dictionary.cpp:3536
aruco::DictionaryBased::nbits_dict
std::map< uint32_t, std::vector< Dictionary * > > nbits_dict
Definition: dictionary_based.h:64
aruco::hamm_distance
int hamm_distance(uint64_t a, uint64_t b)
Definition: dictionary_based.cpp:76


aruco
Author(s): Rafael Muñoz Salinas , Bence Magyar
autogenerated on Sat Sep 23 2023 02:26:45