grab_occlusion.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. #include <sstream>
  2. #include <opencv2\highgui\highgui.hpp>
  3. #include "grab_occlusion.h"
  4. #include "utils.h"
  5. namespace graft_cv {
  6. CStemResultInfos::CStemResultInfos(double seedling_dist,
  7. int holes_number,
  8. double x_min,
  9. double x_max,
  10. double z_min,
  11. double z_max,
  12. std::string pcd_id,
  13. CGcvLogger*pLog)
  14. : m_pLogger(pLog)
  15. , m_seedling_dist(seedling_dist)
  16. , m_holes_number(holes_number)
  17. , m_xmin(x_min)
  18. , m_xmax(x_max)
  19. , m_zmin(z_min)
  20. , m_zmax(z_max)
  21. //, m_append_counter(0)
  22. , m_pcdId(pcd_id)
  23. , m_max_size(50)
  24. {
  25. gen_root_centers();
  26. }
  27. CStemResultInfos::~CStemResultInfos()
  28. {}
  29. void CStemResultInfos::append(
  30. CStemResult& sr
  31. )
  32. {
  33. m_infos.insert(m_infos.begin(), sr);
  34. if (m_infos.size() > m_max_size) {
  35. m_infos.pop_back();
  36. }
  37. //m_append_counter += 1;
  38. //每次都更新
  39. _update_root_centers(sr);
  40. //if (m_append_counter % 10 == 0) {
  41. // //定期写入数据
  42. // _update_root_centers();
  43. // write_root_centers(m_json_filename);
  44. //}
  45. }
  46. void CStemResultInfos::clear()
  47. {
  48. m_infos.clear();
  49. }
  50. void CStemResultInfos::get_root_centers(
  51. std::vector<CStemResult>&rst
  52. )
  53. {
  54. rst.clear();
  55. for (auto& sr : m_root_centers) {
  56. rst.push_back(sr);
  57. }
  58. }
  59. void CStemResultInfos::_update_root_centers(CStemResult& sr) {
  60. //直接在m_root_centers中找到最接近的中心,如果小于指定距离,更新m_root_centers
  61. double d1 = m_seedling_dist / 4.0;
  62. double d_min = 1.0e6;
  63. int min_root_idx = -1;
  64. for (int i = 0; i < m_root_centers.size(); ++i) {
  65. double dist = m_root_centers.at(i).calcluate_distance(sr);
  66. if (dist < d_min) {
  67. d_min = dist;
  68. min_root_idx = i;
  69. }
  70. }
  71. if (d_min < d1 && min_root_idx >= 0) {
  72. //更新指定中心
  73. double mu_x, mu_y, mu_z;
  74. CStemResult& min_root = m_root_centers.at(min_root_idx);
  75. mu_x = min_root.root_x;
  76. if (min_root.root_count == 0) {
  77. mu_y = sr.root_y;
  78. mu_z = sr.root_z;
  79. }
  80. else {
  81. mu_y = (min_root.root_y * min_root.root_count +
  82. sr.root_y * sr.root_count) / (double)(min_root.root_count + sr.root_count);
  83. mu_z = (min_root.root_z * min_root.root_count +
  84. sr.root_z * sr.root_count) / (double)(min_root.root_count + sr.root_count);
  85. }
  86. min_root.root_x = mu_x;
  87. min_root.root_y = mu_y;
  88. min_root.root_z = mu_z;
  89. min_root.root_count += sr.root_count;
  90. }
  91. }
  92. void CStemResultInfos::gen_root_centers()
  93. {
  94. //根据 m_seedling_dist, m_holes_number, m_xmin, m_xmax生成初始的穴位中心
  95. //以m_xmin, m_xmax的中间点为中心,分别找到间隔m_seedling_dist的m_holes_number个穴位中心
  96. //初始的z设成-1,等待更新赋值
  97. double x_mid = 0.5 * (m_xmin + m_xmax);
  98. double holes_mid = 0.5 * (m_holes_number - 1) * m_seedling_dist;
  99. double x0 = x_mid - holes_mid;
  100. double z_mid = 0.5 * (m_zmin + m_zmax);
  101. m_root_centers.clear();
  102. for (int i=0; i<m_holes_number; ++i) {
  103. double x = x0 + i * m_seedling_dist;
  104. double y = 0;
  105. double z = z_mid;
  106. int size = 0;
  107. int count = 0;
  108. CStemResult sr = CStemResult(x, y, z, size, std::string(""), count);
  109. m_root_centers.push_back(sr);
  110. }
  111. }
  112. CSeedlingStatus::CSeedlingStatus(
  113. int dtype,
  114. double step,
  115. double x_min,
  116. double x_max,
  117. double pc_mean_dist,
  118. CGcvLogger*pLog)
  119. : m_pLogger(pLog)
  120. , m_dtype(dtype)
  121. , m_bin_step(step)
  122. , m_xmin(x_min)
  123. , m_xmax(x_max)
  124. , m_record_cursor(-1)
  125. , m_global_cursor(-1)
  126. , m_max_size(50)
  127. , m_pc_mean_dist(pc_mean_dist)
  128. {
  129. int x0 = int(x_min);
  130. int x1 = int(x_max);
  131. m_hist_length = int((x1 - x0) / step);
  132. m_history_histogram = cv::Mat::zeros(m_max_size, m_hist_length, CV_32F);
  133. m_history_point_size = cv::Mat::zeros(m_max_size, 1, CV_32F);
  134. }
  135. CSeedlingStatus::~CSeedlingStatus()
  136. {}
  137. void CSeedlingStatus::set_x_centers(std::vector<double>&cx)
  138. {
  139. m_center_x.clear();
  140. for (auto&x : cx) {
  141. m_center_x.push_back(x);
  142. }
  143. std::sort(m_center_x.begin(), m_center_x.end());
  144. double seedling_distance = m_center_x.at(1) - m_center_x.at(0);
  145. m_idx_low.clear();
  146. m_idx_up.clear();
  147. for (int i = 0; i < m_center_x.size(); ++i) {
  148. int idx_low = int((m_center_x.at(i) - 0.5 * seedling_distance - m_xmin) / m_bin_step);
  149. int idx_up = int((m_center_x.at(i) + 0.5 * seedling_distance - m_xmin) / m_bin_step);
  150. m_idx_low.push_back(idx_low);
  151. m_idx_up.push_back(idx_up);
  152. }
  153. m_history_status = cv::Mat::zeros(m_max_size, m_center_x.size(), CV_8U);
  154. }
  155. void CSeedlingStatus::append_hist(
  156. std::vector<int>&xhist, //input
  157. std::vector<bool>&xstatus //output
  158. )
  159. {
  160. assert(xhist.size() == m_hist_length);
  161. m_global_cursor++;
  162. if (m_record_cursor < m_max_size-1) {
  163. m_record_cursor++;
  164. float pc_size = 0.0;
  165. for (int i = 0; i < xhist.size(); ++i) {
  166. if (i >= m_hist_length) { continue; }
  167. m_history_histogram.at<float>(m_record_cursor,i) = xhist.at(i);
  168. pc_size += xhist.at(i);
  169. }
  170. m_history_point_size.at<float>(m_record_cursor, 0) = pc_size;
  171. get_status(xstatus);
  172. }
  173. else {
  174. //数据上移一行,数据放在最后一行
  175. for (int row = 0; row < m_history_histogram.rows - 1; ++row) {
  176. for (int col = 0; col < m_history_histogram.cols; ++col) {
  177. m_history_histogram.at<float>(row, col) = m_history_histogram.at<float>(row + 1, col);
  178. }
  179. }
  180. for (int row = 0; row < m_history_point_size.rows - 1; ++row) {
  181. m_history_point_size.at<float>(row, 0) = m_history_point_size.at<float>(row+1, 0);
  182. }
  183. /*memcpy_s(m_history_histogram.data,
  184. m_history_histogram.step[0] * (m_max_size - 1),
  185. m_history_histogram.data + m_history_histogram.step[0],
  186. m_history_histogram.step[0] * (m_max_size - 1));*/
  187. /*memcpy_s(m_history_point_size.data,
  188. m_history_point_size.step[0] * (m_max_size - 1),
  189. m_history_point_size.data + m_history_point_size.step[0],
  190. m_history_point_size.step[0] * (m_max_size - 1));*/
  191. float pc_size = 0.0;
  192. for (int i = 0; i < xhist.size(); ++i) {
  193. m_history_histogram.at<float>(m_history_histogram.rows - 1, i) = float(xhist.at(i));
  194. pc_size += xhist.at(i);
  195. }
  196. m_history_point_size.at<float>(m_history_point_size.rows - 1, 0) = pc_size;
  197. get_status(xstatus);
  198. }
  199. }
  200. void CSeedlingStatus::get_status(std::vector<bool>&xstatus)
  201. {
  202. xstatus.clear();
  203. xstatus.assign(m_center_x.size(), false);
  204. //1 如果没有记录输入,返回没有苗
  205. if (m_record_cursor < 0) { return; }
  206. //2 如果是第一次,没有参考,用自身的分布阈值判断是否有苗(可能不准确,但没有其他办法)
  207. //点云分布情况分析
  208. // 每个bin的数量阈值设定m_bin_step宽度,至少有10毫米的点云,才认为有苗
  209. float th_hist = m_bin_step * 10 / m_pc_mean_dist / m_pc_mean_dist;
  210. if (m_record_cursor == 0) {
  211. std::vector<bool> hist_status;
  212. hist_status.assign(m_hist_length, false);
  213. for (int i = 0; i < m_hist_length; ++i) {
  214. if (m_history_histogram.at<float>(m_record_cursor, i) > th_hist) {
  215. hist_status.at(i) = true;
  216. }
  217. }
  218. for (int i = 0; i < m_center_x.size(); ++i) {
  219. int idx_low = m_idx_low.at(i);
  220. int idx_up = m_idx_up.at(i);
  221. int valid_bin_cnt = 0;
  222. for (int k = idx_low; k < idx_up; ++k) {
  223. if (hist_status.at(k)) { valid_bin_cnt++; }
  224. }
  225. double valid_ratio = (double)valid_bin_cnt / (double)(idx_up - idx_low);
  226. xstatus.at(i) = valid_ratio > 0.5;
  227. }
  228. //update m_history_status
  229. for (int i = 0; i < m_history_status.cols; ++i) {
  230. m_history_status.at<unsigned char>(m_record_cursor, i) = xstatus.at(i);
  231. }
  232. return;
  233. }
  234. //3 2次或更多,通过前后2次差分析苗取走的情况
  235. //3.1 计算被取走的点云位置分布
  236. std::vector<float>hist_diff;
  237. hist_diff.assign(m_hist_length, 0.0);
  238. float sum_dn = 0.0;
  239. float sum_n = 0.0;
  240. float diff_cnt = 0.0;
  241. for (int i = 0; i < m_hist_length; ++i) {
  242. diff_cnt = m_history_histogram.at<float>(m_record_cursor - 1, i) -
  243. m_history_histogram.at<float>(m_record_cursor, i);
  244. hist_diff.at(i) = diff_cnt;
  245. sum_n += diff_cnt;
  246. sum_dn += diff_cnt * i;
  247. }
  248. /*if (m_record_cursor < m_max_size) {
  249. for (int i = 0; i < m_hist_length; ++i) {
  250. diff_cnt = m_history_histogram.at<float>(m_record_cursor - 1, i) -
  251. m_history_histogram.at<float>(m_record_cursor, i);
  252. hist_diff.at(i) = diff_cnt;
  253. sum_n += diff_cnt;
  254. sum_dn += diff_cnt * i;
  255. }
  256. }
  257. else {
  258. for (int i = 0; i < m_hist_length; ++i) {
  259. diff_cnt = m_history_histogram.at<float>(m_max_size - 2, i) -
  260. m_history_histogram.at<float>(m_max_size - 1, i);
  261. hist_diff.at(i) = diff_cnt;
  262. sum_n += diff_cnt;
  263. sum_dn += diff_cnt * i;
  264. }
  265. }*/
  266. //3.2 统计增减点云的状态,区分点云增加,点云减小,点云没变化的部分
  267. std::vector<int> hist_status_2d; //3种状态记录: -1取走,0没变化,1上苗
  268. hist_status_2d.assign(m_hist_length, 0);
  269. int add_cnt = 0;
  270. int sub_cnt = 0;
  271. for (int i = 0; i < m_hist_length; ++i) {
  272. if (hist_diff.at(i) > th_hist) {
  273. hist_status_2d.at(i) = -1;
  274. sub_cnt += 1;
  275. }
  276. if (hist_diff.at(i) < -th_hist) {
  277. hist_status_2d.at(i) = 1;
  278. add_cnt += 1;
  279. }
  280. }
  281. //3.3 判断苗的整体情况
  282. double seedling_distance = m_center_x.at(1) - m_center_x.at(0); //株间距离
  283. double grid_one_seedling = seedling_distance / m_bin_step; //每穴位占histogram的桶数
  284. //3.3.1进一排苗
  285. if (add_cnt > grid_one_seedling*3.0) {
  286. xstatus.assign(m_center_x.size(), true);
  287. //update m_history_status
  288. if (m_record_cursor == m_global_cursor) {
  289. if (m_record_cursor < m_max_size) {
  290. for (int i = 0; i < m_history_status.cols; ++i) {
  291. m_history_status.at<unsigned char>(m_record_cursor, i) = xstatus.at(i);
  292. }
  293. }
  294. else {
  295. }
  296. }
  297. else {
  298. //数据上移一行,数据放在最后一行
  299. for (int row = 0; row < m_history_status.rows - 1; ++row) {
  300. for (int col = 0; col < m_history_status.cols; ++col) {
  301. m_history_status.at<float>(row, col) = m_history_status.at<float>(row + 1, col);
  302. }
  303. }
  304. /*memcpy_s(m_history_status.data,
  305. m_history_status.step[0] * (m_max_size - 1),
  306. m_history_status.data + m_history_status.step[0],
  307. m_history_status.step[0] * (m_max_size - 1));
  308. */
  309. for (int i = 0; i < m_history_status.cols; ++i) {
  310. m_history_status.at<unsigned char>(m_max_size-1, i) = xstatus.at(i);
  311. }
  312. }
  313. return;
  314. }
  315. std::vector<size_t>sorted_idx;
  316. std::vector<float>sub_seedling_score; //移出植株得分,记录每个穴位上点云变化得分
  317. //3.3.2 变化很小,说明没有改变(没能成功抓走)
  318. if (add_cnt + sub_cnt < 0.5 * grid_one_seedling) {
  319. goto no_change;
  320. }
  321. //3.3.3 否则的话,就是抓走过一个苗
  322. //找到被取走的苗的中心,然后根据dtype确定有苗的位置
  323. //找覆盖范围最大的区域
  324. double sub_cent_indx = sum_dn / sum_n; //计算改变范围的中心,目前没用到
  325. sub_seedling_score.assign(m_center_x.size(), 0.0);
  326. for (int idx = 0; idx < hist_status_2d.size(); ++idx) {
  327. if (hist_status_2d.at(idx) >= 0) {
  328. //这个histogram上没有移出,不统计, hist_status_2d的值域:-1取走,0没变化,1上苗
  329. continue;
  330. }
  331. for (int i = 0; i < m_center_x.size(); ++i) {
  332. int idx_low = m_idx_low.at(i);
  333. int idx_up = m_idx_up.at(i);
  334. if (idx >= idx_low && idx < idx_up) {
  335. sub_seedling_score.at(i) += 1.0;
  336. }
  337. }
  338. }
  339. int sub_pos = -1;
  340. sorted_idx = sort_indexes_e(sub_seedling_score, false);
  341. for (auto& idx : sorted_idx) {
  342. if (sub_seedling_score.at(idx) < 0.25 * grid_one_seedling) {
  343. //如果改变量,不到穴位范围的一半,不认为是移走的
  344. continue;
  345. }
  346. if (m_history_status.at<unsigned char>(m_record_cursor - 1, idx) == 0) {
  347. //如果这个位置上一帧就没有苗,那判别也是错误的
  348. continue;
  349. }
  350. sub_pos = idx;
  351. break;//找到得分最高,并且满足条件的位置,就是被抓走的位置,跳出
  352. }
  353. if (sub_pos >= 0) {
  354. xstatus.assign(m_center_x.size(), false);
  355. int cursor = m_record_cursor-1;
  356. for (int i = 0; i < m_history_status.cols; ++i) {
  357. if (m_history_status.at<unsigned char>(cursor, i) == 1) {
  358. xstatus.at(i) = true;
  359. }
  360. }
  361. xstatus.at(sub_pos) = false;
  362. //update m_history_status
  363. if (m_record_cursor == m_global_cursor) {
  364. for (int i = 0; i < m_history_status.cols; ++i) {
  365. m_history_status.at<unsigned char>(m_record_cursor, i) = xstatus.at(i);
  366. }
  367. }
  368. else{
  369. //数据上移一行,数据放在最后一行
  370. for (int row = 0; row < m_history_status.rows - 1; ++row) {
  371. for (int col = 0; col < m_history_status.cols; ++col) {
  372. m_history_status.at<float>(row, col) = m_history_status.at<float>(row + 1, col);
  373. }
  374. }
  375. /*memcpy_s(m_history_status.data,
  376. m_history_status.step[0] * (m_max_size - 1),
  377. m_history_status.data + m_history_status.step[0],
  378. m_history_status.step[0] * (m_max_size - 1));*/
  379. for (int i = 0; i < m_history_status.cols; ++i) {
  380. m_history_status.at<unsigned char>(m_max_size - 1, i) = xstatus.at(i);
  381. }
  382. }
  383. return;
  384. }
  385. else {
  386. //如果没有找到有效位置,按没有变化处理
  387. goto no_change;
  388. }
  389. no_change:
  390. //没有改变,用上一次的结果
  391. xstatus.assign(m_center_x.size(), true);
  392. //update m_history_status
  393. if (m_record_cursor == m_global_cursor) {
  394. for (int i = 0; i < m_history_status.cols; ++i) {
  395. m_history_status.at<unsigned char>(m_record_cursor, i) =
  396. m_history_status.at<unsigned char>(m_record_cursor - 1, i);
  397. if (m_history_status.at<unsigned char>(m_record_cursor - 1, i) == 0) {
  398. xstatus.at(i) = false;
  399. }
  400. }
  401. }
  402. else{
  403. //数据上移一行,数据放在最后一行
  404. for (int row = 0; row < m_history_status.rows - 1; ++row) {
  405. for (int col = 0; col < m_history_status.cols; ++col) {
  406. m_history_status.at<float>(row, col) = m_history_status.at<float>(row + 1, col);
  407. }
  408. }
  409. /*memcpy_s(m_history_status.data,
  410. m_history_status.step[0] * (m_max_size - 1),
  411. m_history_status.data + m_history_status.step[0],
  412. m_history_status.step[0] * (m_max_size - 1));*/
  413. for (int i = 0; i < m_history_status.cols; ++i) {
  414. m_history_status.at<unsigned char>(m_max_size - 1, i) =
  415. m_history_status.at<unsigned char>(m_max_size - 2, i);
  416. if (m_history_status.at<unsigned char>(m_max_size - 2, i) == 0) {
  417. xstatus.at(i) = false;
  418. }
  419. }
  420. }
  421. }
  422. }