BitmapToolkit Scol plugin
ArTkMarker.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25/*
26 Toolkit based on OpenCV library
27 First version : dec 2010
28 Author : Bastien BOURINEAU
29 */
30
31#include <scolPlugin.h>
32
33#include "ArTkMarker.h"
34#include "ArManager.h"
35#include <cstdio>
36
37#include <AR/ar.h>
38#include <AR2/config.h>
39#include <AR2/imageFormat.h>
40#include <AR2/imageSet.h>
41#include <AR2/featureSet.h>
42#include <AR2/util.h>
43
44#include <boost/filesystem.hpp>
45
46#include <set>
47
48#define MIN_TRACKED_MARKER_SIZE 240
49
50extern int AR_MARKER_TRAINNED_CB;
51
55bool NFTDataLoader::LoadData(boost::filesystem::path path, KpmRefDataSet** refDataSetPtr, AR2SurfaceSetT** surfaceSetPtr)
56{
57 if (LoadRefDataSet(path, refDataSetPtr))
58 if (LoadFeatureSet(path, surfaceSetPtr))
59 return true;
60
61 return false;
62}
63
64bool NFTDataLoader::LoadRefDataSet(boost::filesystem::path path, KpmRefDataSet** refDataSetPtr)
65{
66 KpmRefDataSet *refDataSet = NULL;
67 FILE *fp;
68 int i, j;
69
70 if (path.empty() || !refDataSetPtr)
71 {
72 return false;
73 }
74
75 path.replace_extension(".fset3");
76 fp = fopen(path.generic_string().c_str(), "rb");
77 if (!fp)
78 {
79 return false;
80 }
81
82 arMallocClear(refDataSet, KpmRefDataSet, 1);
83
84 if (fread(&(refDataSet->num), sizeof(int), 1, fp) != 1) goto bailBadRead;
85 if (refDataSet->num <= 0) goto bailBadRead;
86
87 arMalloc(refDataSet->refPoint, KpmRefData, refDataSet->num); // each KpmRefData = 68 floats, 3 ints = 284 bytes.
88 for (i = 0; i < refDataSet->num; i++)
89 {
90 if (fread(&(refDataSet->refPoint[i].coord2D), sizeof(KpmCoord2D), 1, fp) != 1) goto bailBadRead;
91 if (fread(&(refDataSet->refPoint[i].coord3D), sizeof(KpmCoord2D), 1, fp) != 1) goto bailBadRead;
92 if (fread(&(refDataSet->refPoint[i].featureVec), sizeof(FreakFeature), 1, fp) != 1) goto bailBadRead;
93 if (fread(&(refDataSet->refPoint[i].pageNo), sizeof(int), 1, fp) != 1) goto bailBadRead;
94 if (fread(&(refDataSet->refPoint[i].refImageNo), sizeof(int), 1, fp) != 1) goto bailBadRead;
95 }
96
97 if (fread(&(refDataSet->pageNum), sizeof(int), 1, fp) != 1) goto bailBadRead;
98 if (refDataSet->pageNum <= 0)
99 {
100 refDataSet->pageInfo = NULL;
101 goto bailBadRead;
102 }
103
104 arMalloc(refDataSet->pageInfo, KpmPageInfo, refDataSet->pageNum);
105 for (i = 0; i < refDataSet->pageNum; i++)
106 {
107 if (fread(&(refDataSet->pageInfo[i].pageNo), sizeof(int), 1, fp) != 1) goto bailBadRead;
108 if (fread(&(refDataSet->pageInfo[i].imageNum), sizeof(int), 1, fp) != 1) goto bailBadRead;
109
110 j = refDataSet->pageInfo[i].imageNum;
111 arMalloc(refDataSet->pageInfo[i].imageInfo, KpmImageInfo, j);
112
113 if (fread(refDataSet->pageInfo[i].imageInfo, sizeof(KpmImageInfo), j, fp) != j) goto bailBadRead;
114 }
115
116 *refDataSetPtr = refDataSet;
117 if (fp)
118 fclose(fp);
119
120 return true;
121
122bailBadRead:
123 if (refDataSet)
124 kpmDeleteRefDataSet(&refDataSet);
125 if (fp)
126 fclose(fp);
127 return false;
128}
129
130bool NFTDataLoader::LoadFeatureSet(boost::filesystem::path path, AR2SurfaceSetT** surfaceSetPtr)
131{
132 int i, j, k;
133 AR2SurfaceSetT* surfaceSet = NULL;
134 FILE *fp = NULL;
135
136 if (path.empty() || !surfaceSetPtr)
137 {
138 return false;
139 }
140
141 arMalloc(surfaceSet, AR2SurfaceSetT, 1);
142
143 surfaceSet->num = 1;
144 surfaceSet->contNum = 0;
145 arMalloc(surfaceSet->surface, AR2SurfaceT, surfaceSet->num);
146
147 for (i = 0; i < surfaceSet->num; i++)
148 {
149 surfaceSet->surface[i].imageSet = GetImageSet(path);
150 if (surfaceSet->surface[i].imageSet == NULL)
151 {
152 goto bailBadRead;
153 }
154
155 surfaceSet->surface[i].featureSet = ReadFeatureSet(path);
156 if (surfaceSet->surface[i].featureSet == NULL)
157 {
158 goto bailBadRead;
159 }
160 surfaceSet->surface[i].markerSet = NULL;
161
162 for (j = 0; j < 3; j++)
163 {
164 for (k = 0; k < 4; k++)
165 {
166 surfaceSet->surface[i].trans[j][k] = (j == k) ? 1.0f : 0.0f;
167 }
168 }
169 arUtilMatInvf((const float(*)[4])surfaceSet->surface[i].trans, surfaceSet->surface[i].itrans);
170 surfaceSet->surface[i].jpegName = 0;
171 }
172
173 if (fp)
174 fclose(fp);
175
176 if (i < surfaceSet->num)
177 goto bailBadRead;
178
179 *surfaceSetPtr = surfaceSet;
180 return true;
181
182bailBadRead:
183 if (surfaceSet && surfaceSet->surface)
184 free(surfaceSet->surface);
185
186 if (surfaceSet)
187 free(surfaceSet);
188
189 if (fp)
190 fclose(fp);
191 return false;
192}
193
194AR2ImageSetT* NFTDataLoader::GetImageSet(boost::filesystem::path path)
195{
196 AR2JpegImageT *jpgImage;
197 AR2ImageSetT *imageSet;
198 FILE *fp = NULL;
199 float dpi;
200 int i, k1;
201
202 path.replace_extension(".iset");
203 if ((fp = fopen(path.generic_string().c_str(), "rb")) == NULL)
204 {
205 goto bailBadRead;
206 }
207
208 arMalloc(imageSet, AR2ImageSetT, 1);
209 if (fread(&(imageSet->num), sizeof(imageSet->num), 1, fp) != 1 || imageSet->num <= 0)
210 {
211 free(imageSet);
212 goto bailBadRead;
213 }
214
215 arMalloc(imageSet->scale, AR2ImageT*, imageSet->num);
216 arMalloc(imageSet->scale[0], AR2ImageT, 1);
217
218 jpgImage = ar2ReadJpegImage2(fp);
219 if (jpgImage == NULL || jpgImage->nc != 1)
220 {
221 free(imageSet->scale[0]);
222 free(imageSet->scale);
223 free(imageSet);
224
225 if (jpgImage == NULL)
226 {
227 rewind(fp);
228 return LoadRawImageSet(fp);
229 }
230
231 free(jpgImage);
232 goto bailBadRead;
233 }
234
235 imageSet->scale[0]->xsize = jpgImage->xsize;
236 imageSet->scale[0]->ysize = jpgImage->ysize;
237 imageSet->scale[0]->dpi = jpgImage->dpi;
238 imageSet->scale[0]->imgBW = jpgImage->image;
239 free(jpgImage);
240
241 // Minify for the other scales.
242 // First, find the list of scales we wrote into the file.
243 fseek(fp, (long)(-(int)sizeof(dpi)*(imageSet->num - 1)), SEEK_END);
244 for (i = 1; i < imageSet->num; i++)
245 {
246 if (fread(&dpi, sizeof(dpi), 1, fp) != 1)
247 {
248 for (k1 = 0; k1 < i; k1++)
249 {
250 free(imageSet->scale[k1]->imgBW);
251 free(imageSet->scale[k1]);
252 }
253 free(imageSet->scale);
254 goto bailBadRead;
255 }
256
257 imageSet->scale[i] = GetImageLayer(imageSet->scale[0], dpi);
258 if (imageSet->scale[i] == NULL)
259 {
260 for (k1 = 0; k1 < i; k1++)
261 {
262 free(imageSet->scale[k1]->imgBW);
263 free(imageSet->scale[k1]);
264 }
265 free(imageSet->scale);
266 goto bailBadRead;
267 }
268 }
269
270 if (fp)
271 fclose(fp);
272
273 return imageSet;
274
275bailBadRead:
276 if (fp)
277 fclose(fp);
278 return NULL;
279}
280
281AR2ImageSetT* NFTDataLoader::LoadRawImageSet(FILE* fp)
282{
283 AR2ImageSetT* imageSet;
284 int i, k;
285
286 arMalloc(imageSet, AR2ImageSetT, 1);
287
288 if (fread(&(imageSet->num), sizeof(imageSet->num), 1, fp) != 1 || imageSet->num <= 0)
289 {
290 goto bail;
291 }
292
293 arMalloc(imageSet->scale, AR2ImageT*, imageSet->num);
294 for (i = 0; i < imageSet->num; i++)
295 {
296 arMalloc(imageSet->scale[i], AR2ImageT, 1);
297 }
298
299 for (i = 0; i < imageSet->num; i++)
300 {
301 if (fread(&(imageSet->scale[i]->xsize), sizeof(imageSet->scale[i]->xsize), 1, fp) != 1)
302 {
303 for (k = 0; k < i; k++)
304 {
305 free(imageSet->scale[k]->imgBW);
306 }
307 for (k = 0; k < imageSet->num; k++) free(imageSet->scale[k]);
308 goto bail1;
309 }
310 if (fread(&(imageSet->scale[i]->ysize), sizeof(imageSet->scale[i]->ysize), 1, fp) != 1)
311 {
312 for (k = 0; k < i; k++)
313 {
314 free(imageSet->scale[k]->imgBW);
315 }
316 for (k = 0; k < imageSet->num; k++) free(imageSet->scale[k]);
317 goto bail1;
318 }
319 if (fread(&(imageSet->scale[i]->dpi), sizeof(imageSet->scale[i]->dpi), 1, fp) != 1)
320 {
321 for (k = 0; k < i; k++)
322 {
323 free(imageSet->scale[k]->imgBW);
324 }
325 for (k = 0; k < imageSet->num; k++) free(imageSet->scale[k]);
326 goto bail1;
327 }
328
329 arMalloc(imageSet->scale[i]->imgBW, ARUint8, imageSet->scale[i]->xsize * imageSet->scale[i]->ysize);
330
331 if (fread(imageSet->scale[i]->imgBW, sizeof(ARUint8), imageSet->scale[i]->xsize * imageSet->scale[i]->ysize, fp)
332 != imageSet->scale[i]->xsize * imageSet->scale[i]->ysize)
333 {
334 for (k = 0; k <= i; k++)
335 {
336 free(imageSet->scale[k]->imgBW);
337 }
338 for (k = 0; k < imageSet->num; k++) free(imageSet->scale[k]);
339 goto bail1;
340 }
341 }
342
343 fclose(fp);
344 return imageSet;
345
346bail1:
347 free(imageSet->scale);
348bail:
349 free(imageSet);
350 fclose(fp);
351 return NULL;
352}
353
354AR2FeatureSetT* NFTDataLoader::ReadFeatureSet(boost::filesystem::path path)
355{
356 AR2FeatureSetT *featureSet = NULL;
357 FILE *fp = NULL;
358 int i, j, l3;
359
360 path.replace_extension(".fset");
361 if ((fp = fopen(path.generic_string().c_str(), "rb")) == NULL)
362 {
363 goto done;
364 }
365
366 arMalloc(featureSet, AR2FeatureSetT, 1);
367 if (fread(&(featureSet->num), sizeof(featureSet->num), 1, fp) != 1)
368 {
369 goto bail0;
370 }
371
372 arMalloc(featureSet->list, AR2FeaturePointsT, featureSet->num);
373 for (i = 0; i < featureSet->num; i++)
374 {
375 if (fread(&(featureSet->list[i].scale), sizeof(featureSet->list[i].scale), 1, fp) != 1)
376 {
377 goto bail1;
378 }
379 if (fread(&(featureSet->list[i].maxdpi), sizeof(featureSet->list[i].maxdpi), 1, fp) != 1)
380 {
381 goto bail1;
382 }
383 if (fread(&(featureSet->list[i].mindpi), sizeof(featureSet->list[i].mindpi), 1, fp) != 1)
384 {
385 goto bail1;
386 }
387 if (fread(&(featureSet->list[i].num), sizeof(featureSet->list[i].num), 1, fp) != 1)
388 {
389 goto bail1;
390 }
391
392 arMalloc(featureSet->list[i].coord, AR2FeatureCoordT, featureSet->list[i].num);
393 for (j = 0; j < featureSet->list[i].num; j++)
394 {
395 if (fread(&(featureSet->list[i].coord[j].x), sizeof(featureSet->list[i].coord[j].x), 1, fp) != 1)
396 {
397 goto bail1;
398 }
399 if (fread(&(featureSet->list[i].coord[j].y), sizeof(featureSet->list[i].coord[j].y), 1, fp) != 1)
400 {
401 goto bail1;
402 }
403 if (fread(&(featureSet->list[i].coord[j].mx), sizeof(featureSet->list[i].coord[j].mx), 1, fp) != 1)
404 {
405 goto bail1;
406 }
407 if (fread(&(featureSet->list[i].coord[j].my), sizeof(featureSet->list[i].coord[j].my), 1, fp) != 1)
408 {
409 goto bail1;
410 }
411 if (fread(&(featureSet->list[i].coord[j].maxSim), sizeof(featureSet->list[i].coord[j].maxSim), 1, fp) != 1)
412 {
413 goto bail1;
414 }
415 }
416 }
417
418 goto done;
419
420bail1:
421 for (l3 = 0; l3 < i; l3++) {
422 free(featureSet->list[l3].coord);
423 }
424 free(featureSet->list);
425bail0:
426 free(featureSet);
427 featureSet = NULL;
428
429done:
430 fclose(fp);
431 return featureSet;
432}
433
434AR2ImageT* NFTDataLoader::GetImageLayer(AR2ImageT* src, float dpi)
435{
436 AR2ImageT *dst;
437 ARUint8 *p1, *p2;
438 int wx, wy;
439 int sx, sy, ex, ey;
440 int ii, jj, iii, jjj;
441 int co, value;
442
443 wx = (int)lroundf(src->xsize * dpi / src->dpi);
444 wy = (int)lroundf(src->ysize * dpi / src->dpi);
445
446 arMalloc(dst, AR2ImageT, 1);
447 dst->xsize = wx;
448 dst->ysize = wy;
449 dst->dpi = dpi;
450 arMalloc(dst->imgBW, ARUint8, wx*wy);
451 p2 = dst->imgBW;
452
453 for (jj = 0; jj < wy; jj++)
454 {
455 sy = (int)lroundf(jj * src->dpi / dpi);
456 ey = (int)lroundf((jj + 1) * src->dpi / dpi) - 1;
457 if (ey >= src->ysize) ey = src->ysize - 1;
458 for (ii = 0; ii < wx; ii++)
459 {
460 sx = (int)lroundf(ii * src->dpi / dpi);
461 ex = (int)lroundf((ii + 1) * src->dpi / dpi) - 1;
462 if (ex >= src->xsize) ex = src->xsize - 1;
463
464 co = value = 0;
465 for (jjj = sy; jjj <= ey; jjj++)
466 {
467 p1 = &(src->imgBW[jjj*src->xsize + sx]);
468 for (iii = sx; iii <= ex; iii++)
469 {
470 value += *(p1++);
471 co++;
472 }
473 }
474 *(p2++) = (co == 0) ? 0 : value / co;
475 }
476 }
477
478 return dst;
479}
480
484ArTkMarker::ArTkMarker(std::string filePath, unsigned int nid, float size, unsigned int maxFeatures) : ArMarker(nid, size, ArMarker::AR_ARTK_FFT_MARKER)
485{
486 m_refDataSet = 0;
487 m_surfaceSet = 0;
488 m_featureSet = 0;
489 m_isTrained = false;
490
491 m_file = filePath;
492 m_maxFeatures = maxFeatures;
493
494 if (!m_file.empty())
495 {
496 boost::filesystem::path bpath = filePath;
497 if (bpath.extension() == ".fset" || bpath.extension() == ".fset3")
498 {
499 bpath.replace_extension("");
500 NFTDataLoader nftLoader;
501 //kpmLoadRefDataSet(bpath.generic_string().c_str(), "fset3", &m_refDataSet);
502 //m_surfaceSet = ar2ReadSurfaceSet(bpath.generic_string().c_str(), "fset", NULL);
503
504 if (nftLoader.LoadData(bpath, &m_refDataSet, &m_surfaceSet) && m_refDataSet && m_surfaceSet)
505 {
506 m_imageSize.width = m_refDataSet->pageInfo[0].imageInfo[0].width;
507 m_imageSize.height = m_refDataSet->pageInfo[0].imageInfo[0].height;
508 m_pcorners.clear();
509 m_pcorners.push_back(cv::Point2f(0.0f, 0.0f));
510 m_pcorners.push_back(cv::Point2f(static_cast<float>(m_imageSize.width), 0.0f));
511 m_pcorners.push_back(cv::Point2f(static_cast<float>(m_imageSize.width), static_cast<float>(m_imageSize.height)));
512 m_pcorners.push_back(cv::Point2f(0.0f, static_cast<float>(m_imageSize.height)));
513
514 m_isTrained = true;
515 }
516 }
517 else
518 {
519#ifdef ANDROID
520 long lSize = 0;
521 char* buff = 0;
522
523 FILE* pFile = fopen(m_file.c_str(), "rb");
524 if (pFile)
525 {
526 // obtain file size.
527 fseek(pFile, 0, SEEK_END);
528 lSize = ftell(pFile);
529 rewind(pFile);
530
531 // allocate memory to contain the whole file.
532 buff = (char*)malloc(lSize);
533 if (buff)
534 {
535 // copy the file into the buffer.
536 fread(buff, 1, lSize, pFile);
537 std::vector<char> data(buff, buff + lSize);
538
539 // terminate
540 fclose(pFile);
541
542 m_image = cv::imdecode(data, cv::IMREAD_GRAYSCALE);
543 free(buff);
544 }
545 if (m_image.empty())
546 MMechostr(MSKDEBUG, ">>>>> Picture not loaded ko\n");
547 else
548 MMechostr(MSKDEBUG, ">>>>> Picture loaded ok\n");
549 }
550 else
551 {
552 MMechostr(MSKDEBUG, ">>>>> Picture failed to open : %s\n", filePath.c_str());
553 }
554#else
555 m_image = cv::imread(m_file, cv::IMREAD_GRAYSCALE);
556#endif
557 }
558 }
559
560 CommonConstructor();
561 }
562
566ArTkMarker::ArTkMarker(cv::Mat tpl, unsigned int nid, float size, unsigned int maxFeatures) : ArMarker(nid, size, ArMarker::AR_ARTK_FFT_MARKER)
567{
568 m_refDataSet = 0;
569 m_surfaceSet = 0;
570 m_featureSet = 0;
571 m_isTrained = false;
572
573 m_file = "";
574 m_maxFeatures = maxFeatures;
575
576 cv::cvtColor(tpl, m_image, cv::COLOR_RGB2GRAY);
577
578 CommonConstructor();
579}
580
582{
583 if (!tpl.empty())
584 {
585 SetTrainned(false);
586 SetTracked(false);
587
588 m_cancelTrainning = true;
589 if (m_trainingThread.joinable())
590 m_trainingThread.join();
591
592 tpl.copyTo(m_image);
593 m_cancelTrainning = false;
594
595 //rotate marker 90°
596 /*if (m_image.cols > m_image.rows)
597 {
598 cv::Mat rot;
599 cv::transpose(m_image, rot);
600 cv::flip(rot, m_image, 1);
601 }*/
602
603 int msize = MIN_TRACKED_MARKER_SIZE;
604 if (std::max(m_image.rows, m_image.cols) < msize)
605 {
606 cv::Size nsize;
607 if (m_image.rows >= m_image.cols)
608 {
609 nsize.width = (int)(((float)m_image.cols * (float)msize) / (float)m_image.rows);
610 nsize.height = msize;
611 }
612 else
613 {
614 nsize.width = msize;
615 nsize.height = (int)(((float)m_image.rows * (float)msize) / (float)m_image.cols);
616 }
617
618 cv::resize(m_image, m_image, nsize, 0, 0, cv::INTER_CUBIC);
619 }
620
621 m_imageSize.width = m_image.cols;
622 m_imageSize.height = m_image.rows;
623
624 m_pcorners.clear();
625 m_pcorners.push_back(cv::Point2f(0.0f, 0.0f));
626 m_pcorners.push_back(cv::Point2f(static_cast<float>(m_imageSize.width), 0.0f));
627 m_pcorners.push_back(cv::Point2f(static_cast<float>(m_imageSize.width), static_cast<float>(m_imageSize.height)));
628 m_pcorners.push_back(cv::Point2f(0.0f, static_cast<float>(m_imageSize.height)));
629 m_trainingThread = boost::thread(&ArTkMarker::initTrackingPicture, this);
630 }
631}
632
636void ArTkMarker::CommonConstructor()
637{
638 mNumGoodTracking = 0;
639 m_pageNum = 0;
640#ifdef _WIN32
641 m_ftmi = arFilterTransMatInit(30.0, 28.0);//arFilterTransMatInit(AR_FILTER_TRANS_MAT_SAMPLE_RATE_DEFAULT, AR_FILTER_TRANS_MAT_CUTOFF_FREQ_DEFAULT);
642#else
643 m_ftmi = arFilterTransMatInit(30.0, 20.0);//arFilterTransMatInit(AR_FILTER_TRANS_MAT_SAMPLE_RATE_DEFAULT, AR_FILTER_TRANS_MAT_CUTOFF_FREQ_DEFAULT);
644#endif
645 m_registerNextFrame = false;
646 m_isTracked = false;
647 m_cancelTrainning = false;
648
649 //m_CornerSmoothers.Init(0.2f, 0.2f, 0.2f, 0.20f, 0.15f);
650
651 if (!m_isTrained)
652 {
653 m_refDataSet = 0;
654 m_surfaceSet = 0;
655 m_featureSet = 0;
656
657 m_pcorners.clear();
658 m_pcorners.push_back(cv::Point2f(0.0f, 0.0f));
659 m_pcorners.push_back(cv::Point2f(0.0f, 0.0f));
660 m_pcorners.push_back(cv::Point2f(0.0f, 0.0f));
661 m_pcorners.push_back(cv::Point2f(0.0f, 0.0f));
662
664 }
665 else
666 {
668 }
669}
670
675{
676 m_cancelTrainning = true;
677 if (m_trainingThread.joinable())
678 m_trainingThread.join();
679
680 std::vector<int> empty(2);
681 empty[0] = 0; empty[1] = 0;
682 m_image = cv::Mat(empty);
683 m_pcorners.clear();
684
685 if (m_refDataSet)
686 kpmDeleteRefDataSet(&m_refDataSet);
687
688 if (m_surfaceSet)
689 ar2FreeSurfaceSet(&m_surfaceSet);
690
691 if (m_ftmi)
692 arFilterTransMatFinal(m_ftmi);
693
695}
696
697bool ArTkMarker::SaveData(std::string path)
698{
699 if (!m_isTrained)
700 return false;
701
702 boost::system::error_code ec;
703 boost::filesystem::path bpath = path;
704 bpath.replace_extension(".fset");
705 if (boost::filesystem::exists(bpath))
706 boost::filesystem::remove(bpath, ec);
707
708 bpath.replace_extension(".fset3");
709 if (boost::filesystem::exists(bpath))
710 boost::filesystem::remove(bpath, ec);
711
712 bpath.replace_extension(".iset");
713 if (boost::filesystem::exists(bpath))
714 boost::filesystem::remove(bpath, ec);
715
716 bpath.replace_extension("");
717
718 if (m_surfaceSet && m_surfaceSet->surface[0].imageSet)
719 ar2WriteImageSet((char*)bpath.generic_string().c_str(), m_surfaceSet->surface[0].imageSet);
720 else
721 return false;
722
723 if (m_featureSet)
724 ar2SaveFeatureSet((char*)bpath.generic_string().c_str(), "fset", m_featureSet);
725 else
726 return false;
727
728 if (m_refDataSet)
729 kpmSaveRefDataSet(bpath.generic_string().c_str(), "fset3", m_refDataSet);
730 else
731 return false;
732
733 return true;
734}
735
736bool ArTkMarker::LoadData(std::string filename)
737{
738 return false;
739}
740
742{
743 if (!IsTrained())
744 return NULL;
745
746 boost::unique_lock<boost::recursive_mutex> l(m_trainningMutex);
747 //clone dataset to avoid destruction from detector
748 KpmRefDataSet* refDataSet = NULL;
749 arMalloc(refDataSet, KpmRefDataSet, 1);
750
751 refDataSet->pageNum = 1;
752 refDataSet->num = m_refDataSet->num;
753 arMalloc(refDataSet->pageInfo, KpmPageInfo, 1);
754 arMalloc(refDataSet->refPoint, KpmRefData, refDataSet->num);
755
756 refDataSet->pageInfo[0].pageNo = m_refDataSet->pageInfo[0].pageNo;
757 refDataSet->pageInfo[0].imageNum = m_refDataSet->pageInfo[0].imageNum;
758 arMalloc(refDataSet->pageInfo[0].imageInfo, KpmImageInfo, m_refDataSet->pageInfo[0].imageNum);
759
760 for (int i = 0; i < refDataSet->pageInfo[0].imageNum; i++)
761 {
762 refDataSet->pageInfo[0].imageInfo[i].imageNo = m_refDataSet->pageInfo[0].imageInfo[i].imageNo;
763 refDataSet->pageInfo[0].imageInfo[i].height = m_refDataSet->pageInfo[0].imageInfo[i].height;
764 refDataSet->pageInfo[0].imageInfo[i].width = m_refDataSet->pageInfo[0].imageInfo[i].width;
765 }
766
767 for (int i = 0; i < refDataSet->num; i++)
768 {
769 refDataSet->refPoint[i].coord2D.x = m_refDataSet->refPoint[i].coord2D.x;
770 refDataSet->refPoint[i].coord2D.y = m_refDataSet->refPoint[i].coord2D.y;
771 refDataSet->refPoint[i].coord3D.x = m_refDataSet->refPoint[i].coord3D.x;
772 refDataSet->refPoint[i].coord3D.y = m_refDataSet->refPoint[i].coord3D.y;
773 refDataSet->refPoint[i].featureVec = m_refDataSet->refPoint[i].featureVec;
774 refDataSet->refPoint[i].pageNo = m_refDataSet->refPoint[i].pageNo;
775 refDataSet->refPoint[i].refImageNo = m_refDataSet->refPoint[i].refImageNo;
776 }
777
778 //kpmMergeRefDataSet(&refDataSet, &m_refDataSet);
779
780 //it's called on detector reset
781 SetVisible(false);
782 SetTracked(false);
783 return refDataSet;
784}
785
787{
788 boost::unique_lock<boost::recursive_mutex> l(m_dataMutex);
789 return m_pageNum;
790}
791
793{
794 boost::unique_lock<boost::recursive_mutex> l(m_dataMutex);
795 m_pageNum = page;
796}
797
798void ArTkMarker::SetTracked(bool state)
799{
800 boost::unique_lock<boost::recursive_mutex> l(m_dataMutex);
801 m_isTracked = state;
802}
803
804void ArTkMarker::SetTrainned(bool state)
805{
806 boost::unique_lock<boost::recursive_mutex> l(m_dataMutex);
807 m_isTrained = state;
808}
809
811{
812 boost::unique_lock<boost::recursive_mutex> l(m_dataMutex);
813 return m_isTracked;
814}
815
817{
818 boost::unique_lock<boost::recursive_mutex> l(m_dataMutex);
819 return m_isTrained;
820}
821
822bool ArTkMarker::initTrackingPicture()
823{
824 boost::unique_lock<boost::recursive_mutex> l(m_trainningMutex);
825
826 if (m_refDataSet)
827 {
828 kpmDeleteRefDataSet(&m_refDataSet);
829 m_refDataSet = 0;
830 }
831
832 if (m_surfaceSet)
833 {
834 ar2FreeSurfaceSet(&m_surfaceSet);
835 m_surfaceSet = 0;
836 m_featureSet = 0;
837 }
838
839 // Determine minimum allowable DPI, truncated to 3 decimal places.
840 //max dpi is set to make the marker to 1m size
841 float dpiMax = std::max(m_imageSize.width, m_imageSize.height) / 3.93701f;
842 float dpiMin = truncf((28.0f / (float)(std::min(m_imageSize.width, m_imageSize.height))) * dpiMax * 1000.0f) / 1000.0f;
843 float dpiWork = 0.0f;
844 int dpi_num = 0;
845 int i, j, k;
846
847 if (dpiMin == dpiMax)
848 {
849 dpi_num = 1;
850 }
851 else
852 {
853 dpiWork = dpiMax;
854 for (i = 1;; i++)
855 {
856 dpiWork *= 0.75f;
857 if (dpiWork <= dpiMin*0.95f)
858 {
859 break;
860 }
861 }
862 dpi_num = i + 1;
863 }
864
865 //limit levels
866 if (std::max(m_imageSize.width, m_imageSize.height) <= MIN_TRACKED_MARKER_SIZE)
867 dpi_num = std::min(dpi_num, 6); // for live trainning
868 else if (std::max(m_imageSize.width, m_imageSize.height) >= 800)
869 dpi_num = std::min(dpi_num, 16); // for big pictures
870 else if (std::max(m_imageSize.width, m_imageSize.height) >= 1024)
871 dpi_num = std::min(dpi_num, 8); // for very big pictures
872
873 float* dpi_list = 0;
874 arMalloc(dpi_list, float, dpi_num);
875
876 dpiWork = dpiMax;
877 for (i = 0; i < dpi_num; i++)
878 {
879 dpi_list[i] = dpiWork; // Lowest value goes at tail of array, highest at head.
880 dpiWork *= 0.75f;
881
882 if (dpiWork <= dpiMin*0.95f)
883 dpiWork = dpiMin;
884 }
885
886 //check cancel
887 if (m_cancelTrainning)
888 return false;
889
890 AR2ImageSetT *imageSet = ar2GenImageSet(m_image.data, m_image.cols, m_image.rows, 1, dpiMax, dpi_list, dpi_num);
891
892 // don't need anymore
893 free(dpi_list);
894
895 AR2FeatureMapT *featureMap = NULL;
896
897 arMalloc(m_featureSet, AR2FeatureSetT, 1); // A featureSet with a single image,
898 arMalloc(m_featureSet->list, AR2FeaturePointsT, imageSet->num); // and with 'num' scale levels of this image.
899
900 m_featureSet->num = imageSet->num;
901
902 int numFeatures;
903 float scale1 = 0.0f;
904 float scale2 = 2.5f;
905
906 // Generating FeatureList
907 for (i = 0; i < imageSet->num; i++)
908 {
909 //check cancel
910 if (m_cancelTrainning)
911 return false;
912
913 featureMap = ar2GenFeatureMap(imageSet->scale[i],
914 AR2_DEFAULT_TS1*AR2_TEMP_SCALE, AR2_DEFAULT_TS2*AR2_TEMP_SCALE,
915 AR2_DEFAULT_GEN_FEATURE_MAP_SEARCH_SIZE1, AR2_DEFAULT_GEN_FEATURE_MAP_SEARCH_SIZE2,
916 AR2_DEFAULT_MAX_SIM_THRESH2, AR2_DEFAULT_SD_THRESH2);
917
918 if (featureMap == NULL)
919 {
920 ar2FreeImageSet(&imageSet);
921 ar2FreeFeatureSet(&m_featureSet);
922 m_featureSet = 0;
923
924 //callback for scol object
925 OBJpostEvent(AR_MARKER_TRAINNED_CB, SCOL_PTR this, 0);
926 return false;
927 }
928
929 //check cancel
930 if (m_cancelTrainning)
931 return false;
932
933 m_featureSet->list[i].coord = ar2SelectFeature2(imageSet->scale[i], featureMap,
934 AR2_DEFAULT_TS1*AR2_TEMP_SCALE, AR2_DEFAULT_TS2*AR2_TEMP_SCALE, AR2_DEFAULT_GEN_FEATURE_MAP_SEARCH_SIZE2,
935 AR2_DEFAULT_OCCUPANCY_SIZE * 2 / 3,
936 AR2_DEFAULT_MAX_SIM_THRESH_L3, AR2_DEFAULT_MIN_SIM_THRESH_L3, AR2_DEFAULT_SD_THRESH_L3, &numFeatures);
937
938 if (m_featureSet->list[i].coord == NULL)
939 numFeatures = 0;
940
941 m_featureSet->list[i].num = numFeatures;
942 m_featureSet->list[i].scale = i;
943
944 scale1 = 0.0f;
945 for (j = 0; j < imageSet->num; j++)
946 {
947 if (imageSet->scale[j]->dpi < imageSet->scale[i]->dpi)
948 {
949 if (imageSet->scale[j]->dpi > scale1)
950 scale1 = imageSet->scale[j]->dpi;
951 }
952 }
953
954 if (scale1 == 0.0f)
955 {
956 m_featureSet->list[i].mindpi = imageSet->scale[i]->dpi * 0.5f;
957 }
958 else
959 {
960 m_featureSet->list[i].mindpi = scale1;
961 }
962
963 scale1 = 0.0f;
964 for (j = 0; j < imageSet->num; j++)
965 {
966 if (imageSet->scale[j]->dpi > imageSet->scale[i]->dpi)
967 {
968 if (scale1 == 0.0f || imageSet->scale[j]->dpi < scale1)
969 scale1 = imageSet->scale[j]->dpi;
970 }
971 }
972
973 if (scale1 == 0.0f)
974 {
975 m_featureSet->list[i].maxdpi = imageSet->scale[i]->dpi * 2.0f;
976 }
977 else
978 {
979 scale2 = imageSet->scale[i]->dpi;
980 m_featureSet->list[i].maxdpi = scale2*0.8f + scale1*0.2f;
981 }
982
983 ar2FreeFeatureMap(featureMap);
984 }
985
986 //check cancel
987 if (m_cancelTrainning)
988 return false;
989
990 //surface set
991 arMalloc(m_surfaceSet, AR2SurfaceSetT, 1);
992 m_surfaceSet->num = 1;
993 m_surfaceSet->contNum = 0;
994 arMalloc(m_surfaceSet->surface, AR2SurfaceT, m_surfaceSet->num);
995 m_surfaceSet->surface[0].imageSet = imageSet;
996 m_surfaceSet->surface[0].featureSet = m_featureSet;
997 m_surfaceSet->surface[0].markerSet = NULL;
998 m_surfaceSet->surface[0].jpegName = NULL;
999
1000 for (j = 0; j < 3; j++)
1001 {
1002 for (k = 0; k < 4; k++)
1003 {
1004 m_surfaceSet->surface[0].trans[j][k] = (j == k) ? 1.0f : 0.0f;
1005 }
1006 }
1007
1008 arUtilMatInvf((const float(*)[4])m_surfaceSet->surface[0].trans, m_surfaceSet->surface[0].itrans);
1009
1010 int procMode = KpmProcFullSize;
1011 int maxFeatureNum;
1012 int featureDensity = m_maxFeatures;
1013
1014 for (i = 0; i < imageSet->num; i++)
1015 {
1016 //check cancel
1017 if (m_cancelTrainning)
1018 return false;
1019
1020 maxFeatureNum = featureDensity * imageSet->scale[i]->xsize * imageSet->scale[i]->ysize / (480 * 360);
1021
1022 if (!maxFeatureNum || kpmAddRefDataSet(imageSet->scale[i]->imgBW, imageSet->scale[i]->xsize, imageSet->scale[i]->ysize,
1023 imageSet->scale[i]->dpi,
1024 procMode, KpmCompNull, maxFeatureNum, 1, i, &m_refDataSet) < 0)
1025 {
1026 // Page number set to 1 by default.
1027 kpmDeleteRefDataSet(&m_refDataSet);
1028 m_refDataSet = 0;
1029 ar2FreeSurfaceSet(&m_surfaceSet);
1030 m_surfaceSet = 0;
1031 m_featureSet = 0;
1032 //callback for scol object
1033 OBJpostEvent(AR_MARKER_TRAINNED_CB, SCOL_PTR this, 0);
1034 return false;
1035 }
1036 }
1037
1038 //ar2FreeImageSet(&imageSet);
1039
1040 //ar2SaveFeatureSet
1041 //kpmSaveRefDataSet
1042
1044 SetTrainned(true);
1045
1046 //callback for scol object
1047 OBJpostEvent(AR_MARKER_TRAINNED_CB, SCOL_PTR this, 1);
1048 return true;
1049}
1050
1051void ArTkMarker::RegisterNextFrame(cv::Point point, cv::Size size)
1052{
1053 m_cropPos = point;
1054 m_cropSize = size;
1055 m_registerNextFrame = true;
1056}
1057
1059{
1060 boost::unique_lock<boost::recursive_mutex> l(m_mutex);
1061 m_warped.copyTo(image);
1062
1063 if (image.empty())
1064 return false;
1065 else
1066 return true;
1067}
1068
1069void ArTkMarker::WarpMarkerImage(cv::Mat color)
1070{
1071 cv::Mat HMatrix = cv::findHomography(m_pcorners, *this);
1072 // get warped detected marker
1073 boost::unique_lock<boost::recursive_mutex> l(m_mutex);
1074 cv::warpPerspective(color, m_warped, HMatrix, cv::Size(m_imageSize.width, m_imageSize.height), cv::WARP_INVERSE_MAP | cv::INTER_CUBIC);
1075}
1076
1077void ArTkMarker::ComputeMatrix(ArCameraParam &camParams, bool reverse)
1078{
1079 float halfSizeX = 0.0f;
1080 float halfSizeY = 0.0f;
1081 if (m_imageSize.height >= m_imageSize.width)
1082 {
1083 halfSizeY = m_size / 2.0f;
1084 halfSizeX = ((m_imageSize.width * m_size) / m_imageSize.height) / 2.0f;
1085 }
1086 else
1087 {
1088 halfSizeY = ((m_imageSize.height * m_size) / m_imageSize.width) / 2.0f;
1089 halfSizeX = m_size / 2.0f;
1090 }
1091
1092 /*
1093 m_CornerSmoothers.Update(filterVals);
1094 filterVals = m_CornerSmoothers.GetFilteredPoints();
1095
1096 int p = 0;
1097 for (j = 0; j < 3; j++)
1098 for (i = 0; i < 4; i++)
1099 {
1100 mTackingPos[j][i] = filterVals[p];
1101 p++;
1102 }
1103 */
1104
1105 //filter
1106 arFilterTransMat(m_ftmi, mTackingPos, false);
1107
1108 double modelview_matrix[16];
1109
1110 //mul matrix for 90° rotation
1111 cv::Mat R(4, 4, CV_32F);
1112 R.at<float>(0, 0) = mTackingPos[0][0]; // R1C1
1113 R.at<float>(0, 1) = mTackingPos[0][1]; // R1C2
1114 R.at<float>(0, 2) = mTackingPos[0][2];
1115 R.at<float>(0, 3) = mTackingPos[0][3];
1116 R.at<float>(1, 0) = mTackingPos[1][0]; // R2
1117 R.at<float>(1, 1) = mTackingPos[1][1];
1118 R.at<float>(1, 2) = mTackingPos[1][2];
1119 R.at<float>(1, 3) = mTackingPos[1][3];
1120 R.at<float>(2, 0) = mTackingPos[2][0];
1121 R.at<float>(2, 1) = mTackingPos[2][1];
1122 R.at<float>(2, 2) = mTackingPos[2][2];
1123 R.at<float>(2, 3) = mTackingPos[2][3];
1124
1125 // create a rotation matrix for x axis
1126 cv::Mat RX = cv::Mat::eye(4, 4, CV_32F);
1127 float angleRad = M_PI / 2;
1128 RX.at<float>(1, 1) = cos(angleRad);
1129 RX.at<float>(1, 2) = -sin(angleRad);
1130 RX.at<float>(2, 1) = sin(angleRad);
1131 RX.at<float>(2, 2) = cos(angleRad);
1132
1133 // now multiply
1134 R = R * RX;
1135
1136 modelview_matrix[0 + 0 * 4] = R.at<float>(0, 0); // R1C1
1137 modelview_matrix[0 + 1 * 4] = R.at<float>(0, 1); // R1C2
1138 modelview_matrix[0 + 2 * 4] = R.at<float>(0, 2);
1139 modelview_matrix[0 + 3 * 4] = R.at<float>(0, 3);
1140 modelview_matrix[1 + 0 * 4] = R.at<float>(1, 0); // R2
1141 modelview_matrix[1 + 1 * 4] = R.at<float>(1, 1);
1142 modelview_matrix[1 + 2 * 4] = R.at<float>(1, 2);
1143 modelview_matrix[1 + 3 * 4] = R.at<float>(1, 3);
1144 modelview_matrix[2 + 0 * 4] = -R.at<float>(2, 0); // R3
1145 modelview_matrix[2 + 1 * 4] = -R.at<float>(2, 1);
1146 modelview_matrix[2 + 2 * 4] = -R.at<float>(2, 2);
1147 modelview_matrix[2 + 3 * 4] = -R.at<float>(2, 3);
1148 modelview_matrix[3 + 0 * 4] = 0.0;
1149 modelview_matrix[3 + 1 * 4] = 0.0;
1150 modelview_matrix[3 + 2 * 4] = 0.0;
1151 modelview_matrix[3 + 3 * 4] = 1.0;
1152
1153 if (m_size != 0.0)
1154 {
1155 // convert from marker in 120DPI to millimeter
1156 double f = m_size * 0.01;
1157 modelview_matrix[12] *= f;
1158 modelview_matrix[13] *= f;
1159 modelview_matrix[14] *= f;
1160
1161 // place the position on the center of the object
1162 cv::Point3d p(halfSizeX, 0.0, -halfSizeY);
1163 cv::Matx33d Rt = cv::Matx33d::eye();
1164
1165 Rt(0, 0) = modelview_matrix[0 + 0 * 4];
1166 Rt(0, 1) = modelview_matrix[0 + 1 * 4];
1167 Rt(0, 2) = modelview_matrix[0 + 2 * 4];
1168 Rt(1, 0) = modelview_matrix[1 + 0 * 4];
1169 Rt(1, 1) = modelview_matrix[1 + 1 * 4];
1170 Rt(1, 2) = modelview_matrix[1 + 2 * 4];
1171 Rt(2, 0) = modelview_matrix[2 + 0 * 4];
1172 Rt(2, 1) = modelview_matrix[2 + 1 * 4];
1173 Rt(2, 2) = modelview_matrix[2 + 2 * 4];
1174
1175 cv::Point3d roff = Rt * p;
1176 modelview_matrix[12] += roff.x;
1177 modelview_matrix[13] += roff.y;
1178 modelview_matrix[14] += roff.z;
1179
1180 cv::Mat rot(3, 3, CV_32FC1);
1181 rot.at<float>(0, 0) = mTackingPos[0][0];
1182 rot.at<float>(0, 1) = mTackingPos[0][1];
1183 rot.at<float>(0, 2) = mTackingPos[0][2];
1184 rot.at<float>(1, 0) = mTackingPos[1][0];
1185 rot.at<float>(1, 1) = mTackingPos[1][1];
1186 rot.at<float>(1, 2) = mTackingPos[1][2];
1187 rot.at<float>(2, 0) = mTackingPos[2][0];
1188 rot.at<float>(2, 1) = mTackingPos[2][1];
1189 rot.at<float>(2, 2) = mTackingPos[2][2];
1190
1191 cv::Rodrigues(rot, Rvec);
1192
1193 Tvec.at<float>(0, 0) = modelview_matrix[12];
1194 Tvec.at<float>(1, 0) = modelview_matrix[13];
1195 Tvec.at<float>(2, 0) = -modelview_matrix[14];
1196 }
1197
1198 std::vector<cv::Point3d> corner3d;
1199 corner3d.push_back(cv::Point3d(-halfSizeX, halfSizeY, 0.0));
1200 corner3d.push_back(cv::Point3d(halfSizeX, halfSizeY, 0.0));
1201 corner3d.push_back(cv::Point3d(halfSizeX, -halfSizeY, 0.0));
1202 corner3d.push_back(cv::Point3d(-halfSizeX, -halfSizeY, 0.0));
1203
1204 std::vector<cv::Point2d> projectedPoints;
1205 cv::projectPoints(corner3d, Rvec, Tvec, camParams.camParam.CameraMatrix, camParams.camParam.Distorsion, projectedPoints);
1206
1207 for (int j = 0; j < projectedPoints.size(); j++)
1208 {
1209 (*this).at(j).x = (float)projectedPoints[j].x;
1210 (*this).at(j).y = (float)projectedPoints[j].y;
1211 }
1212
1213 //determine the centroid
1214 Vector3 pixelPosition(0.0, 0.0, 0.0);
1215 for (int j = 0; j < 4; j++)
1216 {
1217 pixelPosition.x += (*this).at(j).x;
1218 pixelPosition.y += (*this).at(j).y;
1219 }
1220
1221 pixelPosition.z = sqrt(pow(((*this).at(1).x - (*this).at(0).x), 2) + pow(((*this).at(1).y - (*this).at(0).y), 2));
1222 pixelPosition.z += sqrt(pow(((*this).at(2).x - (*this).at(1).x), 2) + pow(((*this).at(2).y - (*this).at(1).y), 2));
1223 pixelPosition.z += sqrt(pow(((*this).at(3).x - (*this).at(2).x), 2) + pow(((*this).at(3).y - (*this).at(2).y), 2));
1224 pixelPosition.z += sqrt(pow(((*this).at(0).x - (*this).at(3).x), 2) + pow(((*this).at(0).y - (*this).at(3).y), 2));
1225
1226 pixelPosition.x /= 4.;
1227 pixelPosition.y /= 4.;
1228 pixelPosition.z /= 4.;
1229
1230 SetPixelPosition(pixelPosition);
1231
1232 Vector3 offset = camParams.GetCameraOffset();
1233
1234 SetPosition(Vector3(static_cast<float>(reverse ? -modelview_matrix[12] : modelview_matrix[12]) + offset.x, static_cast<float>(modelview_matrix[13]) + offset.y, static_cast<float>(modelview_matrix[14]) + offset.z));
1235 SetOrientation(BtQuaternion::FromRotationMatrix(modelview_matrix, reverse));
1236}
1237
1238void ArTkMarker::StartTracking(cv::Mat color, const float camPose[3][4], ArCameraParam &camParams, const bool &reverse)
1239{
1240 std::vector<double> filterVals;
1241 int i, j;
1242 for (j = 0; j < 3; j++)
1243 for (i = 0; i < 4; i++)
1244 {
1245 mCamPose[j][i] = camPose[j][i];
1246 mTackingPos[j][i] = camPose[j][i];
1247 //filterVals.push_back(camPose[j][i]);
1248 }
1249
1250 mNumGoodTracking = 0;
1251 ar2SetInitTrans(m_surfaceSet, mCamPose);
1252 //m_CornerSmoothers.Reset();
1253 //m_CornerSmoothers.Update(filterVals);
1254 arFilterTransMat(m_ftmi, mTackingPos, true);
1255 ComputeMatrix(camParams, reverse);
1256 WarpMarkerImage(color);
1257
1258 if (IsTrained() && m_trainingThread.joinable())
1259 m_trainingThread.join();
1260 SetTracked(true);
1261}
1262
1263bool ArTkMarker::RegisterCurrentFrame(const cv::Mat &frame, cv::Size camsize, float tscale)
1264{
1265 if (m_registerNextFrame && camsize.width != 0 && camsize.height != 0 && m_cropSize.width > 1 && m_cropSize.height > 1)
1266 {
1267 m_registerNextFrame = false;
1268 //crop the picture with the coords
1269 cv::Point2f scale = cv::Point2f((float)frame.cols / (float)camsize.width, (float)frame.rows / (float)camsize.height);
1270
1271 m_cropPos.x = (int)((float)m_cropPos.x * tscale * scale.x);
1272 m_cropPos.y = (int)((float)m_cropPos.y * tscale * scale.y);
1273 m_cropSize.width = (int)((float)m_cropSize.width * tscale * scale.x);
1274 m_cropSize.height = (int)((float)m_cropSize.height * tscale * scale.x);
1275
1276 try
1277 {
1278 cv::Mat crop(frame, cv::Rect(m_cropPos.x, m_cropPos.y, m_cropSize.width, m_cropSize.height)); // NOTE: this will only give you a reference to the ROI of the original data
1279
1280 int msize = MIN_TRACKED_MARKER_SIZE;
1281 cv::Size nsize;
1282 if (crop.rows >= crop.cols)
1283 {
1284 nsize.width = (int)(((float)crop.cols * (float)msize) / (float)crop.rows);
1285 nsize.height = msize;
1286 }
1287 else
1288 {
1289 nsize.width = msize;
1290 nsize.height = (int)(((float)crop.rows * (float)msize) / (float)crop.cols);
1291 }
1292
1293 cv::resize(crop, crop, nsize, 0, 0, cv::INTER_CUBIC);
1294
1295 SetTrackedImage(crop);
1296 }
1297 catch (std::exception &)
1298 {
1299 //could not set current frame
1300 MMechostr(MSKDEBUG, "detectNFT : failed to set the current frame as marker.\n");
1301 return false;
1302 }
1303 SetVisible(false);
1304 return true;
1305 }
1306 return false;
1307}
1308
1309bool ArTkMarker::TrackFrame(AR2HandleT* ar2handle, const cv::Mat &color, const cv::Mat &frame, ArCameraParam &camParams, const bool &reverse)
1310{
1311 if (IsTracked())
1312 {
1313 float err = 0;
1314 if (ar2Tracking(ar2handle, m_surfaceSet, frame.data, mCamPose, &err) < 0)
1315 {
1316 SetTracked(false);
1317 SetVisible(false);
1318 return false;
1319 }
1320 else
1321 {
1322 //std::vector<double> filterVals;
1323 int i, j;
1324 for (j = 0; j < 3; j++)
1325 for (i = 0; i < 4; i++)
1326 {
1327 mTackingPos[j][i] = mCamPose[j][i];
1328 //filterVals.push_back(mCamPose[j][i]);
1329 }
1330
1331 ComputeMatrix(camParams, reverse);
1332
1333
1334 //marker visibility is stable
1335 if (mNumGoodTracking < 4)
1336 mNumGoodTracking++;
1337 else
1338 {
1339 SetVisible(true);
1340 //WarpMarkerImage(color);
1341 };
1342
1343 return true;
1344 }
1345 }
1346 return false;
1347}
int AR_MARKER_TRAINNED_CB
Definition ArToolkit.cpp:46
#define MIN_TRACKED_MARKER_SIZE
Vector3 GetCameraOffset()
aruco::CameraParameters camParam
void SetNFTdetectorDirty()
static ArManager * GetInstance()
Definition ArManager.cpp:70
void SetPixelPosition(Vector3 pixelpos)
Definition ArMarker.cpp:62
void SetPosition(Vector3 pos)
Definition ArMarker.cpp:57
void SetOrientation(BtQuaternion orientation)
Definition ArMarker.cpp:67
float m_size
Definition ArMarker.h:56
void SetVisible(bool visible)
Definition ArMarker.cpp:100
void SetPageNum(int page)
bool m_isTrained
Definition ArTkMarker.h:55
bool GetWarpedMarker(cv::Mat &image)
bool TrackFrame(AR2HandleT *ar2handle, const cv::Mat &color, const cv::Mat &frame, ArCameraParam &camParams, const bool &reverse)
bool IsTracked()
bool m_isTracked
Definition ArTkMarker.h:54
bool SaveData(std::string path)
cv::Mat m_image
Definition ArTkMarker.h:53
ArTkMarker(std::string filePath, unsigned int nid, float size, unsigned int maxFeatures=600)
bool RegisterCurrentFrame(const cv::Mat &frame, cv::Size camsize, float tscale=1.0f)
void RegisterNextFrame(cv::Point point, cv::Size size)
int GetPageNum()
void StartTracking(cv::Mat color, const float camPose[3][4], ArCameraParam &camParams, const bool &reverse)
bool IsTrained()
KpmRefDataSet * GetDataSet()
void SetTrackedImage(cv::Mat tpl)
static BtQuaternion FromRotationMatrix(double rotMatrix[16], bool reverseX=false, bool reverseY=true)
bool LoadData(boost::filesystem::path path, KpmRefDataSet **refDataSetPtr, AR2SurfaceSetT **surfaceSetPtr)