arucofidmarkers.cpp
Go to the documentation of this file.
1 
30 #include <aruco/arucofidmarkers.h>
31 #include <opencv2/imgproc/imgproc.hpp>
32 using namespace cv;
33 using namespace std;
34 namespace aruco {
35 
36  /************************************
37  *
38  *
39  *
40  *
41  ************************************/
44  Mat FiducidalMarkers::createMarkerImage(int id,int size) throw (cv::Exception)
45  {
46  Mat marker(size,size, CV_8UC1);
47  marker.setTo(Scalar(0));
48  if (0<=id && id<1024) {
49  //for each line, create
50  int swidth=size/7;
51  int ids[4]={0x10,0x17,0x09,0x0e};
52  for (int y=0;y<5;y++) {
53  int index=(id>>2*(4-y)) & 0x0003;
54  int val=ids[index];
55  for (int x=0;x<5;x++) {
56  Mat roi=marker(Rect((x+1)* swidth,(y+1)* swidth,swidth,swidth));
57  if ( ( val>>(4-x) ) & 0x0001 ) roi.setTo(Scalar(255));
58  else roi.setTo(Scalar(0));
59  }
60  }
61  }
62  else throw cv::Exception(9004,"id invalid","createMarker",__FILE__,__LINE__);
63 
64  return marker;
65  }
69  cv::Mat FiducidalMarkers::getMarkerMat(int id) throw (cv::Exception)
70  {
71  Mat marker(5,5, CV_8UC1);
72  marker.setTo(Scalar(0));
73  if (0<=id && id<1024) {
74  //for each line, create
75  int ids[4]={0x10,0x17,0x09,0x0e};
76  for (int y=0;y<5;y++) {
77  int index=(id>>2*(4-y)) & 0x0003;
78  int val=ids[index];
79  for (int x=0;x<5;x++) {
80  if ( ( val>>(4-x) ) & 0x0001 ) marker.at<uchar>(y,x)=1;
81  else marker.at<uchar>(y,x)=0;
82  }
83  }
84  }
85  else throw cv::Exception (9189,"Invalid marker id","aruco::fiducidal::createMarkerMat",__FILE__,__LINE__);
86  return marker;
87  }
88  /************************************
89  *
90  *
91  *
92  *
93  ************************************/
94 
95  cv::Mat FiducidalMarkers::createBoardImage( Size gridSize,int MarkerSize,int MarkerDistance, BoardConfiguration& TInfo ,vector<int> *excludedIds) throw (cv::Exception)
96  {
97 
98 
99 
100  srand(cv::getTickCount());
101  int nMarkers=gridSize.height*gridSize.width;
102  TInfo.resize(nMarkers);
103  vector<int> ids=getListOfValidMarkersIds_random(nMarkers,excludedIds);
104  for (int i=0;i<nMarkers;i++)
105  TInfo[i].id=ids[i];
106 
107  int sizeY=gridSize.height*MarkerSize+(gridSize.height-1)*MarkerDistance;
108  int sizeX=gridSize.width*MarkerSize+(gridSize.width-1)*MarkerDistance;
109  //find the center so that the ref systeem is in it
110  int centerX=sizeX/2;
111  int centerY=sizeY/2;
112 
113  //indicate the data is expressed in pixels
114  TInfo.mInfoType=BoardConfiguration::PIX;
115  Mat tableImage(sizeY,sizeX,CV_8UC1);
116  tableImage.setTo(Scalar(255));
117  int idp=0;
118  for (int y=0;y<gridSize.height;y++)
119  for (int x=0;x<gridSize.width;x++,idp++) {
120  Mat subrect(tableImage,Rect( x*(MarkerDistance+MarkerSize),y*(MarkerDistance+MarkerSize),MarkerSize,MarkerSize));
121  Mat marker=createMarkerImage( TInfo[idp].id,MarkerSize);
122  //set the location of the corners
123  TInfo[idp].resize(4);
124  TInfo[idp][0]=cv::Point3f( x*(MarkerDistance+MarkerSize),y*(MarkerDistance+MarkerSize),0);
125  TInfo[idp][1]=cv::Point3f( x*(MarkerDistance+MarkerSize)+MarkerSize,y*(MarkerDistance+MarkerSize),0);
126  TInfo[idp][2]=cv::Point3f( x*(MarkerDistance+MarkerSize)+MarkerSize,y*(MarkerDistance+MarkerSize)+MarkerSize,0);
127  TInfo[idp][3]=cv::Point3f( x*(MarkerDistance+MarkerSize),y*(MarkerDistance+MarkerSize)+MarkerSize,0);
128  for (int i=0;i<4;i++) TInfo[idp][i]-=cv::Point3f(centerX,centerY,0);
129  marker.copyTo(subrect);
130  }
131 
132  return tableImage;
133  }
134 
135  /************************************
136  *
137  *
138  *
139  *
140  ************************************/
141  cv::Mat FiducidalMarkers::createBoardImage_ChessBoard( Size gridSize,int MarkerSize, BoardConfiguration& TInfo ,bool centerData ,vector<int> *excludedIds) throw (cv::Exception)
142  {
143 
144 
145  srand(cv::getTickCount());
146 
147  //determine the total number of markers required
148  int nMarkers= 3*(gridSize.width*gridSize.height)/4;//overdetermine the number of marker read
149  vector<int> idsVector=getListOfValidMarkersIds_random(nMarkers,excludedIds);
150 
151 
152  int sizeY=gridSize.height*MarkerSize;
153  int sizeX=gridSize.width*MarkerSize;
154  //find the center so that the ref systeem is in it
155  int centerX=sizeX/2;
156  int centerY=sizeY/2;
157 
158  Mat tableImage(sizeY,sizeX,CV_8UC1);
159  tableImage.setTo(Scalar(255));
160  TInfo.mInfoType=BoardConfiguration::PIX;
161  unsigned int CurMarkerIdx=0;
162  for (int y=0;y<gridSize.height;y++) {
163 
164  bool toWrite;
165  if (y%2==0) toWrite=false;
166  else toWrite=true;
167  for (int x=0;x<gridSize.width;x++) {
168  toWrite=!toWrite;
169  if (toWrite) {
170  if (CurMarkerIdx>=idsVector.size()) throw cv::Exception(999," FiducidalMarkers::createBoardImage_ChessBoard","INTERNAL ERROR. REWRITE THIS!!",__FILE__,__LINE__);
171  TInfo.push_back( MarkerInfo(idsVector[CurMarkerIdx++]));
172 
173  Mat subrect(tableImage,Rect( x*MarkerSize,y*MarkerSize,MarkerSize,MarkerSize));
174  Mat marker=createMarkerImage( TInfo.back().id,MarkerSize);
175  //set the location of the corners
176  TInfo.back().resize(4);
177  TInfo.back()[0]=cv::Point3f( x*(MarkerSize),y*(MarkerSize),0);
178  TInfo.back()[1]=cv::Point3f( x*(MarkerSize)+MarkerSize,y*(MarkerSize),0);
179  TInfo.back()[2]=cv::Point3f( x*(MarkerSize)+MarkerSize,y*(MarkerSize)+MarkerSize,0);
180  TInfo.back()[3]=cv::Point3f( x*(MarkerSize),y*(MarkerSize)+MarkerSize,0);
181  if (centerData) {
182  for (int i=0;i<4;i++)
183  TInfo.back()[i]-=cv::Point3f(centerX,centerY,0);
184  }
185  marker.copyTo(subrect);
186  }
187  }
188  }
189 
190  return tableImage;
191  }
192 
193 
194 
195  /************************************
196  *
197  *
198  *
199  *
200  ************************************/
201  cv::Mat FiducidalMarkers::createBoardImage_Frame( Size gridSize,int MarkerSize,int MarkerDistance, BoardConfiguration& TInfo ,bool centerData,vector<int> *excludedIds ) throw (cv::Exception)
202  {
203  srand(cv::getTickCount());
204  int nMarkers=2*gridSize.height*2*gridSize.width;
205  vector<int> idsVector=getListOfValidMarkersIds_random(nMarkers,excludedIds);
206 
207  int sizeY=gridSize.height*MarkerSize+MarkerDistance*(gridSize.height-1);
208  int sizeX=gridSize.width*MarkerSize+MarkerDistance*(gridSize.width-1);
209  //find the center so that the ref systeem is in it
210  int centerX=sizeX/2;
211  int centerY=sizeY/2;
212 
213  Mat tableImage(sizeY,sizeX,CV_8UC1);
214  tableImage.setTo(Scalar(255));
215  TInfo.mInfoType=BoardConfiguration::PIX;
216  int CurMarkerIdx=0;
217  int mSize=MarkerSize+MarkerDistance;
218  for (int y=0;y<gridSize.height;y++) {
219  for (int x=0;x<gridSize.width;x++) {
220  if (y==0 || y==gridSize.height-1 || x==0 || x==gridSize.width-1) {
221  TInfo.push_back( MarkerInfo(idsVector[CurMarkerIdx++]));
222  Mat subrect(tableImage,Rect( x*mSize,y*mSize,MarkerSize,MarkerSize));
223  Mat marker=createMarkerImage( TInfo.back().id,MarkerSize);
224  marker.copyTo(subrect);
225  //set the location of the corners
226  TInfo.back().resize(4);
227  TInfo.back()[0]=cv::Point3f( x*(mSize),y*(mSize),0);
228  TInfo.back()[1]=cv::Point3f( x*(mSize)+MarkerSize,y*(mSize),0);
229  TInfo.back()[2]=cv::Point3f( x*(mSize)+MarkerSize,y*(mSize)+MarkerSize,0);
230  TInfo.back()[3]=cv::Point3f( x*(mSize),y*(mSize)+MarkerSize,0);
231  if (centerData) {
232  for (int i=0;i<4;i++)
233  TInfo.back()[i]-=cv::Point3f(centerX,centerY,0);
234  }
235 
236  }
237  }
238  }
239 
240  return tableImage;
241  }
242  /************************************
243  *
244  *
245  *
246  *
247  ************************************/
248  Mat FiducidalMarkers::rotate(const Mat &in)
249  {
250  Mat out;
251  in.copyTo(out);
252  for (int i=0;i<in.rows;i++)
253  {
254  for (int j=0;j<in.cols;j++)
255  {
256  out.at<uchar>(i,j)=in.at<uchar>(in.cols-j-1,i);
257  }
258  }
259  return out;
260  }
261 
262 
263  /************************************
264  *
265  *
266  *
267  *
268  ************************************/
269  int FiducidalMarkers::hammDistMarker(Mat bits)
270  {
271  int ids[4][5]=
272  {
273  {
274  1,0,0,0,0
275  }
276  ,
277  {
278  1,0,1,1,1
279  }
280  ,
281  {
282  0,1,0,0,1
283  }
284  ,
285  {
286  0, 1, 1, 1, 0
287  }
288  };
289  int dist=0;
290 
291  for (int y=0;y<5;y++)
292  {
293  int minSum=1e5;
294  //hamming distance to each possible word
295  for (int p=0;p<4;p++)
296  {
297  int sum=0;
298  //now, count
299  for (int x=0;x<5;x++)
300  sum+= bits.at<uchar>(y,x) == ids[p][x]?0:1;
301  if (minSum>sum) minSum=sum;
302  }
303  //do the and
304  dist+=minSum;
305  }
306 
307  return dist;
308  }
309 
310  /************************************
311  *
312  *
313  *
314  *
315  ************************************/
316  int FiducidalMarkers::analyzeMarkerImage(Mat &grey,int &nRotations)
317  {
318 
319  //Markers are divided in 7x7 regions, of which the inner 5x5 belongs to marker info
320  //the external border shoould be entirely black
321 
322  int swidth=grey.rows/7;
323  for (int y=0;y<7;y++)
324  {
325  int inc=6;
326  if (y==0 || y==6) inc=1;//for first and last row, check the whole border
327  for (int x=0;x<7;x+=inc)
328  {
329  int Xstart=(x)*(swidth);
330  int Ystart=(y)*(swidth);
331  Mat square=grey(Rect(Xstart,Ystart,swidth,swidth));
332  int nZ=countNonZero(square);
333  if (nZ> (swidth*swidth) /2) {
334  // cout<<"neb"<<endl;
335  return -1;//can not be a marker because the border element is not black!
336  }
337  }
338  }
339 
340  //now,
341  vector<int> markerInfo(5);
342  Mat _bits=Mat::zeros(5,5,CV_8UC1);
343  //get information(for each inner square, determine if it is black or white)
344 
345  for (int y=0;y<5;y++)
346  {
347 
348  for (int x=0;x<5;x++)
349  {
350  int Xstart=(x+1)*(swidth);
351  int Ystart=(y+1)*(swidth);
352  Mat square=grey(Rect(Xstart,Ystart,swidth,swidth));
353  int nZ=countNonZero(square);
354  if (nZ> (swidth*swidth) /2) _bits.at<uchar>( y,x)=1;
355  }
356  }
357  // printMat<uchar>( _bits,"or mat");
358 
359  //checkl all possible rotations
360  Mat _bitsFlip;
361  Mat Rotations[4];
362  Rotations[0]=_bits;
363  int dists[4];
364  dists[0]=hammDistMarker( Rotations[0]) ;
365  pair<int,int> minDist( dists[0],0);
366  for (int i=1;i<4;i++)
367  {
368  //rotate
369  Rotations[i]=rotate(Rotations[i-1]);
370  //get the hamming distance to the nearest possible word
371  dists[i]=hammDistMarker( Rotations[i]) ;
372  if (dists[i]<minDist.first)
373  {
374  minDist.first= dists[i];
375  minDist.second=i;
376  }
377  }
378  // printMat<uchar>( Rotations [ minDist.second]);
379  // cout<<"MinDist="<<minDist.first<<" "<<minDist.second<<endl;
380 
381  nRotations=minDist.second;
382  if (minDist.first!=0) //FUTURE WORK: correct if any error
383  return -1;
384  else {//Get id of the marker
385  int MatID=0;
386  cv::Mat bits=Rotations [ minDist.second];
387  for (int y=0;y<5;y++)
388  {
389  MatID<<=1;
390  if ( bits.at<uchar>(y,1)) MatID|=1;
391  MatID<<=1;
392  if ( bits.at<uchar>(y,3)) MatID|=1;
393  }
394  return MatID;
395  }
396  }
397 
398 
399  /************************************
400  *
401  *
402  *
403  *
404  ************************************/
405  int FiducidalMarkers::detect(const Mat &in,int &nRotations)
406  {
407  assert(in.rows==in.cols);
408  Mat grey;
409  if ( in.type()==CV_8UC1) grey=in;
410  else cv::cvtColor(in,grey,CV_BGR2GRAY);
411  //threshold image
412  threshold(grey, grey,125, 255, THRESH_BINARY|THRESH_OTSU);
413 
414  //now, analyze the interior in order to get the id
415  //try first with the big ones
416 
417  return analyzeMarkerImage(grey,nRotations);;
418  //too many false positives
419  /* int id=analyzeMarkerImage(grey,nRotations);
420  if (id!=-1) return id;
421  id=analyzeMarkerImage_type2(grey,nRotations);
422  if (id!=-1) return id;
423  return -1;*/
424  }
425 
426  vector<int> FiducidalMarkers::getListOfValidMarkersIds_random(int nMarkers,vector<int> *excluded) throw (cv::Exception)
427  {
428 
429  if (excluded!=NULL)
430  if (nMarkers+excluded->size()>1024) throw cv::Exception(8888,"FiducidalMarkers::getListOfValidMarkersIds_random","Number of possible markers is exceeded",__FILE__,__LINE__);
431 
432  vector<int> listOfMarkers(1024);
433  //set a list with all ids
434  for (int i=0;i<1024;i++) listOfMarkers[i]=i;
435 
436  if (excluded!=NULL)//set excluded to -1
437  for (size_t i=0;i<excluded->size();++i)
438  listOfMarkers[excluded->at(i)]=-1;
439  //random shuffle
440  random_shuffle(listOfMarkers.begin(),listOfMarkers.end());
441  //now, take the first nMarkers elements with value !=-1
442  int i=0;
443  vector<int> retList;
444  while (static_cast<int>(retList.size())<nMarkers) {
445  if (listOfMarkers[i]!=-1)
446  retList.push_back(listOfMarkers[i]);
447  ++i;
448  }
449  return retList;
450  }
451 
452 }
453 
Mat rotate(Mat in)
This class defines a board with several markers. A Board contains several markers so that they are mo...
Definition: board.h:69


aruco
Author(s): Rafael Muñoz Salinas , Bence Magyar
autogenerated on Wed Sep 2 2020 04:02:09