BitmapToolkit Scol plugin
ArTkDetector.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//#include "sService.h"
26
27#include "ArManager.h"
28#include "ArCameraParam.h"
29#include "ArTkDetector.h"
30
31#include <vector>
32
34{
35 mIsDirty = false;
36 needUpdate = false;
37 mDetectionInProgress = false;
38 mKpmHandle = 0;
39 mAr2Handle = 0;
40 mArCamParam = 0;
41 mNumSkip = 0;
42 mScale = 1.0f;
43
44 // Run thread
45 StartThreading(boost::bind(&ArTkDetector::GoThread, this));
46}
47
49{
51
52 if (mKpmHandle)
53 kpmDeleteHandle(&mKpmHandle);
54
55 if (mAr2Handle)
56 ar2DeleteHandle(&mAr2Handle);
57
58 if (mArCamParam)
59 arParamLTFree(&mArCamParam);
60}
61
63{
64 boost::unique_lock<boost::recursive_mutex> lu(mUpdateMutex);
65
66 ArTkMarker* nftmarker = static_cast<ArTkMarker*>(marker);
67
68 mMarkerList.insert(nftmarker);
69
70 lu.unlock();
71}
72
74{
75 boost::unique_lock<boost::recursive_mutex> lu(mUpdateMutex);
76
77 std::set<ArTkMarker*>::iterator imarker = mMarkerList.find(static_cast<ArTkMarker*> (marker));
78 if (imarker != mMarkerList.end())
79 mMarkerList.erase(imarker);
80
81 lu.unlock();
82}
83
85{
86 mIsDirty = true;
87}
88
89void ArTkDetector::BuildCameraParam(ArCameraParam &camparam)
90{
91 if (mArCamParam)
92 arParamLTFree(&mArCamParam);
93
94 mScale = 1.0f;
95
96 int maxsize = std::max(camparam.camParam.CamSize.width, camparam.camParam.CamSize.height);
97 if (maxsize > 640)
98 mScale = 640.0f / (float)maxsize;
99
100 /*if (maxsize > 1600)
101 mScale = 0.4f;
102 else if (maxsize > 1200)
103 mScale = 0.53333f;
104 else if (maxsize > 750)
105 mScale = 0.85333f;
106 else if (maxsize > 640)
107 mScale = 0.9f;
108 else
109 mScale = 1.0f;
110
111#if defined(ANDROID) || defined(APPLE_IOS) || defined(RPI)
112 if (maxsize > 640)
113 mScale *= 0.75f;
114#endif
115 */
116
117 //construct ARtk camParam
118 ARParam cparam;
119 cparam.xsize = (int)((float)camparam.camParam.CamSize.width * mScale);
120 cparam.ysize = (int)((float)camparam.camParam.CamSize.height * mScale);
121
122 cparam.mat[0][0] = camparam.camParam.CameraMatrix.at<float>(0, 0) * mScale;
123 cparam.mat[0][1] = camparam.camParam.CameraMatrix.at<float>(0, 1);
124 cparam.mat[0][2] = camparam.camParam.CameraMatrix.at<float>(0, 2) * mScale;
125 cparam.mat[0][3] = 0.0;
126 cparam.mat[1][0] = camparam.camParam.CameraMatrix.at<float>(1, 0);
127 cparam.mat[1][1] = camparam.camParam.CameraMatrix.at<float>(1, 1) * mScale;
128 cparam.mat[1][2] = camparam.camParam.CameraMatrix.at<float>(1, 2) * mScale;
129 cparam.mat[1][3] = 0.0;
130 cparam.mat[2][0] = camparam.camParam.CameraMatrix.at<float>(2, 0);
131 cparam.mat[2][1] = camparam.camParam.CameraMatrix.at<float>(2, 1);
132 cparam.mat[2][2] = camparam.camParam.CameraMatrix.at<float>(2, 2);
133 cparam.mat[2][3] = 0.0;
134
135 cparam.dist_function_version = 4;
136 cparam.dist_factor[0] = 0.0; // 0.11478076875209808
137 cparam.dist_factor[1] = 0.0; // -0.52081894874572754
138 cparam.dist_factor[2] = 0.0; // -0.00020698705338872969
139 cparam.dist_factor[3] = 0.0; // -0.0040593123994767666
140 cparam.dist_factor[4] = cparam.xsize; // 1348.3432617187500
141 cparam.dist_factor[5] = cparam.xsize; // 1352.3159179687500
142 cparam.dist_factor[6] = cparam.ysize; // 636.59558105468750
143 cparam.dist_factor[7] = cparam.ysize; // 507.52099609375000
144 cparam.dist_factor[8] = 1.0; // 0.99392257313642507
145
146 //arParamLoad("Plugins/btdata/camera_para.dat", 1, &cparam);
147 //arParamChangeSize(&cparam, mLastData.gray.cols, mLastData.gray.rows, &cparam);
148 mArCamParam = arParamLTCreate(&cparam, AR_PARAM_LT_DEFAULT_OFFSET);
149}
150
151void ArTkDetector::InitDetector()
152{
153 boost::unique_lock<boost::recursive_mutex> ld(mUpdateMutex);
154 if (mKpmHandle)
155 kpmDeleteHandle(&mKpmHandle);
156
157 if (mAr2Handle)
158 ar2DeleteHandle(&mAr2Handle);
159
160 // KPM init.
161 mKpmHandle = kpmCreateHandle(mArCamParam);
162 //kpmSetSurfThreadNum(mKpmHandle, 1);
163 //kpmSetProcMode(mKpmHandle, KpmProcTwoThirdSize);
164 kpmSetDetectedFeatureMax(mKpmHandle, 250);
165
166 // AR2 init.
167 mAr2Handle = ar2CreateHandle(mArCamParam, AR_PIXEL_FORMAT_MONO, -1);
168
169 ar2SetTrackingThresh(mAr2Handle, 5.0);
170 ar2SetSimThresh(mAr2Handle, 0.5);
171 ar2SetSearchFeatureNum(mAr2Handle, 64);
172 ar2SetSearchSize(mAr2Handle, 8);
173 ar2SetTemplateSize1(mAr2Handle, 4);
174 ar2SetTemplateSize2(mAr2Handle, 6);
175
176 // load markers data
177 KpmRefDataSet *refDataSet = NULL;
178 int pageCount = 0;
179
180 std::set<ArTkMarker*>::iterator ifttmarker;
181 for (ifttmarker = mMarkerList.begin(); ifttmarker != mMarkerList.end(); ++ifttmarker)
182 {
183 if (!(*ifttmarker)->IsTrained())
184 continue;
185
186 //add marker
187 KpmRefDataSet *refDataSet2 = (*ifttmarker)->GetDataSet();
188 if (refDataSet2 == NULL)
189 continue;
190
191 (*ifttmarker)->SetPageNum(pageCount);
192 kpmChangePageNoOfRefDataSet(refDataSet2, KpmChangePageNoAllPages, pageCount);
193 kpmMergeRefDataSet(&refDataSet, &refDataSet2);
194 pageCount++;
195 }
196
197 if (refDataSet != NULL)
198 {
199 kpmSetRefDataSet(mKpmHandle, refDataSet);
200 kpmDeleteRefDataSet(&refDataSet);
201 }
202
203 ld.unlock();
204}
205
206void ArTkDetector::NFTDetect()
207{
208 KpmResult* kpmResult = NULL;
209 int kpmResultNum = 0;
210
211 {
212 boost::mutex::scoped_lock ld(mDetectMutex);
213 if (mDetectorFrame.empty() || mDetectorFrame.data == 0)
214 return;
215
216 kpmSetMatchingSkipPage(mKpmHandle, mSkippage, mNumSkip);
217 kpmMatching(mKpmHandle, mDetectorFrame.data);
218 kpmGetResult(mKpmHandle, &kpmResult, &kpmResultNum);
219 }
220
221 boost::unique_lock<boost::recursive_mutex> ld(mUpdateMutex);
222 std::set<ArTkMarker*>::iterator imarker;
223
224 for (int i = 0; i < kpmResultNum; i++)
225 {
226 if (kpmResult[i].camPoseF != 0)
227 continue;
228
229 //found marker ?
230 for (imarker = mMarkerList.begin(); imarker != mMarkerList.end(); ++imarker)
231 {
232 if (!(*imarker)->IsTracked() && (*imarker)->IsTrained() && ((*imarker)->GetPageNum() == kpmResult[i].pageNo))
233 (*imarker)->StartTracking(mDetectorColorFrame, kpmResult[i].camPose, mCamparam, mReverse);
234 }
235 }
236 mDetectionInProgress = false;
237 ld.unlock();
238}
239
241{
242 boost::thread detectorThread;
243 while (IsRunning())
244 {
245 if (needUpdate)
246 {
248 manager->GetLastData(mLastData);
249
250 needUpdate = false;
251 bool needDetect = false;
252
253 //cv::blur(mLastData.gray, mLastData.gray, cv::Size(2, 2));
254
255 // Detect all markers seen on gray
256
257 // camera size changed
258 if ((mArCamParam == 0) || (mArCamParam && (((int)((float)mLastData.arCamParam.camParam.CamSize.width * mScale)) != mArCamParam->param.xsize || ((int)((float)mLastData.arCamParam.camParam.CamSize.height * mScale)) != mArCamParam->param.ysize)))
259 mIsDirty = true;
260
261 // init detector
262 if (mIsDirty && !mMarkerList.empty())
263 {
264 boost::mutex::scoped_lock ld(mDetectMutex);
265 mIsDirty = false;
266 if (detectorThread.joinable())
267 detectorThread.join();
268 BuildCameraParam(mLastData.arCamParam);
269 InitDetector();
270 }
271
272 cv::Size nsize;
273 nsize.width = (int)((float)mLastData.gray.cols * mScale);
274 nsize.height = (int)((float)mLastData.gray.rows * mScale);
275
276 if (mScale != 1.0f)
277 cv::resize(mLastData.gray, mLastData.gray, nsize, 0, 0, cv::INTER_LINEAR);
278
279 cv::equalizeHist(mLastData.gray, mLastData.gray);
280
281 boost::unique_lock<boost::recursive_mutex> lu(mUpdateMutex);
282 std::set<ArTkMarker*>::iterator imarker;
283
284 for (imarker = mMarkerList.begin(); imarker != mMarkerList.end(); ++imarker)
285 {
286 if (!(*imarker)->IsTracked())
287 needDetect = true;
288 }
289
290 //tracking
291 for (imarker = mMarkerList.begin(); imarker != mMarkerList.end(); ++imarker)
292 {
293 if ((*imarker)->IsTracked())
294 (*imarker)->TrackFrame(mAr2Handle, mLastData.image, mLastData.gray, mLastData.arCamParam, mLastData.reversedBitmap);
295
296 (*imarker)->RegisterCurrentFrame(mLastData.gray, nsize, mScale);
297 }
298
299 // build nft detector mask
300 if (needDetect && !mDetectionInProgress && !mLastData.image.empty())
301 {
302 boost::mutex::scoped_lock ld(mDetectMutex);
303
304 if (detectorThread.joinable())
305 detectorThread.join();
306
307 mDetectionInProgress = true;
308 mLastData.gray.copyTo(mDetectorFrame);
309 mNumSkip = 0;
310
311 //mask tracked markers
312 unsigned int i;
313 for (imarker = mMarkerList.begin(); imarker != mMarkerList.end(); ++imarker)
314 {
315 if ((*imarker)->IsTracked())
316 {
317 std::vector<cv::Point> poly;
318 for (i = 0; i < (*imarker)->size(); i++)
319 {
320 cv::Point pt1(static_cast<int>((*imarker)->at(i).x * mScale), static_cast<int>((*imarker)->at(i).y * mScale));
321 poly.push_back(pt1);
322 }
323 cv::fillConvexPoly(mDetectorFrame, poly, cv::Scalar(0));
324 mSkippage[mNumSkip] = (*imarker)->GetPageNum();
325 mNumSkip++;
326 }
327 }
328
329 mCamparam = mLastData.arCamParam;
330 mReverse = mLastData.reversedBitmap;
331 //cv::resize(mLastData.image, mDetectorColorFrame, nsize, 0, 0, cv::INTER_CUBIC);
332 mLastData.image.copyTo(mDetectorColorFrame);
333 detectorThread = boost::thread(&ArTkDetector::NFTDetect, this);
334 }
335
336 lu.unlock();
337 }
338 else
339 {
340 //prevent cpu burn
341 boost::this_thread::sleep_for(boost::chrono::milliseconds(1)); //DO not burn too much CPU
342 }
343 }
344
345 if (detectorThread.joinable())
346 detectorThread.join();
347}
aruco::CameraParameters camParam
void GetLastData(LASTDATA &data)
static ArManager * GetInstance()
Definition ArManager.cpp:70
void RemoveMarker(ArMarker *marker)
void AddMarker(ArMarker *marker)
This class represents a marker. It is a vector of the fours corners ot the marker.
Definition ArTkMarker.h:51
ArCameraParam arCamParam
cv::Mat image
cv::Mat gray
bool reversedBitmap
Create a thread type. .
void StartThreading(std::function< void()> threadFunction)