31 #include <opencv2/imgproc/imgproc.hpp> 44 Mat FiducidalMarkers::createMarkerImage(
int id,
int size)
throw (cv::Exception)
46 Mat marker(size,size, CV_8UC1);
47 marker.setTo(Scalar(0));
48 if (0<=
id &&
id<1024) {
51 int ids[4]={0x10,0x17,0x09,0x0e};
52 for (
int y=0;y<5;y++) {
53 int index=(
id>>2*(4-y)) & 0x0003;
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));
62 else throw cv::Exception(9004,
"id invalid",
"createMarker",__FILE__,__LINE__);
69 cv::Mat FiducidalMarkers::getMarkerMat(
int id)
throw (cv::Exception)
71 Mat marker(5,5, CV_8UC1);
72 marker.setTo(Scalar(0));
73 if (0<=
id &&
id<1024) {
75 int ids[4]={0x10,0x17,0x09,0x0e};
76 for (
int y=0;y<5;y++) {
77 int index=(
id>>2*(4-y)) & 0x0003;
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;
85 else throw cv::Exception (9189,
"Invalid marker id",
"aruco::fiducidal::createMarkerMat",__FILE__,__LINE__);
95 cv::Mat FiducidalMarkers::createBoardImage( Size gridSize,
int MarkerSize,
int MarkerDistance,
BoardConfiguration& TInfo ,vector<int> *excludedIds)
throw (cv::Exception)
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++)
107 int sizeY=gridSize.height*MarkerSize+(gridSize.height-1)*MarkerDistance;
108 int sizeX=gridSize.width*MarkerSize+(gridSize.width-1)*MarkerDistance;
114 TInfo.mInfoType=BoardConfiguration::PIX;
115 Mat tableImage(sizeY,sizeX,CV_8UC1);
116 tableImage.setTo(Scalar(255));
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);
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);
141 cv::Mat FiducidalMarkers::createBoardImage_ChessBoard( Size gridSize,
int MarkerSize,
BoardConfiguration& TInfo ,
bool centerData ,vector<int> *excludedIds)
throw (cv::Exception)
145 srand(cv::getTickCount());
148 int nMarkers= 3*(gridSize.width*gridSize.height)/4;
149 vector<int> idsVector=getListOfValidMarkersIds_random(nMarkers,excludedIds);
152 int sizeY=gridSize.height*MarkerSize;
153 int sizeX=gridSize.width*MarkerSize;
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++) {
165 if (y%2==0) toWrite=
false;
167 for (
int x=0;x<gridSize.width;x++) {
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++]));
173 Mat subrect(tableImage,Rect( x*MarkerSize,y*MarkerSize,MarkerSize,MarkerSize));
174 Mat marker=createMarkerImage( TInfo.back().id,MarkerSize);
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);
182 for (
int i=0;i<4;i++)
183 TInfo.back()[i]-=cv::Point3f(centerX,centerY,0);
185 marker.copyTo(subrect);
201 cv::Mat FiducidalMarkers::createBoardImage_Frame( Size gridSize,
int MarkerSize,
int MarkerDistance,
BoardConfiguration& TInfo ,
bool centerData,vector<int> *excludedIds )
throw (cv::Exception)
203 srand(cv::getTickCount());
204 int nMarkers=2*gridSize.height*2*gridSize.width;
205 vector<int> idsVector=getListOfValidMarkersIds_random(nMarkers,excludedIds);
207 int sizeY=gridSize.height*MarkerSize+MarkerDistance*(gridSize.height-1);
208 int sizeX=gridSize.width*MarkerSize+MarkerDistance*(gridSize.width-1);
213 Mat tableImage(sizeY,sizeX,CV_8UC1);
214 tableImage.setTo(Scalar(255));
215 TInfo.mInfoType=BoardConfiguration::PIX;
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);
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);
232 for (
int i=0;i<4;i++)
233 TInfo.back()[i]-=cv::Point3f(centerX,centerY,0);
252 for (
int i=0;i<in.rows;i++)
254 for (
int j=0;j<in.cols;j++)
256 out.at<uchar>(i,j)=in.at<uchar>(in.cols-j-1,i);
269 int FiducidalMarkers::hammDistMarker(Mat bits)
291 for (
int y=0;y<5;y++)
295 for (
int p=0;p<4;p++)
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;
316 int FiducidalMarkers::analyzeMarkerImage(Mat &grey,
int &nRotations)
322 int swidth=grey.rows/7;
323 for (
int y=0;y<7;y++)
326 if (y==0 || y==6) inc=1;
327 for (
int x=0;x<7;x+=inc)
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) {
341 vector<int> markerInfo(5);
342 Mat _bits=Mat::zeros(5,5,CV_8UC1);
345 for (
int y=0;y<5;y++)
348 for (
int x=0;x<5;x++)
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;
364 dists[0]=hammDistMarker( Rotations[0]) ;
365 pair<int,int> minDist( dists[0],0);
366 for (
int i=1;i<4;i++)
369 Rotations[i]=
rotate(Rotations[i-1]);
371 dists[i]=hammDistMarker( Rotations[i]) ;
372 if (dists[i]<minDist.first)
374 minDist.first= dists[i];
381 nRotations=minDist.second;
382 if (minDist.first!=0)
386 cv::Mat bits=Rotations [ minDist.second];
387 for (
int y=0;y<5;y++)
390 if ( bits.at<uchar>(y,1)) MatID|=1;
392 if ( bits.at<uchar>(y,3)) MatID|=1;
405 int FiducidalMarkers::detect(
const Mat &in,
int &nRotations)
407 assert(in.rows==in.cols);
409 if ( in.type()==CV_8UC1) grey=in;
410 else cv::cvtColor(in,grey,CV_BGR2GRAY);
412 threshold(grey, grey,125, 255, THRESH_BINARY|THRESH_OTSU);
417 return analyzeMarkerImage(grey,nRotations);;
426 vector<int> FiducidalMarkers::getListOfValidMarkersIds_random(
int nMarkers,vector<int> *excluded)
throw (cv::Exception)
430 if (nMarkers+excluded->size()>1024)
throw cv::Exception(8888,
"FiducidalMarkers::getListOfValidMarkersIds_random",
"Number of possible markers is exceeded",__FILE__,__LINE__);
432 vector<int> listOfMarkers(1024);
434 for (
int i=0;i<1024;i++) listOfMarkers[i]=i;
437 for (
size_t i=0;i<excluded->size();++i)
438 listOfMarkers[excluded->at(i)]=-1;
440 random_shuffle(listOfMarkers.begin(),listOfMarkers.end());
444 while (static_cast<int>(retList.size())<nMarkers) {
445 if (listOfMarkers[i]!=-1)
446 retList.push_back(listOfMarkers[i]);
This class defines a board with several markers. A Board contains several markers so that they are mo...