track.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. #include "track.h"
  2. //#include "dat/dat_tracker.hpp"
  3. ///
  4. /// \brief CTrack
  5. /// \param pt
  6. /// \param region
  7. /// \param deltaTime
  8. /// \param accelNoiseMag
  9. /// \param trackID
  10. /// \param filterObjectSize
  11. /// \param externalTrackerForLost
  12. ///
  13. CTrack::CTrack(const CRegion& region,
  14. tracking::KalmanType kalmanType,
  15. track_t deltaTime,
  16. track_t accelNoiseMag,
  17. bool useAcceleration,
  18. size_t trackID,
  19. size_t regionID,
  20. tracking::FilterGoal filterGoal,
  21. tracking::LostTrackType externalTrackerForLost
  22. )
  23. :
  24. m_trackID(trackID),
  25. m_regionID(regionID),
  26. m_skippedFrames(0),
  27. m_lastRegion(region),
  28. m_predictionPoint(region.m_rect.center),
  29. m_predictionRect(region.m_rrect),
  30. m_predictionRect3D(region.m_rect),
  31. m_kalman(kalmanType, useAcceleration, deltaTime, accelNoiseMag),
  32. m_filterGoal(filterGoal),
  33. m_outOfTheFrame(false),
  34. m_externalTrackerForLost(externalTrackerForLost)
  35. {
  36. if (filterGoal == tracking::FilterRect)
  37. m_kalman.Update(region.m_brect, true);
  38. else if(filterGoal == tracking::FilterRect3D)
  39. m_kalman.Update(region.m_rect, true);
  40. else
  41. m_kalman.Update(m_predictionPoint, true);
  42. m_trace.push_back(m_predictionPoint, m_predictionPoint);
  43. }
  44. ///
  45. /// \brief CTrack::CalcDistCenter
  46. /// \param reg
  47. /// \return
  48. ///
  49. track_t CTrack::CalcDistCenter(const CRegion& reg) const
  50. {
  51. cv::Point3f diff = m_predictionPoint - reg.m_rect.center;
  52. return sqrtf(sqr(diff.x) + sqr(diff.y));
  53. }
  54. ///
  55. /// \brief CTrack::CalcDistRect
  56. /// \param reg
  57. /// \return
  58. ///
  59. track_t CTrack::CalcDistRect(const CRegion& reg) const
  60. {
  61. std::array<track_t, 5> diff;
  62. diff[0] = reg.m_rrect.center.x - m_lastRegion.m_rrect.center.x;
  63. diff[1] = reg.m_rrect.center.y - m_lastRegion.m_rrect.center.y;
  64. diff[2] = static_cast<track_t>(m_lastRegion.m_rrect.size.width - reg.m_rrect.size.width);
  65. diff[3] = static_cast<track_t>(m_lastRegion.m_rrect.size.height - reg.m_rrect.size.height);
  66. diff[4] = static_cast<track_t>(m_lastRegion.m_rrect.angle - reg.m_rrect.angle);
  67. track_t dist = 0;
  68. for (size_t i = 0; i < diff.size(); ++i)
  69. {
  70. dist += sqr(diff[i]);
  71. }
  72. return sqrtf(dist);
  73. }
  74. ///
  75. /// \brief CTrack::CalcDistRect3D
  76. /// \param reg
  77. /// \return
  78. ///
  79. track_t CTrack::CalcDistRect3D(const CRegion& reg) const
  80. {
  81. std::array<track_t, 7> diff;
  82. diff[0] = reg.m_rect.center.x - m_lastRegion.m_rect.center.x;
  83. diff[1] = reg.m_rect.center.y - m_lastRegion.m_rect.center.y;
  84. diff[2] = 0;//reg.m_rect.center.z - m_lastRegion.m_rect.center.z;
  85. diff[3] = static_cast<track_t>(m_lastRegion.m_rect.size.width - reg.m_rect.size.width);
  86. diff[4] = static_cast<track_t>(m_lastRegion.m_rect.size.height - reg.m_rect.size.height);
  87. diff[5] = static_cast<track_t>(m_lastRegion.m_rect.size.length - reg.m_rect.size.length);
  88. diff[6] = 0;//static_cast<track_t>(m_lastRegion.m_rect.yaw - reg.m_rect.yaw);
  89. track_t dist = 0;
  90. for (size_t i = 0; i < diff.size(); ++i)
  91. {
  92. dist += sqr(diff[i]);
  93. }
  94. return sqrtf(dist);
  95. }
  96. ///
  97. /// \brief CTrack::Update
  98. /// \*param region
  99. /// \param dataCorrect
  100. /// \param max_trace_length
  101. /// \param prevFrame
  102. /// \param currFrame
  103. /// \param trajLen
  104. ///
  105. void CTrack::Update(
  106. const CRegion& region,
  107. bool dataCorrect,
  108. size_t max_trace_length,
  109. cv::UMat prevFrame,
  110. cv::UMat currFrame,
  111. int trajLen
  112. )
  113. {
  114. if (m_filterGoal == tracking::FilterRect) // Kalman filter for object coordinates and size
  115. RectUpdate(region, dataCorrect, prevFrame, currFrame);
  116. if (m_filterGoal == tracking::FilterRect3D) // Kalman filter for object coordinates and size
  117. Rect3DUpdate(region, dataCorrect, prevFrame, currFrame);
  118. else // Kalman filter only for object center
  119. PointUpdate(region.m_rect.center, region.m_rrect.size, dataCorrect, currFrame.size());
  120. if (dataCorrect)
  121. {
  122. //std::cout << m_lastRegion.m_brect << " - " << region.m_brect << std::endl;
  123. m_lastRegion = region;
  124. m_trace.push_back(m_predictionPoint, region.m_rect.center);
  125. CheckStatic(trajLen, currFrame, region);
  126. }
  127. else
  128. {
  129. m_trace.push_back(m_predictionPoint);
  130. }
  131. if (m_trace.size() > max_trace_length)
  132. m_trace.pop_front(m_trace.size() - max_trace_length);
  133. }
  134. ///
  135. /// \brief CTrack::IsStatic
  136. /// \return
  137. ///
  138. bool CTrack::IsStatic() const
  139. {
  140. return m_isStatic;
  141. }
  142. ///
  143. /// \brief CTrack::IsStaticTimeout
  144. /// \param framesTime
  145. /// \return
  146. ///
  147. bool CTrack::IsStaticTimeout(int framesTime) const
  148. {
  149. return (m_staticFrames > framesTime);
  150. }
  151. ///
  152. /// \brief CTrack::IsOutOfTheFrame
  153. /// \return
  154. ///
  155. bool CTrack::IsOutOfTheFrame() const
  156. {
  157. return m_outOfTheFrame;
  158. }
  159. ///
  160. //cv::RotatedRect CTrack::CalcPredictionEllipse(cv::Size_<track_t> minRadius) const
  161. //{
  162. // // Move ellipse to velocity
  163. // auto velocity = m_kalman.GetVelocity();
  164. // Point_t d(3.f * velocity[0], 3.f * velocity[1]);
  165. // cv::RotatedRect rrect(m_predictionPoint, cv::Size2f(std::max(minRadius.width, fabs(d.x)), std::max(minRadius.height, fabs(d.y))), 0);
  166. // if (fabs(d.x) + fabs(d.y) > 4) // pix
  167. // {
  168. // if (fabs(d.x) > 0.0001f)
  169. // {
  170. // track_t l = std::min(rrect.size.width, rrect.size.height) / 3;
  171. // track_t p2_l = sqrtf(sqr(d.x) + sqr(d.y));
  172. // rrect.center.x = l * d.x / p2_l + m_predictionPoint.x;
  173. // rrect.center.y = l * d.y / p2_l + m_predictionPoint.y;
  174. // rrect.angle = atanf(d.y / d.x);
  175. // }
  176. // else
  177. // {
  178. // rrect.center.y += d.y / 3;
  179. // rrect.angle = static_cast<float>(CV_PI / 2.);
  180. // }
  181. // }
  182. // return rrect;
  183. //}
  184. ///
  185. /// \brief CTrack::IsInsideArea
  186. /// If result <= 1 then center of the object is inside ellipse with prediction and velocity
  187. /// \param pt
  188. /// \return
  189. ///
  190. track_t CTrack::IsInsideArea(const Point_t& pt, const cv::RotatedRect& rrect) const
  191. {
  192. Point_t pt_(pt.x - rrect.center.x, pt.y - rrect.center.y);
  193. track_t r = sqrtf(sqr(pt_.x) + sqr(pt_.y));
  194. track_t t = (r > 1) ? acosf(pt_.x / r) : 0;
  195. track_t t_ = t - rrect.angle;
  196. Point_t pt_rotated(r * cosf(t_), r * sinf(t_));
  197. return sqr(pt_rotated.x) / sqr(rrect.size.width) + sqr(pt_rotated.y) / sqr(rrect.size.height);
  198. }
  199. ///
  200. /// \brief CTrack::WidthDist
  201. /// \param reg
  202. /// \return
  203. ///
  204. track_t CTrack::WidthDist(const CRegion& reg) const
  205. {
  206. if (m_lastRegion.m_rect.size.width < reg.m_rect.size.width)
  207. return m_lastRegion.m_rect.size.width / reg.m_rect.size.width;
  208. else
  209. return reg.m_rect.size.width / m_lastRegion.m_rect.size.width;
  210. }
  211. ///
  212. /// \brief CTrack::HeightDist
  213. /// \param reg
  214. /// \return
  215. ///
  216. track_t CTrack::HeightDist(const CRegion& reg) const
  217. {
  218. if (m_lastRegion.m_rect.size.height < reg.m_rect.size.height)
  219. return m_lastRegion.m_rect.size.height / reg.m_rect.size.height;
  220. else
  221. return reg.m_rect.size.height / m_lastRegion.m_rect.size.height;
  222. }
  223. ///
  224. /// \brief CTrack::CheckStatic
  225. /// \param trajLen
  226. /// \return
  227. ///
  228. bool CTrack::CheckStatic(int trajLen, cv::UMat currFrame, const CRegion& region)
  229. {
  230. if (!trajLen || static_cast<int>(m_trace.size()) < trajLen)
  231. {
  232. m_isStatic = false;
  233. m_staticFrames = 0;
  234. m_staticFrame = cv::UMat();
  235. }
  236. else
  237. {
  238. track_t kx = 0;
  239. track_t bx = 0;
  240. track_t ky = 0;
  241. track_t by = 0;
  242. get_lin_regress_params(m_trace, m_trace.size() - trajLen, m_trace.size(), kx, bx, ky, by);
  243. track_t speed = sqrt(sqr(kx * trajLen) + sqr(ky * trajLen));
  244. const track_t speedThresh = 10;
  245. if (speed < speedThresh)
  246. {
  247. if (!m_isStatic)
  248. {
  249. m_staticFrame = currFrame.clone();
  250. m_staticRect = region.m_rect;
  251. }
  252. ++m_staticFrames;
  253. m_isStatic = true;
  254. }
  255. else
  256. {
  257. m_isStatic = false;
  258. m_staticFrames = 0;
  259. m_staticFrame = cv::UMat();
  260. }
  261. }
  262. return m_isStatic;
  263. }
  264. ///
  265. /// \brief GetLastRect
  266. /// \return
  267. ///
  268. Rect3D CTrack::GetLastRect() const
  269. {
  270. if (m_filterGoal == tracking::FilterRect)
  271. return Rect3D(cv::Point3f(m_predictionRect.center.x,m_predictionRect.center.y,0),Size3D(m_predictionRect.boundingRect().width,m_predictionRect.boundingRect().height,0),0);
  272. else if(m_filterGoal == tracking::FilterRect3D)
  273. return m_predictionRect3D;
  274. else
  275. return Rect3D(cv::Point3f(m_predictionPoint.x, m_predictionPoint.y,0),Size3D(0,0,0),0);
  276. }
  277. ///
  278. /// \brief CTrack::LastRegion
  279. /// \return
  280. ///
  281. const CRegion& CTrack::LastRegion() const
  282. {
  283. return m_lastRegion;
  284. }
  285. ///
  286. /// \brief CTrack::ConstructObject
  287. /// \return
  288. ///
  289. TrackingObject CTrack::ConstructObject() const
  290. {
  291. return TrackingObject(GetLastRect(), m_lastRegion, m_trackID, m_regionID, m_trace, IsStatic(), IsOutOfTheFrame(), m_kalman.GetVelocity(), m_detectedFrames);
  292. }
  293. ///
  294. /// \brief CTrack::SkippedFrames
  295. /// \return
  296. ///
  297. size_t CTrack::SkippedFrames() const
  298. {
  299. return m_skippedFrames;
  300. }
  301. ///
  302. /// \brief CTrack::SkippedFrames
  303. /// \return
  304. ///
  305. size_t& CTrack::SkippedFrames()
  306. {
  307. return m_skippedFrames;
  308. }
  309. ///
  310. /// \brief CTrack::DetectedFrames
  311. /// \return
  312. ///
  313. size_t& CTrack::DetectedFrames()
  314. {
  315. return m_detectedFrames;
  316. }
  317. ///
  318. /// \brief RectUpdate
  319. /// \param region
  320. /// \param dataCorrect
  321. /// \param prevFrame
  322. /// \param currFrame
  323. ///
  324. void CTrack::RectUpdate(
  325. const CRegion& region,
  326. bool dataCorrect,
  327. cv::UMat prevFrame,
  328. cv::UMat currFrame
  329. )
  330. {
  331. m_kalman.GetRectPrediction();
  332. bool recalcPrediction = true;
  333. auto Clamp = [](int& v, int& size, int hi) -> int
  334. {
  335. int res = 0;
  336. if (size < 1)
  337. size = 0;
  338. if (v < 0)
  339. {
  340. res = v;
  341. v = 0;
  342. return res;
  343. }
  344. else if (v + size > hi - 1)
  345. {
  346. res = v;
  347. v = hi - 1 - size;
  348. if (v < 0)
  349. {
  350. size += v;
  351. v = 0;
  352. }
  353. res -= v;
  354. return res;
  355. }
  356. return res;
  357. };
  358. auto UpdateRRect = [&](cv::Rect prevRect, cv::Rect newRect)
  359. {
  360. m_predictionRect.center.x += newRect.x - prevRect.x;
  361. m_predictionRect.center.y += newRect.y - prevRect.y;
  362. m_predictionRect.size.width *= newRect.width / static_cast<float>(prevRect.width);
  363. m_predictionRect.size.height *= newRect.height / static_cast<float>(prevRect.height);
  364. };
  365. switch (m_externalTrackerForLost)
  366. {
  367. case tracking::TrackNone:
  368. break;
  369. }
  370. if (recalcPrediction)
  371. UpdateRRect(m_predictionRect.boundingRect(), m_kalman.Update(region.m_brect, dataCorrect));
  372. cv::Rect brect = m_predictionRect.boundingRect();
  373. int dx = Clamp(brect.x, brect.width, currFrame.cols);
  374. int dy = Clamp(brect.y, brect.height, currFrame.rows);
  375. m_outOfTheFrame = (dx != 0) || (dy != 0) || (brect.width < 2) || (brect.height < 2);
  376. m_predictionPoint = cv::Point3f(m_predictionRect.center.x,m_predictionRect.center.y,0);
  377. //std::cout << "brect = " << brect << ", dx = " << dx << ", dy = " << dy << ", outOfTheFrame = " << m_outOfTheFrame << ", predictionPoint = " << m_predictionPoint << std::endl;
  378. }
  379. ///
  380. /// \brief Rect3DUpdate
  381. /// \param region
  382. /// \param dataCorrect
  383. /// \param prevFrame
  384. /// \param currFrame
  385. ///
  386. void CTrack::Rect3DUpdate(
  387. const CRegion& region,
  388. bool dataCorrect,
  389. cv::UMat prevFrame,
  390. cv::UMat currFrame
  391. )
  392. {
  393. m_kalman.GetRect3DPrediction();
  394. switch (m_externalTrackerForLost)
  395. {
  396. case tracking::TrackNone:
  397. break;
  398. }
  399. m_predictionRect3D = m_kalman.Update(region.m_rect, dataCorrect);
  400. m_predictionPoint = m_predictionRect3D.center;
  401. //std::cout << "brect = " << brect << ", dx = " << dx << ", dy = " << dy << ", outOfTheFrame = " << m_outOfTheFrame << ", predictionPoint = " << m_predictionPoint << std::endl;
  402. }
  403. ///
  404. /// \brief PointUpdate
  405. /// \param pt
  406. /// \param dataCorrect
  407. ///
  408. void CTrack::PointUpdate(
  409. const cv::Point3f& pt,
  410. const cv::Size& newObjSize,
  411. bool dataCorrect,
  412. const cv::Size& frameSize
  413. )
  414. {
  415. m_kalman.GetPointPrediction();
  416. m_predictionPoint = m_kalman.Update(pt, dataCorrect);
  417. if (dataCorrect)
  418. {
  419. const int a1 = 1;
  420. const int a2 = 9;
  421. m_predictionRect.size.width = (a1 * newObjSize.width + a2 * m_predictionRect.size.width) / (a1 + a2);
  422. m_predictionRect.size.height = (a1 * newObjSize.height + a2 * m_predictionRect.size.height) / (a1 + a2);
  423. }
  424. auto Clamp = [](track_t& v, int hi) -> bool
  425. {
  426. if (v < 0)
  427. {
  428. v = 0;
  429. return true;
  430. }
  431. else if (hi && v > hi - 1)
  432. {
  433. v = static_cast<track_t>(hi - 1);
  434. return true;
  435. }
  436. return false;
  437. };
  438. auto p = m_predictionPoint;
  439. m_outOfTheFrame = Clamp(p.x, frameSize.width) || Clamp(p.y, frameSize.height) || (m_predictionRect.size.width < 2) || (m_predictionRect.size.height < 2);
  440. //std::cout << "predictionRect = " << m_predictionRect.boundingRect() << ", outOfTheFrame = " << m_outOfTheFrame << ", predictionPoint = " << m_predictionPoint << std::endl;
  441. }