我正在比较点的坐标。当坐标相似时,相关的点ID(例如102和202)将保存在多图结构中。
如果另一个Point具有类似的坐标(例如ID 302),我想形成一个Point ID三元组(四倍...),依此类推。
我的问题是ID 202和ID 302也会形成一个已经在我的三元组中的对。所以我必须删除那对。我只想保留最大的顺序。
现在,我正在使用向量,多图和多图迭代器的组合,对于这样的“简单”操作而言,它似乎很庞大。
我正在使用一种更聪明的方法吗?
这是工作代码:
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <map>
int main(int argc, char** argv)
{
std::vector<std::pair<int, cv::Point2d>> matched_points;
matched_points.push_back(std::make_pair(100, cv::Point2d(260.103, 1335.96)));
matched_points.push_back(std::make_pair(101, cv::Point2d(238.017, 1313.15)));
matched_points.push_back(std::make_pair(102, cv::Point2d(112.052, 1338)));
matched_points.push_back(std::make_pair(103, cv::Point2d(326.396, 1301.1)));
matched_points.push_back(std::make_pair(104, cv::Point2d(328.225, 1302.48)));
matched_points.push_back(std::make_pair(105, cv::Point2d(259.943, 1386.1)));
matched_points.push_back(std::make_pair(106, cv::Point2d(1033.7, 1197.04)));
matched_points.push_back(std::make_pair(200, cv::Point2d(1430.65, 1304.55)));
matched_points.push_back(std::make_pair(201, cv::Point2d(1185.66, 1032.1)));
matched_points.push_back(std::make_pair(202, cv::Point2d(112.052, 1338)));
matched_points.push_back(std::make_pair(203, cv::Point2d(326.396, 1301.1)));
matched_points.push_back(std::make_pair(204, cv::Point2d(328.225, 1302.48)));
matched_points.push_back(std::make_pair(205, cv::Point2d(259.943, 1386.1)));
matched_points.push_back(std::make_pair(206, cv::Point2d(1033.7, 1197.04)));
matched_points.push_back(std::make_pair(300, cv::Point2d(1430.65, 1304.55)));
matched_points.push_back(std::make_pair(301, cv::Point2d(1185.66, 1032.1)));
matched_points.push_back(std::make_pair(302, cv::Point2d(112.052, 1338)));
matched_points.push_back(std::make_pair(303, cv::Point2d(326.396, 1301.1)));
matched_points.push_back(std::make_pair(304, cv::Point2d(328.225, 1302.48)));
matched_points.push_back(std::make_pair(305, cv::Point2d(259.943, 1386.1)));
matched_points.push_back(std::make_pair(306, cv::Point2d(1033.7, 1197.04)));
// Possibly adding more points (400s, 500s ...)
// Save integer numbers of matching points
std::multimap<int, int> matches_map;
for (size_t i = 0; i < matched_points.size(); ++i) {
for (size_t j = 0; j <matched_points.size(); ++j) {
if (j > i) {
if (abs(matched_points[i].second.x - matched_points[j].second.x) < 1 && (abs(matched_points[i].second.y - matched_points[j].second.y)) < 1) {
//std::cout << " True " << std::endl;
//std::cout << " Point 1:" << " ID: " << Cam_4.unmatched_img_points[i].first << " X: " << Cam_4.unmatched_img_points[i].second.x << " Y: " << Cam_4.unmatched_img_points[i].second.y << std::endl;
//std::cout << " Point 2:" << " ID: " << Cam_4.unmatched_img_points[j].first << " X: " << Cam_4.unmatched_img_points[j].second.x << " Y: " << Cam_4.unmatched_img_points[j].second.y << std::endl;
matches_map.insert(std::pair<int, int>(matched_points[i].first, matched_points[j].first));
}
}
}
}
// Eliminate similar pairs and form triples/quadruples/quintuples... if possible
std::vector<int> unique_keys;
for (std::multimap<int, int>::iterator multimap_iterator = matches_map.begin(), end = matches_map.end(); multimap_iterator != end; multimap_iterator = matches_map.upper_bound(multimap_iterator->first)) {
unique_keys.push_back(multimap_iterator->first);
}
typedef std::multimap<int, int>::iterator MMAPIterator;
std::vector<std::vector<int>> final_values;
std::vector<int> helper_vector;
for (size_t i = 0; i < unique_keys.size(); ++i) {
std::pair<MMAPIterator, MMAPIterator> result = matches_map.equal_range(unique_keys[i]);
helper_vector.push_back(unique_keys[i]);
for (MMAPIterator it = result.first; it != result.second; it++) {
//std::cout << it->second << std::endl;
helper_vector.push_back(it->second);
}
final_values.push_back(helper_vector);
helper_vector.clear();
}
std::vector<int> v1, v2;
for (size_t i = 0; i < final_values.size(); ++i) {
for (size_t j = 0; j < final_values.size(); ++j) {
if (j > i) {
v1 = final_values[i];
v2 = final_values[j];
if (std::includes(v1.begin(), v1.end(), v2.begin(), v2.end())) {
std::cout << "Erased position " << j << std::endl;
final_values.erase(final_values.begin() + j);
}
v1.clear();
v2.clear();
}
}
}
for (size_t i = 0; i < final_values.size(); ++i) {
std::cout << "Printing column " << i << std::endl;
for (size_t j = 0; j < final_values[i].size(); ++j) {
std::cout << final_values[i][j] << std::endl;
}
}
}
答案 0 :(得分:1)
好吧,由于您没有关注我的第二条评论,因此我将给出答案。您的问题是“我正在使用一种更聪明的方法吗?”答案是“是”,因为您的代码没有执行应执行的任务。
您要对位于边1的正方形中的元素进行聚类,然后注意以下几点:
matched_points.push_back(std::make_pair(100, cv::Point2d(0.0, 0.0 )));
matched_points.push_back(std::make_pair(101, cv::Point2d(0.0, 0.9 )));
matched_points.push_back(std::make_pair(102, cv::Point2d(0.0, 1.8 )));
matched_points.push_back(std::make_pair(103, cv::Point2d(0.0, 2.7 )));
matched_points.push_back(std::make_pair(104, cv::Point2d(0.0, 3.6 )));
matched_points.push_back(std::make_pair(105, cv::Point2d(0.0, 4.5 )));
matched_points.push_back(std::make_pair(106, cv::Point2d(0.0, 5.4 )));
matched_points.push_back(std::make_pair(200, cv::Point2d(0.0, 6.3)));
matched_points.push_back(std::make_pair(201, cv::Point2d(0.0, 7.2)));
matched_points.push_back(std::make_pair(202, cv::Point2d(0.0, 8.1)));
matched_points.push_back(std::make_pair(203, cv::Point2d(0.0, 9.0)));
matched_points.push_back(std::make_pair(204, cv::Point2d(0.0, 9.9)));
matched_points.push_back(std::make_pair(205, cv::Point2d(0.0, 10.8)));
matched_points.push_back(std::make_pair(206, cv::Point2d(0.0, 11.6)));
应全部归为一个集群。根据您的输出,事实并非如此。
因此,这里的问题是您无法将点集重复连接在一起。这是一个非常著名的问题,称为Disjoint-set data structure,实际上它用于查找图形的连接组件。
在这种情况下,您应该使用代码的第一部分来创建图形的边缘矩阵,然后使用联合查找算法找到其连接的组件。
在这里您可以找到基于索引的Union-Find数据结构的示例实现,该索引映射到向量中的点。不太聪明,但是应该可以。
// Union-find (UF)
struct UF {
std::vector<int> P_;
UF(size_t size) : P_(size) {
iota(begin(P_), end(P_), 0);
}
int operator[](int i) {
return P_[i];
}
void Merge(int i, int j) {
// FindRoot(i)
while (P_[i] < i) {
i = P_[i];
}
// FindRoot(j)
while (P_[j] < j) {
j = P_[j];
}
if (i < j)
P_[j] = i;
else
P_[i] = j;
}
int Flatten() {
int k = 0;
int size = P_.size();
for (int i = 0; i < size; ++i) {
if (P_[i] < i) {
P_[i] = P_[P_[i]];
}
else {
P_[i] = k;
k = k + 1;
}
}
return k;
}
};
诀窍是建立邻接矩阵(谁连接到谁),并且在这样做时,如果两个元素相连,则合并它们的集合。展平操作只需将集合从0重新编号为n-1,因此将元素重新映射到其簇更容易。
int main(int argc, char** argv)
{
using elem = std::pair<int, cv::Point2d>;
std::vector<elem> matched_points;
// fill the matched_points vector here
auto connected = [](const elem& a, const elem& b) {
return abs(a.second.x - b.second.x) < 1 && (abs(a.second.y - b.second.y)) < 1;
};
UF uf(matched_points.size());
for (size_t i = 0; i < matched_points.size() - 1; ++i) {
for (size_t j = i + 1; j < matched_points.size(); ++j) {
if (connected(matched_points[i], matched_points[j])) {
uf.Merge(i, j);
}
}
}
int ncc = uf.Flatten();
std::vector<std::vector<elem>> clusters(ncc);
for (size_t i = 0; i < matched_points.size(); ++i) {
clusters[uf[i]].push_back(matched_points[i]);
}
}
聚类向量将包含连接在一起的点的向量(无特定顺序)。
答案 1 :(得分:-1)
您需要为坐标创建一个良好的索引。例如:
int64 ind = (((int64)cvRound(p.x)) << 32) | ((int64)cvRound(p.y));
并使用一个std :: map搜索重复项。