AbandObjApp.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #include "AbandObjApp.h"
  2. #include "DetUtils.h"
  3. NAMESPACE_MAS_BEGIN
  4. NAMESPACE_ABANDOBJ_BEGIN
  5. tzc::Mutex AbandObjApp::_mutex;
  6. AbandObjApp* AbandObjApp::_instance = nullptr;
  7. AbandObjApp* AbandObjApp::Instance()
  8. {
  9. if (!_instance)
  10. {
  11. _mutex.Lock();
  12. if (!_instance)
  13. {
  14. _instance = new AbandObjApp();
  15. TZLogInfo("AbandObjApp Instance created~~~");
  16. }
  17. _mutex.Unlock();
  18. }
  19. ++(_instance->m_usecnt);
  20. return _instance;
  21. }
  22. void AbandObjApp::DestroyInstance()
  23. {
  24. tzc::ScopedLock lock(_mutex);
  25. if ((_instance->m_usecnt) < 0)
  26. {
  27. TZLogWarn("AbandObjApp Instance does not exist!!!");
  28. _instance->m_usecnt = 0;
  29. }
  30. else if ((_instance->m_usecnt) == 0)
  31. {
  32. TZ_delete(_instance);
  33. TZLogInfo("AbandObjApp Instance destroyed~~~");
  34. }
  35. else
  36. {
  37. TZLogWarn("AbandObjApp still in use by %d objects!", _instance->m_usecnt);
  38. TZ_delete(_instance);
  39. TZLogInfo("AbandObjApp Instance destroyed~~~");
  40. }
  41. }
  42. TZ_INT AbandObjApp::Initialize(const std::string& initParam)
  43. {
  44. if (m_inited)
  45. {
  46. TZLogInfo("AbandObjApp has been initialized~~~");
  47. return MEC_OK;
  48. }
  49. AbandObjBuild buildParam;
  50. AbandObjBuild::fromJson(initParam, buildParam);
  51. m_factor = buildParam.factor;
  52. m_shortTermRate = buildParam.short_term_rate;
  53. m_shortTermHistory = buildParam.short_term_history;
  54. m_longTermRate = buildParam.long_term_rate;
  55. m_longTermHistory = buildParam.long_term_history;
  56. m_varThreshold = buildParam.var_threshold;
  57. m_detectShadows = buildParam.detect_shadows;
  58. m_iouThreshold = buildParam.iou_threshold;
  59. m_areaThreshold = buildParam.area_threshold;
  60. m_perimeterThreshold = buildParam.perimeter_threshold;
  61. if (buildParam.algo == "MOG2")
  62. {
  63. m_pLongBG = cv::createBackgroundSubtractorMOG2(m_longTermHistory,
  64. m_varThreshold,
  65. m_detectShadows);
  66. m_pShortBG = cv::createBackgroundSubtractorMOG2(m_shortTermHistory,
  67. m_varThreshold,
  68. m_detectShadows);
  69. }
  70. else
  71. {
  72. TZLogError("Invalid algorithm name!!!");
  73. return MEC_FAILED;
  74. }
  75. m_inited = TRUE;
  76. TZLogInfo("AbandObjApp Initialized~~~");
  77. return MEC_OK;
  78. }
  79. TZ_INT AbandObjApp::SetDetectCfg(const std::string& initParam)
  80. {
  81. AbandObjCfg cfgParam;
  82. AbandObjCfg::fromJson(initParam, cfgParam);
  83. m_factor = cfgParam.factor;
  84. m_shortTermRate = cfgParam.short_term_rate;
  85. m_shortTermHistory = cfgParam.short_term_history;
  86. m_longTermRate = cfgParam.long_term_rate;
  87. m_longTermHistory = cfgParam.long_term_history;
  88. m_varThreshold = cfgParam.var_threshold;
  89. m_detectShadows = cfgParam.detect_shadows;
  90. m_iouThreshold = cfgParam.iou_threshold;
  91. m_areaThreshold = cfgParam.area_threshold;
  92. m_perimeterThreshold = cfgParam.perimeter_threshold;
  93. if (cfgParam.algo == "MOG2")
  94. {
  95. m_pLongBG = cv::createBackgroundSubtractorMOG2(m_longTermHistory,
  96. m_varThreshold,
  97. m_detectShadows);
  98. m_pShortBG = cv::createBackgroundSubtractorMOG2(m_shortTermHistory,
  99. m_varThreshold,
  100. m_detectShadows);
  101. }
  102. else
  103. {
  104. TZLogError("Invalid algorithm name!!!");
  105. return MEC_FAILED;
  106. }
  107. return MEC_OK;
  108. }
  109. TZ_INT AbandObjApp::Dispose()
  110. {
  111. if (!m_inited)
  112. {
  113. return MEC_NOT_INITED;
  114. }
  115. _mutex.Lock();
  116. --(m_usecnt);
  117. TZLogInfo("AbandObjApp usecnt -1, now = %d~~~", m_usecnt);
  118. TZ_BOOL empty = (m_usecnt == 0);
  119. _mutex.Unlock();
  120. if (empty)
  121. {
  122. m_inited = FALSE;
  123. TZLogInfo("AbandObjApp Dispose~~~");
  124. this->DestroyInstance();
  125. }
  126. return MEC_OK;
  127. }
  128. TZ_INT AbandObjApp::DoDetect(cv::Mat& input, std::vector<Proposal>& propRes)
  129. {
  130. cv::Mat image;
  131. cv::resize(input, image, cv::Size(input.cols / m_factor, input.rows / m_factor));
  132. cv::Mat ltMask, stMask, subMask;
  133. // 高斯模糊
  134. cv::GaussianBlur(image, image, cv::Size(5, 5), 0);
  135. // 转换为灰度图
  136. cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
  137. // 更新背景模型并获取前景掩码
  138. m_pLongBG->apply(image, ltMask, m_longTermRate);
  139. m_pShortBG->apply(image, stMask, m_shortTermRate);
  140. // 计算长期掩码减去短期掩码,得到差分掩码
  141. cv::subtract(ltMask, stMask, subMask);
  142. // 对差分掩码进行去噪处理
  143. // 先腐蚀再膨胀(开操作)
  144. cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
  145. cv::erode(subMask, subMask, kernel, cv::Point(-1, -1), 2, 1, 1);
  146. kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
  147. cv::dilate(subMask, subMask, cv::Mat(), cv::Point(-1, -1), 2, 1, 1);
  148. // 高斯模糊进一步平滑掩码
  149. cv::GaussianBlur(subMask, subMask, cv::Size(49, 49), 7);
  150. // 将低于阈值的像素设为0,进一步清理噪点
  151. subMask.setTo(0, subMask <= 5);
  152. // 查找轮廓
  153. std::vector<std::vector<cv::Point>> contours;
  154. cv::findContours(subMask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
  155. // 遍历所有轮廓
  156. for (size_t i = 0; i < contours.size(); i++) {
  157. double area = cv::contourArea(contours[i]);
  158. double perimeter = cv::arcLength(contours[i], true);
  159. // 过滤掉面积或周长过小的轮廓
  160. if (area > m_areaThreshold && perimeter > m_perimeterThreshold) {
  161. // 绘制轮廓
  162. cv::drawContours(image, contours, i, cv::Scalar(0, 0, 255), 2);
  163. // 获取轮廓的边界矩形
  164. cv::Rect rect = cv::boundingRect(contours[i]);
  165. // 绘制矩形
  166. cv::rectangle(image, rect, cv::Scalar(0, 255, 0), 2);
  167. // 创建proposal对象
  168. Proposal p;
  169. p.x = rect.x * m_factor; // 恢复到原始尺寸
  170. p.y = rect.y * m_factor;
  171. p.w = rect.width * m_factor;
  172. p.h = rect.height * m_factor;
  173. p.life = 10; // 初始生命周期
  174. p.status = Active; // 初始状态
  175. // 检查当前proposal是否与已有proposal重叠
  176. for (size_t j = 0; j < m_proposals.size(); j++) {
  177. AreaBox boxA, boxB;
  178. boxA.LTX = p.x;
  179. boxA.LTY = p.y;
  180. boxA.RBX = p.x + p.w;
  181. boxA.RBY = p.y + p.h;
  182. boxB.LTX = m_proposals[j].x;
  183. boxB.LTY = m_proposals[j].y;
  184. boxB.RBX = m_proposals[j].x + m_proposals[j].w;
  185. boxB.RBY = m_proposals[j].y + m_proposals[j].h;
  186. if (!detutils::IsIoULeqThreshold(boxA, boxB, m_iouThreshold)) {
  187. p.status = Overlap; // 重叠,不添加新的proposal
  188. m_proposals[j].life++; // 延长已有proposal的生命周期
  189. if (m_proposals[j].status == Accepted){
  190. continue; // 已经进行过检测
  191. }
  192. m_proposals[j].status = Active; // 标记为需要检测的有效proposal
  193. }
  194. }
  195. // 如果没有与任何proposal重叠,则添加为新的proposal
  196. if (p.status == Active){
  197. m_proposals.push_back(p);
  198. }
  199. }
  200. }
  201. // 遍历所有proposal,更新其状态
  202. for (size_t i = 0; i < m_proposals.size(); i++) {
  203. if (m_proposals[i].status == Active) { // 需要检测的proposal
  204. if (m_proposals[i].life > 60) { // 生存超过60帧
  205. // 处理proposal区域
  206. //Mat roi = solve_proposal(origin_frame, proposals[i]);
  207. // TODO: 对roi进行CLIP视觉特征提取和结果保存
  208. propRes.push_back(m_proposals[i]);
  209. m_proposals[i].status = Accepted; // 标记为已检测
  210. }
  211. } else {
  212. // 减少proposal的生命周期
  213. m_proposals[i].life--;
  214. if (m_proposals[i].life == 0) {
  215. // 生命周期结束,删除proposal
  216. m_proposals.erase(m_proposals.begin() + i);
  217. i--; // 调整索引
  218. }
  219. }
  220. }
  221. return MEC_OK;
  222. }
  223. AbandObjApp::AbandObjApp()
  224. : m_inited(FALSE),
  225. m_usecnt(0) {}
  226. AbandObjApp::~AbandObjApp()
  227. {
  228. this->Dispose();
  229. }
  230. NAMESPACE_ABANDOBJ_END
  231. NAMESPACE_MAS_END