39 void Marker::VisualizeMarkerPose(IplImage *
image,
Camera *
cam,
double visualize2d_points[12][2], CvScalar color)
const {
41 for (
int i=0; i<4; i++) {
42 cvLine(image, cvPoint((
int)visualize2d_points[i][0], (
int)visualize2d_points[i][1]), cvPoint((
int)visualize2d_points[(i+1)%4][0], (
int)visualize2d_points[(i+1)%4][1]), color);
43 cvLine(image, cvPoint((
int)visualize2d_points[i][0], (
int)visualize2d_points[i][1]), cvPoint((
int)visualize2d_points[4+i][0], (
int)visualize2d_points[4+i][1]), color);
44 cvLine(image, cvPoint((
int)visualize2d_points[4+i][0], (
int)visualize2d_points[4+i][1]), cvPoint((
int)visualize2d_points[4+((i+1)%4)][0], (
int)visualize2d_points[4+((i+1)%4)][1]), color);
47 cvLine(image, cvPoint((
int)visualize2d_points[8][0], (
int)visualize2d_points[8][1]), cvPoint((
int)visualize2d_points[9][0], (
int)visualize2d_points[9][1]), CV_RGB(255,0,0));
48 cvLine(image, cvPoint((
int)visualize2d_points[8][0], (
int)visualize2d_points[8][1]), cvPoint((
int)visualize2d_points[10][0], (
int)visualize2d_points[10][1]), CV_RGB(0,255,0));
49 cvLine(image, cvPoint((
int)visualize2d_points[8][0], (
int)visualize2d_points[8][1]), cvPoint((
int)visualize2d_points[11][0], (
int)visualize2d_points[11][1]), CV_RGB(0,0,255));
52 void Marker::VisualizeMarkerContent(IplImage *
image,
Camera *
cam,
double datatext_point[2],
double content_point[2])
const {
53 #ifdef VISUALIZE_MARKER_POINTS 54 for (
size_t i=0; i<marker_allpoints_img.size(); i++) {
55 if (marker_allpoints_img[i].val == 0)
56 cvCircle(image, cvPoint(
int(marker_allpoints_img[i].
x),
int(marker_allpoints_img[i].
y)), 1, CV_RGB(0, 255,0));
57 else if (marker_allpoints_img[i].val == 255)
58 cvCircle(image, cvPoint(
int(marker_allpoints_img[i].x),
int(marker_allpoints_img[i].y)), 1, CV_RGB(255, 0,0));
60 cvCircle(image, cvPoint(
int(marker_allpoints_img[i].x),
int(marker_allpoints_img[i].y)), 2, CV_RGB(255,255,0));
66 cvInitFont(&font, 0, 0.5, 0.5, 0);
67 std::stringstream val;
69 cvPutText(image, val.str().c_str(), cvPoint((
int)datatext_point[0], (
int)datatext_point[1]), &
font, CV_RGB(255,255,0));
72 int xc = int(content_point[0]);
73 int yc = int(content_point[1]);
74 for (
int j=0; j<
res*3; j++) {
75 for (
int i=0; i<res*3; i++) {
78 if ((x >= 0) && (x < image->
width) &&
79 (y >= 0) && (y < image->
height))
81 if (cvGet2D(marker_content, j/3, i/3).val[0]) {
82 cvSet2D(image, y, x, CV_RGB(255,255,255));
84 cvSet2D(image, y, x, CV_RGB(0,0,0));
91 void Marker::VisualizeMarkerError(IplImage *
image,
Camera *
cam,
double errortext_point[2])
const {
93 cvInitFont(&font, 0, 0.5, 0.5, 0);
94 std::stringstream val;
95 if (GetError(MARGIN_ERROR|DECODE_ERROR) > 0) {
97 val<<int(GetError(MARGIN_ERROR)*100)<<
"% ";
98 val<<int(GetError(DECODE_ERROR)*100)<<
"% ";
99 cvPutText(image, val.str().c_str(), cvPoint((
int)errortext_point[0], (
int)errortext_point[1]), &
font, CV_RGB(255,0,0));
100 }
else if (GetError(TRACK_ERROR) > 0.01) {
102 val<<int(GetError(TRACK_ERROR)*100)<<
"%";
103 cvPutText(image, val.str().c_str(), cvPoint((
int)errortext_point[0], (
int)errortext_point[1]), &
font, CV_RGB(128,0,0));
107 void MarkerData::VisualizeMarkerContent(IplImage *
image,
Camera *
cam,
double datatext_point[2],
double content_point[2])
const {
108 #ifdef VISUALIZE_MARKER_POINTS 109 for (
size_t i=0; i<marker_allpoints_img.size(); i++) {
110 if (marker_allpoints_img[i].val == 0)
111 cvCircle(image, cvPoint(
int(marker_allpoints_img[i].
x),
int(marker_allpoints_img[i].
y)), 1, CV_RGB(0, 255,0));
112 else if (marker_allpoints_img[i].val == 255)
113 cvCircle(image, cvPoint(
int(marker_allpoints_img[i].x),
int(marker_allpoints_img[i].y)), 1, CV_RGB(255, 0,0));
115 cvCircle(image, cvPoint(
int(marker_allpoints_img[i].x),
int(marker_allpoints_img[i].y)), 2, CV_RGB(255,255,0));
121 cvInitFont(&font, 0, 0.5, 0.5, 0);
122 std::stringstream val;
123 CvScalar rgb=CV_RGB(255,255,0);
124 if (content_type == MARKER_CONTENT_TYPE_NUMBER) {
127 if (content_type == MARKER_CONTENT_TYPE_FILE) rgb=CV_RGB(0,255,255);
128 if (content_type == MARKER_CONTENT_TYPE_HTTP) rgb=CV_RGB(255,0,255);
131 cvPutText(image, val.str().c_str(), cvPoint((
int)datatext_point[0], (
int)datatext_point[1]), &
font, rgb);
135 double visualize3d_points[12][3] = {
137 { -(edge_length/2), -(edge_length/2), 0 },
138 { -(edge_length/2), (edge_length/2), 0 },
139 { (edge_length/2), (edge_length/2), 0 },
140 { (edge_length/2), -(edge_length/2), 0 },
141 { -(edge_length/2), -(edge_length/2), edge_length },
142 { -(edge_length/2), (edge_length/2), edge_length },
143 { (edge_length/2), (edge_length/2), edge_length },
144 { (edge_length/2), -(edge_length/2), edge_length },
147 { edge_length, 0, 0 },
148 { 0, edge_length, 0 },
149 { 0, 0, edge_length },
151 double visualize2d_points[12][2];
152 CvMat visualize3d_points_mat;
153 CvMat visualize2d_points_mat;
154 cvInitMatHeader(&visualize3d_points_mat, 12, 3, CV_64F, visualize3d_points);
155 cvInitMatHeader(&visualize2d_points_mat, 12, 2, CV_64F, visualize2d_points);
156 cam->
ProjectPoints(&visualize3d_points_mat, &pose, &visualize2d_points_mat);
158 VisualizeMarkerPose(image, cam, visualize2d_points, color);
159 VisualizeMarkerContent(image, cam, visualize2d_points[0], visualize2d_points[8]);
160 VisualizeMarkerError(image, cam, visualize2d_points[2]);
163 void Marker::CompareCorners(vector<PointDouble > &_marker_corners_img,
int *orientation,
double *error) {
164 vector<PointDouble >::iterator corners_new = _marker_corners_img.begin();
165 vector<PointDouble >::const_iterator corners_old = marker_corners_img.begin();
166 vector<double> errors(4);
167 for (
int i=0; i<4; i++) {
173 *orientation = min_element(errors.begin(), errors.end()) - errors.begin();
174 *error = sqrt(errors[*orientation]/4);
178 void Marker::CompareContent(vector<PointDouble > &_marker_corners_img, IplImage *
gray,
Camera *
cam,
int *orientation)
const {
184 bool Marker::UpdateContent(vector<PointDouble > &_marker_corners_img, IplImage *
gray,
Camera *
cam,
int frame_no ) {
185 return UpdateContentBasic(_marker_corners_img, gray, cam, frame_no);
188 bool Marker::UpdateContentBasic(vector<PointDouble > &_marker_corners_img, IplImage *
gray,
Camera *
cam,
int frame_no ) {
189 vector<PointDouble > marker_corners_img_undist;
190 marker_corners_img_undist.resize(_marker_corners_img.size());
191 copy(_marker_corners_img.begin(), _marker_corners_img.end(), marker_corners_img_undist.begin());
195 vector<PointDouble> marker_points_img(marker_points.size());
196 marker_points_img.resize(marker_points.size());
197 cam->
Undistort(marker_corners_img_undist);
198 H.Find(marker_corners, marker_corners_img_undist);
199 H.ProjectPoints(marker_points, marker_points_img);
200 cam->
Distort(marker_points_img);
202 ros_marker_points_img.clear();
206 double min = 255.0, max = 0.0;
207 for (
int j=0; j<marker_content->height; j++) {
208 for (
int i=0; i<marker_content->width; i++) {
209 x = (int)(0.5+
Limit(marker_points_img[(j*marker_content->width)+i].x, 1, gray->width-2));
210 y = (int)(0.5+
Limit(marker_points_img[(j*marker_content->width)+i].y, 1, gray->height-2));
212 marker_points_img[(j*marker_content->width)+i].val = (
int)cvGetReal2D(gray, y, x);
229 cvSet2D(marker_content, j, i, cvScalar(marker_points_img[(j*marker_content->width)+i].val));
230 if(marker_points_img[(j*marker_content->width)+i].val > max) max = marker_points_img[(j*marker_content->width)+i].val;
231 if(marker_points_img[(j*marker_content->width)+i].val < min) min = marker_points_img[(j*marker_content->width)+i].val;
237 vector<PointDouble> marker_margin_w_img(marker_margin_w.size());
238 vector<PointDouble> marker_margin_b_img(marker_margin_b.size());
239 H.ProjectPoints(marker_margin_w, marker_margin_w_img);
240 H.ProjectPoints(marker_margin_b, marker_margin_b_img);
241 cam->
Distort(marker_margin_w_img);
242 cam->
Distort(marker_margin_b_img);
245 for (
size_t i=0; i<marker_margin_w_img.size(); i++) {
246 x = (int)(0.5+
Limit(marker_margin_w_img[i].x, 0, gray->width-1));
247 y = (int)(0.5+
Limit(marker_margin_w_img[i].y, 0, gray->height-1));
248 marker_margin_w_img[i].val = (int)cvGetReal2D(gray, y, x);
249 max += marker_margin_w_img[i].val;
253 for (
size_t i=0; i<marker_margin_b_img.size(); i++) {
254 x = (int)(0.5+
Limit(marker_margin_b_img[i].x, 0, gray->width-1));
255 y = (int)(0.5+
Limit(marker_margin_b_img[i].y, 0, gray->height-1));
256 marker_margin_b_img[i].val = (int)cvGetReal2D(gray, y, x);
257 min += marker_margin_b_img[i].val;
262 max /= marker_margin_w_img.size();
263 min /= marker_margin_b_img.size();
266 cvThreshold(marker_content, marker_content, (max+min)/2.0, 255, CV_THRESH_BINARY);
271 for (
size_t i=0; i<marker_margin_w_img.size(); i++) {
272 if (marker_margin_w_img[i].val < (max+min)/2.0) erroneous++;
275 for (
size_t i=0; i<marker_margin_b_img.size(); i++) {
276 if (marker_margin_b_img[i].val > (max+min)/2.0) erroneous++;
279 margin_error = (double)erroneous/total;
282 #ifdef VISUALIZE_MARKER_POINTS 285 marker_allpoints_img.clear();
286 for (
size_t i=0; i<marker_margin_w_img.size(); i++) {
288 if (p.val < (max+min)/2.0) p.val=255;
290 marker_allpoints_img.push_back(p);
292 for (
size_t i=0; i<marker_margin_b_img.size(); i++) {
294 if (p.val > (max+min)/2.0) p.val=255;
296 marker_allpoints_img.push_back(p);
298 for (
size_t i=0; i<marker_points_img.size(); i++) {
301 marker_allpoints_img.push_back(p);
306 void Marker::UpdatePose(vector<PointDouble > &_marker_corners_img,
Camera *
cam,
int orientation,
int frame_no ,
bool update_pose ) {
307 marker_corners_img.resize(_marker_corners_img.size());
308 copy(_marker_corners_img.begin(), _marker_corners_img.end(), marker_corners_img.begin());
312 std::rotate(marker_corners_img.begin(), marker_corners_img.begin() + orientation, marker_corners_img.end());
316 bool Marker::DecodeContent(
int *orientation) {
322 void Marker::SaveMarkerImage(
const char *filename,
int save_res)
const {
330 IplImage *img = cvCreateImage(cvSize(save_res, save_res), IPL_DEPTH_8U, 1);
331 IplImage *img_content = cvCreateImage(cvSize(
int(
res*scale+0.5),
int(
res*scale+0.5)), IPL_DEPTH_8U, 1);
334 cvGetSubRect(img, &submat, cvRect(
int(
margin*scale),
int(
margin*scale),
int(
res*scale),
int(
res*scale)));
335 cvResize(marker_content, img_content, CV_INTER_NN);
336 cvCopy(img_content, &submat);
337 cvSaveImage(filename, img);
338 cvReleaseImage(&img_content);
339 cvReleaseImage(&img);
342 void Marker::ScaleMarkerToImage(IplImage *
image)
const {
343 const int multiplier=96;
345 IplImage *img_content = cvCreateImage(cvSize(
int(multiplier*
res+0.5),
int(multiplier*
res+0.5)), IPL_DEPTH_8U, 1);
348 cvGetSubRect(img, &submat, cvRect(
int(multiplier*
margin+0.5),
int(multiplier*
margin+0.5),
int(multiplier*
res+0.5),
int(multiplier*
res+0.5)));
349 cvResize(marker_content, img_content, CV_INTER_NN);
350 cvCopy(img_content, &submat);
351 cvResize(img, image, CV_INTER_NN);
352 cvReleaseImage(&img_content);
353 cvReleaseImage(&img);
356 void Marker::SetMarkerSize(
double _edge_length,
int _res,
double _margin) {
358 edge_length = (_edge_length?_edge_length:1);
360 margin = (_margin?_margin:1);
361 double x_min = -0.5*edge_length;
362 double y_min = -0.5*edge_length;
363 double x_max = 0.5*edge_length;
364 double y_max = 0.5*edge_length;
372 marker_corners_img.resize(4);
375 marker_corners.clear();
376 marker_corners.push_back(
PointDouble(x_min, y_min));
377 marker_corners.push_back(
PointDouble(x_max, y_min));
378 marker_corners.push_back(
PointDouble(x_max, y_max));
379 marker_corners.push_back(
PointDouble(x_min, y_max));
382 if (
res <= 0)
return;
385 marker_points.clear();
386 for(
int j = 0; j <
res; ++j) {
387 for(
int i = 0; i <
res; ++i) {
389 pt.y = cy_max - (step*j) - (step/2);
390 pt.x = cx_min + (step*i) + (step/2);
391 marker_points.push_back(pt);
398 marker_margin_w.clear();
399 marker_margin_b.clear();
400 for(
int j = -1; j<=
margin-1; j++) {
403 for (
int i=0; i<
res; i++) {
404 pt.x = cx_min + step*i + step/2;
405 pt.y = y_min + step*j + step/2;
406 if (j < 0) marker_margin_w.push_back(pt);
407 else marker_margin_b.push_back(pt);
408 pt.y = y_max - step*j - step/2;
409 if (j < 0) marker_margin_w.push_back(pt);
410 else marker_margin_b.push_back(pt);
411 pt.y = cy_min + step*i + step/2;
412 pt.x = x_min + step*j + step/2;
413 if (j < 0) marker_margin_w.push_back(pt);
414 else marker_margin_b.push_back(pt);
415 pt.x = x_max - step*j - step/2;
416 if (j < 0) marker_margin_w.push_back(pt);
417 else marker_margin_b.push_back(pt);
420 for(
int i = -1; i<=
margin-1; i++) {
421 pt.x = x_min + step*i + step/2;
422 pt.y = y_min + step*j + step/2;
423 if ((j < 0) || (i < 0)) marker_margin_w.push_back(pt);
424 else marker_margin_b.push_back(pt);
425 pt.x = x_min + step*i + step/2;
426 pt.y = y_max - step*j - step/2;
427 if ((j < 0) || (i < 0)) marker_margin_w.push_back(pt);
428 else marker_margin_b.push_back(pt);
429 pt.x = x_max - step*i - step/2;
430 pt.y = y_max - step*j - step/2;
431 if ((j < 0) || (i < 0)) marker_margin_w.push_back(pt);
432 else marker_margin_b.push_back(pt);
433 pt.x = x_max - step*i - step/2;
434 pt.y = y_min + step*j + step/2;
435 if ((j < 0) || (i < 0)) marker_margin_w.push_back(pt);
436 else marker_margin_b.push_back(pt);
511 if (marker_content) cvReleaseMat(&marker_content);
512 marker_content = cvCreateMat(res, res, CV_8U);
513 cvSet(marker_content, cvScalar(255));
516 if (marker_content) cvReleaseMat(&marker_content);
518 Marker::Marker(
double _edge_length,
int _res,
double _margin)
520 marker_content = NULL;
524 SetMarkerSize(_edge_length, _res, _margin);
525 ros_orientation = -1;
526 ros_corners_3D.resize(4);
530 marker_content = NULL;
552 #ifdef VISUALIZE_MARKER_POINTS 553 marker_allpoints_img.resize(m.marker_allpoints_img.size());
554 copy(m.marker_allpoints_img.begin(), m.marker_allpoints_img.end(), marker_allpoints_img.begin());
558 bool MarkerArtoolkit::DecodeContent(
int *orientation) {
559 int a = (int)cvGetReal2D(marker_content, 0, 0);
560 int b = (int)cvGetReal2D(marker_content,
res-1, 0);
561 int c = (int)cvGetReal2D(marker_content,
res-1,
res-1);
562 int d = (int)cvGetReal2D(marker_content, 0,
res-1);
563 if (!a && !b && c) *orientation = 0;
564 else if (!b && !c && d) *orientation = 1;
565 else if (!c && !d && a) *orientation = 2;
566 else if (!d && !a && b) *orientation = 3;
571 for (
int j = 0; j <
res; j++) {
572 for (
int i = 0; i <
res ; i++) {
573 if (*orientation == 0) {
574 if ((j == 0) && (i == 0))
continue;
575 if ((j == res-1) && (i == 0))
continue;
576 if ((j == res-1) && (i == res-1))
continue;
577 if (cvGetReal2D(marker_content, j, i)) bs.
push_back(
false);
580 else if (*orientation == 1) {
581 if (((res-i-1) == res-1) && (j == 0))
continue;
582 if (((res-i-1) == res-1) && (j == res-1))
continue;
583 if (((res-i-1) == 0) && (j == res-1))
continue;
584 if (cvGetReal2D(marker_content, res-i-1, j)) bs.
push_back(
false);
587 else if (*orientation == 2) {
588 if (((res-j-1) == res-1) && ((res-i-1) == res-1))
continue;
589 if (((res-j-1) == 0) && ((res-i-1) == res-1))
continue;
590 if (((res-j-1) == 0) && ((res-i-1) == 0))
continue;
591 if (cvGetReal2D(marker_content, res-j-1, res-i-1)) bs.
push_back(
false);
594 else if (*orientation == 3) {
595 if ((i == 0) && ((res-j-1) == res-1))
continue;
596 if ((i == 0) && ((res-j-1) == 0))
continue;
597 if ((i == res-1) && ((res-j-1) == 0))
continue;
598 if (cvGetReal2D(marker_content, i, res-j-1)) bs.
push_back(
false);
607 void MarkerArtoolkit::SetContent(
unsigned long _id) {
614 for (
int j =
res-1; j >= 0; j--) {
615 for (
int i =
res-1; i >= 0 ; i--) {
616 if ((j == 0) && (i == 0))
617 cvSetReal2D(marker_content, j, i, 0);
618 else if ((j ==
res-1) && (i == 0))
619 cvSetReal2D(marker_content, j, i, 0);
620 else if ((j ==
res-1) && (i ==
res-1))
621 cvSetReal2D(marker_content, j, i, 255);
624 cvSetReal2D(marker_content, j, i, 0);
626 cvSetReal2D(marker_content, j, i, 255);
632 void MarkerData::DecodeOrientation(
int *error,
int *total,
int *orientation) {
634 vector<double> errors(4);
639 for (i=0; i<
res; i++) {
641 if ((
int)cvGetReal2D(marker_content, j, i) != color) errors[0]++;
642 if ((
int)cvGetReal2D(marker_content, i, j) != color) errors[1]++;
643 color = (color?0:255);
645 errors[2] = errors[0];
646 errors[3] = errors[1];
650 for (j = (res/2)-2; j <= (res/2)+2; j++) {
653 if ((
int)cvGetReal2D(marker_content, j, i) != 0) errors[0]++;
654 if ((
int)cvGetReal2D(marker_content, i, j) != 0) errors[1]++;
655 if ((
int)cvGetReal2D(marker_content, j, i) != 255) errors[2]++;
656 if ((
int)cvGetReal2D(marker_content, i, j) != 255) errors[3]++;
657 }
else if (j > (res/2)) {
659 if ((
int)cvGetReal2D(marker_content, j, i) != 255) errors[0]++;
660 if ((
int)cvGetReal2D(marker_content, i, j) != 255) errors[1]++;
661 if ((
int)cvGetReal2D(marker_content, j, i) != 0) errors[2]++;
662 if ((
int)cvGetReal2D(marker_content, i, j) != 0) errors[3]++;
665 *orientation = min_element(errors.begin(), errors.end()) - errors.begin();
666 *error = int(errors[*orientation]);
670 bool MarkerData::DetectResolution(vector<PointDouble > &_marker_corners_img, IplImage *
gray,
Camera *
cam) {
671 vector<PointDouble> marker_corners_img_undist;
672 marker_corners_img_undist.resize(_marker_corners_img.size());
673 copy(_marker_corners_img.begin(), _marker_corners_img.end(), marker_corners_img_undist.begin());
676 std::vector<PointDouble> line_points;
679 pt.x=0; pt.y=0; line_points.push_back(pt);
680 pt.x=-0.5*edge_length; pt.y=0; line_points.push_back(pt);
681 pt.x=+0.5*edge_length; pt.y=0; line_points.push_back(pt);
682 pt.x=0; pt.y=-0.5*edge_length; line_points.push_back(pt);
683 pt.x=0; pt.y=+0.5*edge_length; line_points.push_back(pt);
690 vector<PointDouble> line_points_img(line_points.size());
691 line_points_img.resize(line_points.size());
692 cam->
Undistort(marker_corners_img_undist);
693 H.
Find(marker_corners, marker_corners_img_undist);
699 int white_count[4] = {0};
701 pt2.x = int(line_points_img[0].
x);
702 pt2.y = int(line_points_img[0].
y);
703 if ((pt2.x < 0) || (pt2.y < 0) ||
704 (pt2.x >= gray->width) || (pt2.y >= gray->height))
709 for (
int i=0; i<4; i++) {
710 CvLineIterator iterator;
711 pt1.x = int(line_points_img[i+1].x);
712 pt1.y = int(line_points_img[i+1].y);
713 if ((pt1.x < 0) || (pt1.y < 0) ||
714 (pt1.x >= gray->width) || (pt1.y >= gray->height))
718 int count = cvInitLineIterator(gray, pt1, pt2, &iterator, 8, 0);
719 std::vector<uchar> vals;
720 for(
int ii = 0; ii < count; ii++ ){
721 CV_NEXT_LINE_POINT(iterator);
722 vals.push_back(*(iterator.ptr));
724 uchar vmin = *(std::min_element(vals.begin(), vals.end()));
725 uchar vmax = *(std::max_element(vals.begin(), vals.end()));
726 uchar thresh = (vmin+vmax)/2;
729 for (
size_t ii=0; ii<vals.size(); ii++) {
732 if (vals[ii] < thresh) { bc++; wc=0; }
735 if (white && (bc >= N)) {
738 else if (!white && (wc >= N)) {
745 if ((white_count[0]+white_count[1]) == (white_count[2]+white_count[3]))
return false;
746 else if ((white_count[0]+white_count[1]) > (white_count[2]+white_count[3])) {
747 if (white_count[0] != white_count[1])
return false;
748 if (white_count[0] < 2)
return false;
749 int nof_whites = white_count[0]*2-(white?1:0);
750 int new_res = 2*nof_whites-1;
751 SetMarkerSize(edge_length, new_res,
margin);
754 if (white_count[2] != white_count[3])
return false;
755 if (white_count[2] < 2)
return false;
756 if (((white_count[2]%2) == 0) != white)
return false;
757 int nof_whites = white_count[2]*2-(white?1:0);
758 int new_res = 2*nof_whites-1;
759 SetMarkerSize(edge_length, new_res,
margin);
764 bool MarkerData::UpdateContent(vector<PointDouble > &_marker_corners_img, IplImage *
gray,
Camera *
cam,
int frame_no ) {
766 if (!DetectResolution(_marker_corners_img, gray, cam))
return false;
768 return UpdateContentBasic(_marker_corners_img, gray, cam, frame_no);
771 int MarkerData::DecodeCode(
int orientation,
BitsetExt *bs,
int *erroneous,
int *total,
772 unsigned char* content_type)
776 for (
int j = 0; j <
res; j++) {
777 for (
int i = 0; i <
res ; i++) {
779 if ((orientation == 0) || (orientation == 2)) {
780 if (j == res/2)
continue;
781 if ((i == res/2) && (j >= (res/2)-2) && (j <= (res/2)+2))
continue;
783 if (i == res/2)
continue;
784 if ((j == res/2) && (i >= (res/2)-2) && (i <= (res/2)+2))
continue;
787 if (orientation == 0) color = (int)cvGetReal2D(marker_content, j, i);
788 else if (orientation == 1) color = (int)cvGetReal2D(marker_content, res-i-1, j);
789 else if (orientation == 2) color = (int)cvGetReal2D(marker_content, res-j-1, res-i-1);
790 else if (orientation == 3) color = (int)cvGetReal2D(marker_content, i, res-j-1);
797 unsigned char flags = 0;
815 flags = header.
uchar();
818 flags &= MARKER_CONTENT_TYPE_NUMBER;
824 *content_type = flags & 0x7;
826 if (errors > 0) (*erroneous) += errors;
829 void MarkerData::Read6bitStr(
BitsetExt *bs,
char *s,
size_t s_max_len) {
830 deque<bool> bits = bs->
GetBits();
831 deque<bool>::const_iterator iter;
835 for (iter = bits.begin(); iter != bits.end(); iter++) {
836 if (*iter) c |= (0x01 << bitpos);
839 if (c == 000) s[len] =
':';
840 else if ((c >= 001) && (c <= 032)) s[len] =
'a' + (char)c - 1;
841 else if ((c >= 033) && (c <= 044)) s[len] =
'0' + (char)c - 1;
842 else if (c == 045) s[len] =
'+';
843 else if (c == 046) s[len] =
'-';
844 else if (c == 047) s[len] =
'*';
845 else if (c == 050) s[len] =
'/';
846 else if (c == 051) s[len] =
'(';
847 else if (c == 052) s[len] =
')';
848 else if (c == 053) s[len] =
'$';
849 else if (c == 054) s[len] =
'=';
850 else if (c == 055) s[len] =
' ';
851 else if (c == 056) s[len] =
',';
852 else if (c == 057) s[len] =
'.';
853 else if (c == 060) s[len] =
'#';
854 else if (c == 061) s[len] =
'[';
855 else if (c == 062) s[len] =
']';
856 else if (c == 063) s[len] =
'%';
857 else if (c == 064) s[len] =
'\"';
858 else if (c == 065) s[len] =
'_';
859 else if (c == 066) s[len] =
'!';
860 else if (c == 067) s[len] =
'&';
861 else if (c == 070) s[len] =
'\'';
862 else if (c == 071) s[len] =
'?';
863 else if (c == 072) s[len] =
'<';
864 else if (c == 073) s[len] =
'>';
865 else if (c == 074) s[len] =
'@';
866 else if (c == 075) s[len] =
'\\';
867 else if (c == 076) s[len] =
'^';
868 else if (c == 077) s[len] =
';';
871 if (len >= (s_max_len-1))
break;
878 bool MarkerData::DecodeContent(
int *orientation) {
886 DecodeOrientation(&erroneous, &total, orientation);
887 int err = DecodeCode(*orientation, &bs, &erroneous, &total, &content_type);
890 decode_error = DBL_MAX;
894 if(content_type == MARKER_CONTENT_TYPE_NUMBER){
895 data.id = bs.
ulong();
898 Read6bitStr(&bs, data.str, MAX_MARKER_STRING_LEN);
901 decode_error = (double)(erroneous)/total;
908 unsigned char c = (
unsigned char)*s;
909 if (c ==
':') bs->
push_back((
unsigned char)0,6);
910 else if ((c >=
'A') && (c <=
'Z')) bs->
push_back((
unsigned char)(001 + c -
'A'),6);
911 else if ((c >=
'a') && (c <=
'z')) bs->
push_back((
unsigned char)(001 + c -
'a'),6);
912 else if ((c >=
'0') && (c <=
'9')) bs->
push_back((
unsigned char)(033 + c -
'0'),6);
913 else if (c ==
'+') bs->
push_back((
unsigned char)045,6);
914 else if (c ==
'-') bs->
push_back((
unsigned char)046,6);
915 else if (c ==
'*') bs->
push_back((
unsigned char)047,6);
916 else if (c ==
'/') bs->
push_back((
unsigned char)050,6);
917 else if (c ==
'(') bs->
push_back((
unsigned char)051,6);
918 else if (c ==
')') bs->
push_back((
unsigned char)052,6);
919 else if (c ==
'$') bs->
push_back((
unsigned char)053,6);
920 else if (c ==
'=') bs->
push_back((
unsigned char)054,6);
921 else if (c ==
' ') bs->
push_back((
unsigned char)055,6);
922 else if (c ==
',') bs->
push_back((
unsigned char)056,6);
923 else if (c ==
'.') bs->
push_back((
unsigned char)057,6);
924 else if (c ==
'#') bs->
push_back((
unsigned char)060,6);
925 else if (c ==
'[') bs->
push_back((
unsigned char)061,6);
926 else if (c ==
']') bs->
push_back((
unsigned char)062,6);
927 else if (c ==
'%') bs->
push_back((
unsigned char)063,6);
928 else if (c ==
'\"') bs->
push_back((
unsigned char)064,6);
929 else if (c ==
'_') bs->
push_back((
unsigned char)065,6);
930 else if (c ==
'!') bs->
push_back((
unsigned char)066,6);
931 else if (c ==
'&') bs->
push_back((
unsigned char)067,6);
932 else if (c ==
'\'') bs->
push_back((
unsigned char)070,6);
933 else if (c ==
'?') bs->
push_back((
unsigned char)071,6);
934 else if (c ==
'<') bs->
push_back((
unsigned char)072,6);
935 else if (c ==
'>') bs->
push_back((
unsigned char)073,6);
936 else if (c ==
'@') bs->
push_back((
unsigned char)074,6);
937 else if (c ==
'\\') bs->
push_back((
unsigned char)075,6);
938 else if (c ==
'^') bs->
push_back((
unsigned char)076,6);
939 else if (c ==
';') bs->
push_back((
unsigned char)077,6);
940 else bs->
push_back((
unsigned char)071,6);
945 int MarkerData::UsableDataBits(
int marker_res,
int hamming) {
946 if (marker_res < 5)
return 0;
947 if (!(marker_res % 2))
return 0;
948 int bits = marker_res * marker_res;
949 if (marker_res > 5) bits -= 8;
952 int tail = bits % hamming;
953 if (tail < 3) bits -= tail;
957 void MarkerData::SetContent(
MarkerContentType _content_type,
unsigned long _id,
const char *_str,
bool force_strong_hamming,
bool verbose) {
959 content_type = _content_type;
962 if (content_type == MARKER_CONTENT_TYPE_NUMBER) {
965 STRCPY(data.str, MAX_MARKER_STRING_LEN, _str);
968 const int max_marker_res = 127;
974 if (content_type == MARKER_CONTENT_TYPE_NUMBER) {
976 for (
res=5;
res<max_marker_res;
res+=2) {
978 enc_bits = UsableDataBits(
res, hamming);
979 data_bits = BitsetExt::count_hamming_dec_len(hamming, enc_bits);
980 if (data_bits >= bs_data.
Length())
break;
981 if ((
res > 5) && !force_strong_hamming) {
983 enc_bits = UsableDataBits(
res, hamming);
984 data_bits = BitsetExt::count_hamming_dec_len(hamming, enc_bits);
985 if (data_bits >= bs_data.
Length())
break;
991 cout<<
"Using hamming("<<hamming<<
") for "<<
res<<
"x"<<
res<<
" marker"<<endl;
992 cout<<bs_data.
Length()<<
" bits are filled into "<<data_bits;
993 cout<<
" bits, and encoded into "<<enc_bits<<
" bits"<<endl;
994 cout<<
"data src: "; bs_data.
Output(cout); cout<<endl;
995 cout<<
"data enc: "; bs_data.
Output(cout); cout<<endl;
998 if (hamming == 16) bs_flags.
push_back(
true);
1003 cout<<
"flags src: "; bs_flags.
Output(cout); cout<<endl;
1004 cout<<
"flags enc: "; bs_flags.
Output(cout); cout<<endl;
1008 Add6bitStr(&bs_data, data.str);
1009 for (
res=7;
res<max_marker_res;
res+=2) {
1011 enc_bits = UsableDataBits(
res, hamming);
1012 data_bits = BitsetExt::count_hamming_dec_len(hamming, enc_bits);
1013 if (data_bits >= bs_data.
Length())
break;
1014 if (!force_strong_hamming) {
1016 enc_bits = UsableDataBits(
res, hamming);
1017 data_bits = BitsetExt::count_hamming_dec_len(hamming, enc_bits);
1018 if (data_bits >= bs_data.
Length())
break;
1021 while (bs_data.
Length() < ((data_bits/6)*6)) {
1022 bs_data.
push_back((
unsigned char)055,6);
1024 while (bs_data.
Length() < data_bits) {
1028 if (hamming == 16) bs_flags.
push_back(
true);
1030 if (content_type == MARKER_CONTENT_TYPE_STRING) bs_flags.
push_back((
unsigned long)1,3);
1031 else if (content_type == MARKER_CONTENT_TYPE_FILE) bs_flags.
push_back((
unsigned long)2,3);
1032 else if (content_type == MARKER_CONTENT_TYPE_HTTP) bs_flags.
push_back((
unsigned long)3,3);
1035 cout<<
"Using hamming("<<hamming<<
") for "<<
res<<
"x"<<
res<<
" marker"<<endl;
1036 cout<<bs_data.
Length()<<
" bits are filled into "<<data_bits;
1037 cout<<
" bits, and encoded into "<<enc_bits<<
" bits"<<endl;
1038 cout<<
"data src: "; bs_data.
Output(cout); cout<<endl;
1039 cout<<
"data enc: "; bs_data.
Output(cout); cout<<endl;
1040 cout<<
"flags src: "; bs_flags.
Output(cout); cout<<endl;
1041 cout<<
"flags enc: "; bs_flags.
Output(cout); cout<<endl;
1046 deque<bool> bs(bs_flags.
GetBits());
1047 bs.insert(bs.end(), bs_data.
GetBits().begin(), bs_data.
GetBits().end());
1048 deque<bool>::const_iterator iter = bs.begin();
1049 SetMarkerSize(edge_length,
res,
margin);
1050 cvSet(marker_content, cvScalar(255));
1051 for (
int j=0; j<
res; j++) {
1052 for (
int i=0; i<
res; i++) {
1054 if (i%2) cvSet2D(marker_content, j, i, cvScalar(0));
1055 }
else if ((i == res/2) && (j < res/2) && (j >= (res/2)-2)) {
1056 cvSet2D(marker_content, j, i, cvScalar(0));
1057 }
else if ((i == res/2) && (j > res/2) && (j <= (res/2)+2)) {
1058 cvSet2D(marker_content, j, i, cvScalar(255));
1060 if (iter != bs.end()) {
1061 if (*iter) cvSet2D(marker_content, j, i, cvScalar(0));
void clear()
Clear the bits.
bool pop_back()
Pop the back bit.
std::vector< PointDouble > marker_corners_img
Marker corners in image coordinates.
Simple Homography class for finding and projecting points between two planes.
unsigned long ulong()
The Bitset as 'unsigned long'.
TFSIMD_FORCE_INLINE const tfScalar & y() const
std::ostream & Output(std::ostream &os) const
Output the bits to selected ostream.
Simple Camera class for calculating distortions, orientation or projections with pre-calibrated camer...
bool pop_front()
Pop the front bit.
void fill_zeros_left(const size_t bit_count)
Fill the Bitset with non-meaningful zeros.
Pose pose
The current marker Pose.
Bitset is a basic class for handling bit sequences
void ProjectPoints(std::vector< CvPoint3D64f > &pw, Pose *pose, std::vector< CvPoint2D64f > &pi) const
Project points.
void Find(const std::vector< PointDouble > &pw, const std::vector< PointDouble > &pi)
Find Homography for two point-sets.
void push_back_meaningful(const unsigned long l)
Push back meaningful bits from 'long' l.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW bool valid
TFSIMD_FORCE_INLINE const tfScalar & x() const
std::vector< PointDouble > ros_marker_points_img
Marker points in image coordinates.
Basic 2D Marker functionality.
double PointSquaredDistance(PointType p1, PointType p2)
Returns the squared distance of two points.
unsigned char uchar()
The Bitset as 'unsigned char'.
int Length()
The length of the Bitset.
std::deque< bool > & GetBits()
The Bitset as 'deque<bool>'.
std::vector< PointDouble > marker_points
Marker color points in marker coordinates.
void Distort(CvPoint2D32f &point)
Applys the lens distortion for one point on an image plane.
int hamming_dec(int block_len)
Hamming decoding 'in-place' using the defined block length.
ALVAR_EXPORT Point< CvPoint2D64f > PointDouble
The default double point type.
Iterator implementation for traversing templated Marker vector without the template.
void ProjectPoints(const std::vector< PointDouble > &from, std::vector< PointDouble > &to)
Project points using the Homography.
void STRCPY(char *to, size_t size, const char *src)
void CalcExteriorOrientation(std::vector< CvPoint3D64f > &pw, std::vector< CvPoint2D64f > &pi, Pose *pose)
Calculate exterior orientation.
void push_back(const bool bit)
Push back one bit.
An extended Bitset ( BitsetExt ) for handling e.g. Hamming encoding/decoding.
This file implements a marker interface as well as ALVAR markers and ARToolKit markers.
This file defines library export definitions, version numbers and build information.
double ALVAR_EXPORT Limit(double val, double min_val, double max_val)
Limits a number to between two values.
ar_track_alvar::ARCloud ros_corners_3D
void Undistort(std::vector< PointDouble > &points)
Unapplys the lens distortion for points on image plane.
std::vector< PointDouble > marker_corners
Marker corners in marker coordinates.
void hamming_enc(int block_len)
Hamming encoding 'in-place' using the defined block length.