/** 将最新的轮廓合并到已有的“活动区域中”,如果没有重叠,则新建“活动区域” */ void DetectWithOF5::merge_motions(const CONTOURS ®ions) { remove_timeout_motions(); /** 检查 regions 是否属于某个 motions ... */ std::set<size_t> merged_idxs; // regions 中,被合并的idx std::vector<size_t> exp_idxs; for (size_t i = 0; i < motions_.size(); i++) { /** 针对每个 motion,合并所有与最后位置相交的轮廓 */ Motion &m = motions_[i]; exp_idxs.clear(); // motion 仅仅保留最后 M 帧 if (m.history.size() > m.M) { m.history.pop_front(); // FIXME: 有可能 history 中剩下的都是“空”轮廓了,但一般情况下不会的 ... if (m.tracking_inited_) { m.tracking_pts.pop_front(); // FIXME: 保证 size() ... } m.dense_of_poss.pop_front(); m.dense_of_xs.pop_front(); m.dense_of_ys.pop_front(); m.frame_idx_ ++; } assert(!m.tracking_inited_ || m.history.size() == m.tracking_pts.size()); // 最后一个有效轮廓的外接圆 .. cv::Point2f c0; float r0; cv::minEnclosingCircle(m.last_contour, c0, r0); // 最后轮廓的外接圆 for (size_t j = 0; j < regions.size(); j++) { cv::Point2f c; float r; cv::minEnclosingCircle(regions[j], c, r); if (::is_cross(c0, r0, c, r)) { exp_idxs.push_back(j); merged_idxs.insert(j); } } /** FIXME: 如果需要扩展两个以上轮廓,而且两个轮廓距离还比较远,如何合并? 可能更好的方法是,根据历史运动的方向,选择其中某个轮廓,但 .... */ bool update = false; if (exp_idxs.size() == 1) { // 保存被合并的轮廓 .. m.last_contour = regions[exp_idxs[0]]; motions_[i].history.push_back(m.last_contour); motions_[i].stamp = curr_; update = true; } else if (exp_idxs.size() == 0) { // 此时说明 motion 没有活动 ??? motions_[i].history.push_back(CONTOUR()); // } else { // TODO: 应该根据历史轨迹方向,选择更有可能的一个 ... m.last_contour = regions[exp_idxs[0]]; motions_[i].history.push_back(m.last_contour); motions_[i].stamp = curr_; update = true; } if (update) { // 重新计算外界矩形 ... m.update_bounding_rc(); } if (m.dense_of_poss.size() > 0) { // 更新稠密光流 cv::Mat x, y; if (calc_dense_of(m.brc, x, y)) { m.dense_of_poss.push_back(m.brc); m.dense_of_xs.push_back(x); m.dense_of_ys.push_back(y); } } if (!m.tracking_inited_) { m.init_tracking(cc_); } } // 合并重叠的 motions merge_overlapped_motions(); // 创建新的 motions for (size_t i = 0; i < regions.size(); i++) { if (merged_idxs.find(i) == merged_idxs.end()) { // 所有未被合并的轮廓都应该创建为新的 motions ?? const CONTOUR &c = regions[i]; /** 使用不同颜色标识motion,方便调试 ... */ const cv::Scalar _colors[] = { cv::Scalar(0, 128, 0), cv::Scalar(0, 0, 128), cv::Scalar(0, 128, 128), cv::Scalar(0, 255, 128), cv::Scalar(0, 255, 0), cv::Scalar(128, 255, 0), cv::Scalar(128, 128, 0), cv::Scalar(255, 0, 0) }; const size_t _colors_cnt = sizeof(_colors) / sizeof(cv::Scalar); static int _mid = 0; Motion m; m.parent = this; m.discard_ = false; m.id = _mid++; m.M = motion_M_; m.history.push_back(c); m.last_contour = c; m.brc = cv::boundingRect(c); m.stamp = curr_; m.frame_idx_ = hist_.frame_idx_ + hist_.frames.size() - 1; // FIXME: 对应着历史中最后一帧图像 ... m.color = _colors[m.id % _colors_cnt]; m.tracking_inited_ = false; m.init_tracking(cc_); // 启用稠密光流 ... cv::Mat x, y; if (calc_dense_of(m.brc, x, y)) { m.dense_of_poss.push_back(m.brc); m.dense_of_xs.push_back(x); m.dense_of_ys.push_back(y); } motions_.push_back(m); } } }