grab_occlusion.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  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::_update_root_centers() {
  93. // //依据m_infos中的数据,苗间距m_seedling_dist,聚类生成茎的平均位置,茎的点云平均数量
  94. // //更新m_root_centers
  95. // //以root_center为基础进行聚类,如果root_center是空的,因当前数据进行聚类
  96. // std::vector<CStemResult> root_centers;
  97. // double d1 = m_seedling_dist / 2.0;
  98. // double d2 = d1*1.75;
  99. // pcl::PointCloud<pcl::PointXYZ>::Ptr cloud2d_pos(new pcl::PointCloud < pcl::PointXYZ>);
  100. // for (auto&sr : m_infos) {
  101. // cloud2d_pos->points.push_back(pcl::PointXYZ((float)sr.root_x, 0.0, (float)sr.root_z));
  102. // }
  103. // cloud2d_pos->width = cloud2d_pos->points.size();
  104. // std::vector<pcl::PointXYZ>cluster_center;
  105. // std::vector<std::vector<int>> cluster_member;
  106. // euclidean_clustering_ttsas(cloud2d_pos, d1, d2, cluster_center, cluster_member);
  107. // for (size_t i = 0; i < cluster_center.size(); ++i) {
  108. // double x = (double)cluster_center.at(i).x;
  109. // double y = (double)cluster_center.at(i).y;
  110. // double z = (double)cluster_center.at(i).z;
  111. // int count = (int)cluster_member.at(i).size();
  112. // int pc_size = 0.0;
  113. // for (auto& idx : cluster_member.at(i)) {
  114. // pc_size += m_infos.at(idx).stem_size;
  115. // }
  116. // pc_size = (int)(pc_size / (float)count);
  117. // CStemResult sr = CStemResult(x, y, z, pc_size, std::string(""), count);
  118. // root_centers.push_back(sr);
  119. // }
  120. // if (m_root_centers.size() == 0) {
  121. // //如果没有历史数据,直接赋值
  122. // m_root_centers = root_centers;
  123. // }
  124. // else {
  125. // if (m_infos.size() > 50) {
  126. // //如果当前数据量较大,用当前的结果
  127. // m_root_centers = root_centers;
  128. // }
  129. // else {
  130. // //否则将当前结果合并到m_root_centers
  131. // //m_root_centers
  132. // for (auto& cent : root_centers) {
  133. // double dist_min = d2;
  134. // int min_root_idx = 0;
  135. // for (int j = 0; j < m_root_centers.size();++j) {
  136. // CStemResult& root = m_root_centers.at(j);
  137. // double dist = root.calcluate_distance(cent);
  138. // if (dist < dist_min) {
  139. // dist_min = dist;
  140. // min_root_idx = j;
  141. // }
  142. // }
  143. // if (dist_min < d1) {
  144. // //merge
  145. // double mu_x, mu_y,mu_z;
  146. // CStemResult& min_root = m_root_centers.at(min_root_idx);
  147. // mu_x = (min_root.root_x * min_root.root_count +
  148. // cent.root_x * cent.root_count) / (double)(min_root.root_count + cent.root_count);
  149. // mu_y = (min_root.root_y * min_root.root_count +
  150. // cent.root_y * cent.root_count) / (double)(min_root.root_count + cent.root_count);
  151. // mu_z = (min_root.root_z * min_root.root_count +
  152. // cent.root_z * cent.root_count) / (double)(min_root.root_count + cent.root_count);
  153. // min_root.root_x = mu_x;
  154. // min_root.root_y = mu_y;
  155. // min_root.root_z = mu_z;
  156. // min_root.root_count += cent.root_count;
  157. // }
  158. // else {
  159. // //add root
  160. // m_root_centers.push_back(cent);
  161. // }
  162. // }
  163. // }
  164. // }
  165. // //m_root_centers 排序、剔除
  166. // std::sort(m_root_centers.begin(), m_root_centers.end(),
  167. // [](const CStemResult& sr1, const CStemResult& sr2) {return sr1.root_x < sr2.root_x; });
  168. // //nms
  169. // _filter_root_centers(d1, d2);
  170. //}
  171. //void CStemResultInfos::_filter_root_centers(double d1, double d2)
  172. //{
  173. // //对生成的根中心m_root_centers进行过滤,剔除异常
  174. // //1 z值,通过中值,距离中值远的剔除
  175. // if (m_root_centers.size() > 3) {
  176. // std::vector<double>root_z;
  177. // for (auto&rc : m_root_centers) {
  178. // root_z.push_back(rc.root_z);
  179. // }
  180. // std::sort(root_z.begin(), root_z.end());
  181. // double mid_z = 0.0;
  182. // if (root_z.size() % 2 == 1) {
  183. // int idx = (m_root_centers.size() - 1) / 2;
  184. // mid_z = root_z.at(idx);
  185. // }
  186. // else {
  187. // int idx = root_z.size() / 2;
  188. // mid_z = 0.5 * (root_z.at(idx) + root_z.at(idx - 1));
  189. // }
  190. // std::vector<CStemResult> valid_root_centers;
  191. // for (auto&rc : m_root_centers) {
  192. // if (fabs(rc.root_z - mid_z) < d2) {
  193. // valid_root_centers.push_back(rc);
  194. // }
  195. // }
  196. // m_root_centers = valid_root_centers;
  197. // }
  198. // //2 按x做分组,排除权重小的
  199. // if (m_root_centers.size() > 3) {
  200. // std::vector<double> center_dist;
  201. // for (int i = 0; i < m_root_centers.size(); ++i) {
  202. // double x = m_root_centers.at(i).root_x;
  203. // double mod_sum = 0.0;
  204. // for (int j = 0; j < m_root_centers.size(); ++j) {
  205. // double dist = fabs(m_root_centers.at(j).root_x - x);
  206. // double mod = fmod(dist, m_seedling_dist);
  207. // double mod_inv = m_seedling_dist - mod;
  208. // mod = min(mod, mod_inv);
  209. // mod_sum += mod;
  210. // }
  211. // mod_sum /= (m_root_centers.size() - 1);
  212. // center_dist.push_back(mod_sum);
  213. // }
  214. // std::vector<CStemResult> valid_root_centers;
  215. // for (int i = 0; i < center_dist.size(); ++i) {
  216. // double dist = center_dist.at(i);
  217. // if (dist < d1) {
  218. // valid_root_centers.push_back(m_root_centers.at(i));
  219. // }
  220. // }
  221. // m_root_centers = valid_root_centers;
  222. // }
  223. // //3 数量少的剔除
  224. // int total_count = 0;
  225. // for (auto&rc : m_root_centers) {
  226. // total_count += rc.root_count;
  227. // }
  228. // if (total_count > 50) {
  229. // bool need_del = false;
  230. // for (auto& rc : m_root_centers) {
  231. // if (rc.root_count <= 2) {
  232. // need_del = true;
  233. // break;
  234. // }
  235. // }
  236. // if (need_del) {
  237. // std::vector<CStemResult> valid_root_centers;
  238. // for (int i = 0; i < m_root_centers.size(); ++i) {
  239. // if (m_root_centers.at(i).root_count > 2) {
  240. // valid_root_centers.push_back(m_root_centers.at(i));
  241. // }
  242. // }
  243. // m_root_centers = valid_root_centers;
  244. // }
  245. //
  246. // }
  247. //}
  248. void CStemResultInfos::gen_root_centers()
  249. {
  250. //根据 m_seedling_dist, m_holes_number, m_xmin, m_xmax生成初始的穴位中心
  251. //以m_xmin, m_xmax的中间点为中心,分别找到间隔m_seedling_dist的m_holes_number个穴位中心
  252. //初始的z设成-1,等待更新赋值
  253. double x_mid = 0.5 * (m_xmin + m_xmax);
  254. double holes_mid = 0.5 * (m_holes_number - 1) * m_seedling_dist;
  255. double x0 = x_mid - holes_mid;
  256. double z_mid = 0.5 * (m_zmin + m_zmax);
  257. m_root_centers.clear();
  258. for (int i=0; i<m_holes_number; ++i) {
  259. double x = x0 + i * m_seedling_dist;
  260. double y = 0;
  261. double z = z_mid;
  262. int size = 0;
  263. int count = 0;
  264. CStemResult sr = CStemResult(x, y, z, size, std::string(""), count);
  265. m_root_centers.push_back(sr);
  266. }
  267. }
  268. //void CStemResultInfos::set_json_filename(std::string& filename) {
  269. // m_json_filename = std::string(filename);
  270. //}
  271. //void CStemResultInfos::read_root_centers(
  272. // std::string& filename
  273. //)
  274. //{
  275. // //读取历史数据,每次启动时,去取
  276. // m_json_filename = std::string(filename);
  277. // //1 文件是否存在
  278. // ifstream f(filename.c_str());
  279. // if (!f.good()) {
  280. // //文件不存在
  281. // if (m_pLogger) {
  282. // stringstream buff;
  283. // buff << m_pcdId << ": json file not exists:" << filename;
  284. // m_pLogger->INFO(buff.str());
  285. // }
  286. // return;
  287. // }
  288. // cv::FileStorage fs(filename, cv::FileStorage::READ);
  289. // cv::FileNode root_centers = fs["root_centers"];
  290. // cv::FileNodeIterator it = root_centers.begin(), it_end = root_centers.end();
  291. // m_root_centers.clear();
  292. // for (; it != it_end; ++it) {
  293. // double x = (double)(*it)["x"];
  294. // double y = (double)(*it)["y"];
  295. // double z = (double)(*it)["z"];
  296. // int size = (int)(*it)["size"];
  297. // std::string bid = (std::string)(*it)["batch_id"];
  298. // int count = (int)(*it)["count"];
  299. // CStemResult sr = CStemResult(x,y,z,size, bid, count);
  300. // m_root_centers.push_back(sr);
  301. // }
  302. // fs.release();
  303. //}
  304. //void CStemResultInfos::write_root_centers(
  305. // std::string& filename
  306. //)
  307. //{
  308. // cv::FileStorage fs(filename, cv::FileStorage::WRITE);
  309. // fs << "root_centers" << "[";
  310. // for (auto& sr : m_root_centers) {
  311. // fs << "{" << "x" << sr.root_x
  312. // << "y" << sr.root_y
  313. // << "z" << sr.root_z
  314. // << "size" << sr.stem_size
  315. // << "batch_id" << sr.batch_id
  316. // << "count" << sr.root_count
  317. // << "}";
  318. // }
  319. // fs << "]";
  320. // fs.release();
  321. //}
  322. //void CStemResultInfos::euclidean_clustering_ttsas(
  323. // pcl::PointCloud<pcl::PointXYZ>::Ptr in_cloud,
  324. // double d1, double d2,
  325. // std::vector<pcl::PointXYZ>&cluster_center,
  326. // std::vector<std::vector<int>> &clustr_member
  327. //)
  328. //{
  329. // if (m_pLogger) {
  330. // stringstream buff;
  331. // buff << m_pcdId << ": root center estimate: euclidean_clustering_ttsas() begin...";
  332. // m_pLogger->INFO(buff.str());
  333. // }
  334. // std::vector<int> cluster_weight;
  335. // std::vector<int> data_stat;
  336. // std::vector<pcl::PointXYZ>cluster_center_raw;
  337. // std::vector<std::vector<int>> clustr_member_raw;
  338. // for (size_t i = 0; i < in_cloud->points.size(); ++i) { data_stat.push_back(0); }
  339. // size_t data_len = in_cloud->points.size();
  340. // int exists_change = 0;
  341. // int prev_change = 0;
  342. // int cur_change = 0;
  343. // int m = 0;
  344. // while (std::find(data_stat.begin(), data_stat.end(), 0) != data_stat.end()) {
  345. // bool new_while_first = true;
  346. // for (size_t i = 0; i < data_len; ++i) {
  347. // if (data_stat.at(i) == 0 && new_while_first && exists_change == 0) {
  348. // new_while_first = false;
  349. // std::vector<int> idx;
  350. // idx.push_back(i);
  351. // clustr_member_raw.push_back(idx);
  352. // pcl::PointXYZ center;
  353. // center.x = in_cloud->points.at(i).x;
  354. // center.y = in_cloud->points.at(i).y;
  355. // center.z = in_cloud->points.at(i).z;
  356. // cluster_center_raw.push_back(center);
  357. // data_stat.at(i) = 1;
  358. // cur_change += 1;
  359. // cluster_weight.push_back(1);
  360. // m += 1;
  361. // }
  362. // else if (data_stat[i] == 0) {
  363. // std::vector<float> distances;
  364. // for (size_t j = 0; j < clustr_member_raw.size(); ++j) {
  365. // std::vector<float> distances_sub;
  366. // for (size_t jj = 0; jj < clustr_member_raw.at(j).size(); ++jj) {
  367. // size_t ele_idx = clustr_member_raw.at(j).at(jj);
  368. // double d = sqrt(
  369. // (in_cloud->points.at(i).x - in_cloud->points.at(ele_idx).x) * (in_cloud->points.at(i).x - in_cloud->points.at(ele_idx).x) +
  370. // (in_cloud->points.at(i).y - in_cloud->points.at(ele_idx).y) * (in_cloud->points.at(i).y - in_cloud->points.at(ele_idx).y) +
  371. // (in_cloud->points.at(i).z - in_cloud->points.at(ele_idx).z) * (in_cloud->points.at(i).z - in_cloud->points.at(ele_idx).z));
  372. // distances_sub.push_back(d);
  373. // }
  374. // double min_dist = *std::min_element(distances_sub.begin(), distances_sub.end());
  375. // distances.push_back(min_dist);
  376. // }
  377. // int min_idx = std::min_element(distances.begin(), distances.end()) - distances.begin();
  378. // if (distances.at(min_idx) < d1) {
  379. // data_stat.at(i) = 1;
  380. // double w = cluster_weight.at(min_idx);
  381. // cluster_weight.at(min_idx) += 1;
  382. // clustr_member_raw.at(min_idx).push_back(i);
  383. // cluster_center_raw.at(min_idx).x = (cluster_center_raw.at(min_idx).x * w + in_cloud->points.at(i).x) / (w + 1);
  384. // cluster_center_raw.at(min_idx).y = (cluster_center_raw.at(min_idx).y * w + in_cloud->points.at(i).y) / (w + 1);
  385. // cluster_center_raw.at(min_idx).z = (cluster_center_raw.at(min_idx).z * w + in_cloud->points.at(i).z) / (w + 1);
  386. // cur_change += 1;
  387. // }
  388. // else if (distances.at(min_idx) > d2) {
  389. // std::vector<int> idx;
  390. // idx.push_back(i);
  391. // clustr_member_raw.push_back(idx);
  392. // pcl::PointXYZ center;
  393. // center.x = in_cloud->points.at(i).x;
  394. // center.y = in_cloud->points.at(i).y;
  395. // center.z = in_cloud->points.at(i).z;
  396. // cluster_center_raw.push_back(center);
  397. // data_stat.at(i) = 1;
  398. // cur_change += 1;
  399. // cluster_weight.push_back(1);
  400. // m += 1;
  401. // }
  402. // }
  403. // else if (data_stat.at(i) == 1) {
  404. // cur_change += 1;
  405. // }
  406. // }
  407. // exists_change = fabs(cur_change - prev_change);
  408. // prev_change = cur_change;
  409. // cur_change = 0;
  410. // }
  411. // // copy result
  412. // for (size_t i = 0; i < clustr_member_raw.size(); ++i) {
  413. // //if (clustr_member_raw.at(i).size() < 20) { continue; }
  414. // cluster_center.push_back(cluster_center_raw.at(i));
  415. // clustr_member.push_back(clustr_member_raw.at(i));
  416. // }
  417. // if (m_pLogger) {
  418. // stringstream buff;
  419. // buff << m_pcdId << ": root center estimate: euclidean_clustering_ttsas() end";
  420. // m_pLogger->INFO(buff.str());
  421. // }
  422. //}
  423. CSeedlingStatus::CSeedlingStatus(
  424. int dtype,
  425. double step,
  426. double x_min,
  427. double x_max,
  428. double pc_mean_dist,
  429. CGcvLogger*pLog)
  430. : m_pLogger(pLog)
  431. , m_dtype(dtype)
  432. , m_bin_step(step)
  433. , m_xmin(x_min)
  434. , m_xmax(x_max)
  435. , m_record_cursor(-1)
  436. , m_max_size(50)
  437. , m_pc_mean_dist(pc_mean_dist)
  438. {
  439. int x0 = int(x_min);
  440. int x1 = int(x_max);
  441. m_hist_length = int((x1 - x0) / step);
  442. m_history_histogram = cv::Mat::zeros(m_max_size, m_hist_length, CV_32F);
  443. m_history_point_size = cv::Mat::zeros(m_max_size, 1, CV_32F);
  444. }
  445. CSeedlingStatus::~CSeedlingStatus()
  446. {}
  447. void CSeedlingStatus::set_x_centers(std::vector<double>&cx)
  448. {
  449. m_center_x.clear();
  450. for (auto&x : cx) {
  451. m_center_x.push_back(x);
  452. }
  453. std::sort(m_center_x.begin(), m_center_x.end());
  454. double seedling_distance = m_center_x.at(1) - m_center_x.at(0);
  455. m_idx_low.clear();
  456. m_idx_up.clear();
  457. for (int i = 0; i < m_center_x.size(); ++i) {
  458. int idx_low = int((m_center_x.at(i) - 0.5 * seedling_distance - m_xmin) / m_bin_step);
  459. int idx_up = int((m_center_x.at(i) + 0.5 * seedling_distance - m_xmin) / m_bin_step);
  460. m_idx_low.push_back(idx_low);
  461. m_idx_up.push_back(idx_up);
  462. }
  463. m_history_status = cv::Mat::zeros(m_max_size, m_center_x.size(), CV_8U);
  464. }
  465. void CSeedlingStatus::append_hist(
  466. std::vector<int>&xhist, //input
  467. std::vector<bool>&xstatus //output
  468. )
  469. {
  470. assert(xhist.size() == m_hist_length);
  471. if (m_record_cursor < m_max_size) {
  472. m_record_cursor++;
  473. float pc_size = 0.0;
  474. for (int i = 0; i < xhist.size(); ++i) {
  475. m_history_histogram.at<float>(m_record_cursor,i) = xhist.at(i);
  476. pc_size += xhist.at(i);
  477. }
  478. m_history_point_size.at<float>(m_record_cursor, 0) = pc_size;
  479. get_status(xstatus);
  480. }
  481. else {
  482. //数据上移一行,数据放在最后一行
  483. memcpy_s(m_history_histogram.data,
  484. m_history_histogram.step[0] * (m_max_size - 1),
  485. m_history_histogram.data + m_history_histogram.step[0],
  486. m_history_histogram.step[0] * (m_max_size - 1));
  487. memcpy_s(m_history_point_size.data,
  488. m_history_point_size.step[0] * (m_max_size - 1),
  489. m_history_point_size.data + m_history_point_size.step[0],
  490. m_history_point_size.step[0] * (m_max_size - 1));
  491. float pc_size = 0.0;
  492. for (int i = 0; i < xhist.size(); ++i) {
  493. m_history_histogram.at<float>(m_max_size - 1, i) = float(xhist.at(i));
  494. pc_size += xhist.at(i);
  495. }
  496. m_history_point_size.at<float>(m_max_size - 1, 0) = pc_size;
  497. get_status(xstatus);
  498. }
  499. }
  500. void CSeedlingStatus::get_status(std::vector<bool>&xstatus)
  501. {
  502. xstatus.clear();
  503. xstatus.assign(m_center_x.size(), false);
  504. //1 如果没有记录输入,返回没有苗
  505. if (m_record_cursor < 0) { return; }
  506. //2 如果是第一次,没有参考,用自身的分布阈值判断是否有苗(可能不准确,但没有其他办法)
  507. //点云分布情况分析
  508. // 每个bin的数量阈值设定m_bin_step宽度,至少有10毫米的点云,才认为有苗
  509. float th_hist = m_bin_step * 10 / m_pc_mean_dist / m_pc_mean_dist;
  510. if (m_record_cursor == 0) {
  511. std::vector<bool> hist_status;
  512. hist_status.assign(m_hist_length, false);
  513. for (int i = 0; i < m_hist_length; ++i) {
  514. if (m_history_histogram.at<float>(m_record_cursor, i) > th_hist) {
  515. hist_status.at(i) = true;
  516. }
  517. }
  518. for (int i = 0; i < m_center_x.size(); ++i) {
  519. int idx_low = m_idx_low.at(i);
  520. int idx_up = m_idx_up.at(i);
  521. int valid_bin_cnt = 0;
  522. for (int k = idx_low; k < idx_up; ++k) {
  523. if (hist_status.at(k)) { valid_bin_cnt++; }
  524. }
  525. double valid_ratio = (double)valid_bin_cnt / (double)(idx_up - idx_low);
  526. xstatus.at(i) = valid_ratio > 0.5;
  527. }
  528. //update m_history_status
  529. for (int i = 0; i < m_history_status.cols; ++i) {
  530. m_history_status.at<unsigned char>(m_record_cursor, i) = xstatus.at(i);
  531. }
  532. return;
  533. }
  534. //3 2次或更多,通过前后2次差分析苗取走的情况
  535. //3.1 计算被取走的点云位置分布
  536. std::vector<float>hist_diff;
  537. hist_diff.assign(m_hist_length, 0.0);
  538. float sum_dn = 0.0;
  539. float sum_n = 0.0;
  540. float diff_cnt = 0.0;
  541. if (m_record_cursor < m_max_size) {
  542. for (int i = 0; i < m_hist_length; ++i) {
  543. diff_cnt = m_history_histogram.at<float>(m_record_cursor - 1, i) -
  544. m_history_histogram.at<float>(m_record_cursor, i);
  545. hist_diff.at(i) = diff_cnt;
  546. sum_n += diff_cnt;
  547. sum_dn += diff_cnt * i;
  548. }
  549. }
  550. else {
  551. for (int i = 0; i < m_hist_length; ++i) {
  552. diff_cnt = m_history_histogram.at<float>(m_max_size - 2, i) -
  553. m_history_histogram.at<float>(m_max_size - 1, i);
  554. hist_diff.at(i) = diff_cnt;
  555. sum_n += diff_cnt;
  556. sum_dn += diff_cnt * i;
  557. }
  558. }
  559. //3.2 统计增减点云的状态,区分点云增加,点云减小,点云没变化的部分
  560. std::vector<int> hist_status_2d; //3种状态记录: -1取走,0没变化,1上苗
  561. hist_status_2d.assign(m_hist_length, 0);
  562. int add_cnt = 0;
  563. int sub_cnt = 0;
  564. for (int i = 0; i < m_hist_length; ++i) {
  565. if (hist_diff.at(i) > th_hist) {
  566. hist_status_2d.at(i) = -1;
  567. sub_cnt += 1;
  568. }
  569. if (hist_diff.at(i) < -th_hist) {
  570. hist_status_2d.at(i) = 1;
  571. add_cnt += 1;
  572. }
  573. }
  574. //3.3 判断苗的整体情况
  575. double seedling_distance = m_center_x.at(1) - m_center_x.at(0); //株间距离
  576. double grid_one_seedling = seedling_distance / m_bin_step; //没穴位占histogram的桶数
  577. //3.3.1进一排苗
  578. if (add_cnt > grid_one_seedling*3.0) {
  579. xstatus.assign(m_center_x.size(), true);
  580. //update m_history_status
  581. if (m_record_cursor < m_max_size) {
  582. for (int i = 0; i < m_history_status.cols; ++i) {
  583. m_history_status.at<unsigned char>(m_record_cursor, i) = xstatus.at(i);
  584. }
  585. }
  586. else {
  587. memcpy_s(m_history_status.data,
  588. m_history_status.step[0] * (m_max_size - 1),
  589. m_history_status.data + m_history_status.step[0],
  590. m_history_status.step[0] * (m_max_size - 1));
  591. for (int i = 0; i < m_history_status.cols; ++i) {
  592. m_history_status.at<unsigned char>(m_max_size-1, i) = xstatus.at(i);
  593. }
  594. }
  595. return;
  596. }
  597. std::vector<size_t>sorted_idx;
  598. std::vector<float>sub_seedling_score; //移出植株得分,记录每个穴位上点云变化得分
  599. //3.3.2 变化很小,说明没有改变(没能成功抓走)
  600. if (add_cnt + sub_cnt < 0.5 * grid_one_seedling) {
  601. goto no_change;
  602. }
  603. //3.3.3 否则的话,就是抓走过一个苗
  604. //找到被取走的苗的中心,然后根据dtype确定有苗的位置
  605. //找覆盖范围最大的区域
  606. double sub_cent_indx = sum_dn / sum_n; //计算改变范围的中心,目前没用到
  607. sub_seedling_score.assign(m_center_x.size(), 0.0);
  608. for (int idx = 0; idx < hist_status_2d.size(); ++idx) {
  609. if (hist_status_2d.at(idx) >= 0) {
  610. //这个histogram上没有移出,不统计, hist_status_2d的值域:-1取走,0没变化,1上苗
  611. continue;
  612. }
  613. for (int i = 0; i < m_center_x.size(); ++i) {
  614. int idx_low = m_idx_low.at(i);
  615. int idx_up = m_idx_up.at(i);
  616. if (idx >= idx_low && idx < idx_up) {
  617. sub_seedling_score.at(i) += 1.0;
  618. }
  619. }
  620. }
  621. int sub_pos = -1;
  622. sorted_idx = sort_indexes_e(sub_seedling_score, false);
  623. for (auto& idx : sorted_idx) {
  624. if (sub_seedling_score.at(idx) < 0.25 * grid_one_seedling) {
  625. //如果改变量,不到穴位范围的一半,不认为是移走的
  626. continue;
  627. }
  628. if (m_history_status.at<unsigned char>(m_record_cursor - 1, idx) == 0) {
  629. //如果这个位置上一帧就没有苗,那判别也是错误的
  630. continue;
  631. }
  632. sub_pos = idx;
  633. break;//找到得分最高,并且满足条件的位置,就是被抓走的位置,跳出
  634. }
  635. if (sub_pos >= 0) {
  636. xstatus.assign(m_center_x.size(), false);
  637. if (m_dtype == 0) {
  638. //穗苗
  639. for (int kk = 0; kk <sub_pos; ++kk) {
  640. xstatus.at(kk) = true;
  641. }
  642. }
  643. else {
  644. //砧木
  645. for (int kk = sub_pos + 1; kk < m_center_x.size(); ++kk) {
  646. xstatus.at(kk) = true;
  647. }
  648. }
  649. //update m_history_status
  650. if (m_record_cursor < m_max_size) {
  651. for (int i = 0; i < m_history_status.cols; ++i) {
  652. m_history_status.at<unsigned char>(m_record_cursor, i) = xstatus.at(i);
  653. }
  654. }
  655. else{
  656. memcpy_s(m_history_status.data,
  657. m_history_status.step[0] * (m_max_size - 1),
  658. m_history_status.data + m_history_status.step[0],
  659. m_history_status.step[0] * (m_max_size - 1));
  660. for (int i = 0; i < m_history_status.cols; ++i) {
  661. m_history_status.at<unsigned char>(m_max_size - 1, i) = xstatus.at(i);
  662. }
  663. }
  664. return;
  665. }
  666. else {
  667. //如果没有找到有效位置,按没有变化处理
  668. goto no_change;
  669. }
  670. no_change:
  671. //没有改变,用上一次的结果
  672. xstatus.assign(m_center_x.size(), true);
  673. //update m_history_status
  674. if (m_record_cursor < m_max_size) {
  675. for (int i = 0; i < m_history_status.cols; ++i) {
  676. m_history_status.at<unsigned char>(m_record_cursor, i) =
  677. m_history_status.at<unsigned char>(m_record_cursor - 1, i);
  678. if (m_history_status.at<unsigned char>(m_record_cursor - 1, i) == 0) {
  679. xstatus.at(i) = false;
  680. }
  681. }
  682. }
  683. else{
  684. memcpy_s(m_history_status.data,
  685. m_history_status.step[0] * (m_max_size - 1),
  686. m_history_status.data + m_history_status.step[0],
  687. m_history_status.step[0] * (m_max_size - 1));
  688. for (int i = 0; i < m_history_status.cols; ++i) {
  689. m_history_status.at<unsigned char>(m_max_size - 1, i) =
  690. m_history_status.at<unsigned char>(m_max_size - 2, i);
  691. if (m_history_status.at<unsigned char>(m_max_size - 2, i) == 0) {
  692. xstatus.at(i) = false;
  693. }
  694. }
  695. }
  696. }
  697. }