Формируйте тройки / четверки целых чисел и удаляйте дубликаты - PullRequest
0 голосов
/ 20 марта 2019

Я сравниваю координаты точек.Когда координаты похожи, идентификаторы соответствующих точек (например, 102 и 202) сохраняются в многокарточной структуре.
Если другая точка имеет аналогичные координаты (например, идентификатор 302), я хочу сформировать тройной идентификатор точки (четверной ...) и так далее.У меня проблема в том, что ID 202 и 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;
        }
    }


}

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Хорошо, поскольку вы не ответили на мой второй комментарий, я пойду с ответом.Ваш вопрос был "Есть ли более разумный подход, который я использую?"и ответ «Да», потому что ваш код не выполняет задачу, которую он должен делать.

Вы хотите объединить элементы, которые попадают в квадрат со стороны 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)));

должны все попасть в один кластер.Учитывая ваш вывод, это не так.

Так что проблема здесь в том, что вы не можете повторно соединять наборы точек вместе.Это очень известная проблема, называемая структура данных с несвязным множеством , и фактически она используется для поиска связанных компонентов графа.

В вашем случае вы должны использовать первую часть вашего кода для создания граничной матрицы графа, а затем найти его связанные компоненты с помощью алгоритма union-find.

Реализация 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;
    }
};

Поиск подключенных компонентов

Хитрость заключается в построении матрицы смежности (кто с кем связан) и при этом, если два элементасвязаны слияния их наборов.Операция сглаживания просто перенумеровывает наборы от 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]);
    }
}

Вектор кластеров будет содержать векторы точек, соединенных вместе (в произвольном порядке).

0 голосов
/ 21 марта 2019

Вам нужно создать хороший индекс для координат.Например:

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

И использовать одну std :: map для поиска дубликатов.

...