形成三元组/四元组并删除重复项

问题描述 投票:0回答:2

我正在比较点的坐标。当坐标相似时,相关点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;
        }
    }


}
c++ opencv duplicates multimap std-pair
2个回答
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算法找到它的连接组件。

Implementing Union-Find

在这里,您可以找到基于索引的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;
    }
};

Finding connected components

诀窍是建立邻接矩阵(谁与谁连接),并在这样做时,如果两个元素连接合并他们的集合。展平操作只需将集合重新编号为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
投票

您需要为坐标创建一个好的索引。例如:

int64 ind = (((int64)cvRound(p.x)) << 32) | ((int64)cvRound(p.y));

并使用一个std :: map进行搜索重复。

© www.soinside.com 2019 - 2024. All rights reserved.