C++ 在c+中合并某些元素+;以最有效的方式提供矢量或类似的数据结构
如何通过只在完整列表上迭代一次来合并向量或类似数据结构中的某些元素?有没有比我现有的更有效的方法 我有一个点的向量:C++ 在c+中合并某些元素+;以最有效的方式提供矢量或类似的数据结构,c++,algorithm,opencv,c++11,C++,Algorithm,Opencv,C++11,如何通过只在完整列表上迭代一次来合并向量或类似数据结构中的某些元素?有没有比我现有的更有效的方法 我有一个点的向量:std::向量轮廓 我需要经常比较其中的两个,然后决定是合并还是继续比较 例如,轮廓矩有一些辅助函数来计算点之间的距离。函数merge()仅从一个轮廓力矩对象获取所有点,并将它们添加到调用轮廓力矩对象中 #include <iostream> #include <cmath> #include <ctime> #include <cstdl
std::向量轮廓
我需要经常比较其中的两个,然后决定是合并还是继续比较
例如,轮廓矩有一些辅助函数来计算点之间的距离。函数merge()
仅从一个轮廓力矩对象获取所有点,并将它们添加到调用轮廓力矩对象中
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <opencv/cv.h>
#include <opencv2/imgproc/imgproc.hpp>
class ContourMoments
{
private:
void init()
{
moments = cv::moments(contour);
center = cv::Point2f(moments.m10 / moments.m00, moments.m01 / moments.m00);
float totalX = 0.0, totalY = 0.0;
for (auto const&p : contour)
{
totalX += p.x;
totalY += p.y;
}
gravitationalCenter = cv::Point2f(totalX / contour.size(), totalY / contour.size());
}
public:
cv::Moments moments;
std::vector<cv::Point2f> contour;
cv::Point2f center;
cv::Point2f gravitationalCenter;
ContourMoments(const std::vector<cv::Point2f> &c)
{
contour = c;
init();
}
ContourMoments(const ContourMoments &cm)
{
contour = cm.contour;
init();
}
void merge(const ContourMoments &cm)
{
contour.insert(contour.end(), std::make_move_iterator(cm.contour.begin()), std::make_move_iterator(cm.contour.end()));
init();
}
float horizontalDistanceTo(const ContourMoments &cm)
{
return std::abs(center.x - cm.center.x);
}
float verticalDistanceTo(const ContourMoments &cm)
{
return std::abs(center.y - cm.center.y);
}
float centerDistanceTo(const ContourMoments &cm)
{
return std::sqrt(std::pow(center.x - cm.center.x, 2) + std::pow(center.y - cm.center.y, 2));
}
ContourMoments() = default;
~ContourMoments() = default;
};
float RandomFloat(float a, float b) {
float random = ((float) rand()) / (float) RAND_MAX;
float diff = b - a;
float r = random * diff;
return a + r;
}
std::vector<std::vector<cv::Point2f>> createData()
{
std::vector<std::vector<cv::Point2f>> cs;
for (int i = 0; i < 2000; ++i) {
std::vector<cv::Point2f> c;
int j_stop = rand()%11;
for (int j = 0; j < j_stop; ++j) {
c.push_back(cv::Point2f(RandomFloat(0.0, 20.0), RandomFloat(0.0, 20.0)));
}
cs.push_back(c);
}
return cs;
}
void printVectorOfVectorsOfPoints(const std::vector<std::vector<cv::Point2f>> &cs) {
std::cout << "####################################################" << std::endl;
for (const auto &el : cs) {
bool first = true;
for (const auto &pt : el) {
if (!first) {
std::cout << ", ";
}
first = false;
std::cout << "{x: " + std::to_string(pt.x) + ", y: " + std::to_string(pt.y) + "}";
}
std::cout << std::endl;
}
std::cout << "####################################################" << std::endl;
}
void merge(std::vector<std::vector<cv::Point2f>> &contours, int &counterMerged){
for(auto it = contours.begin() ; it < contours.end() ; /*++it*/)
{
int counter = 0;
if (it->size() < 5)
{
it = contours.erase(it);
continue;
}
for (auto it2 = it + 1; it2 < contours.end(); /*++it2*/)
{
if (it2->size() < 5)
{
it2 = contours.erase(it2);
continue;
}
ContourMoments cm1(*it);
ContourMoments cm2(*it2);
if (cm1.centerDistanceTo(cm2) > 4.0)
{
++counter;
++it2;
continue;
}
counterMerged++;
cm1.merge(std::move(cm2));
it2 = contours.erase(it2);
}
if (counter > 0)
{
std::advance(it, counter);
}
else
{
++it;
}
}
}
int main(int argc, const char * argv[])
{
srand(time(NULL));
std::vector<std::vector<cv::Point2f>> contours = createData();
printVectorOfVectorsOfPoints(contours);
int counterMerged = 0;
merge(contours, counterMerged);
printVectorOfVectorsOfPoints(contours);
std::cout << "Merged " << std::to_string(counterMerged) << " vectors." << std::endl;
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
类等值线矩
{
私人:
void init()
{
力矩=cv::力矩(轮廓);
中心=cv::点2F(矩.m10/矩.m00,矩.m01/矩.m00);
浮动总x=0.0,总y=0.0;
用于(自动const&p:等高线)
{
总x+=p.x;
总y+=p.y;
}
重力中心=cv::Point2f(totalX/contour.size(),totalY/contour.size());
}
公众:
cv::瞬间;
矢量轮廓;
cv::点2F中心;
cv::点2F重力中心;
轮廓矩(常数标准::矢量和c)
{
轮廓=c;
init();
}
轮廓矩(常数轮廓矩和厘米)
{
轮廓=厘米轮廓;
init();
}
空洞合并(常数和厘米)
{
insert(contour.end(),std::make_move_迭代器(cm.contour.begin()),std::make_move_迭代器(cm.contour.end());
init();
}
浮动水平距离(常数和厘米)
{
返回标准::abs(center.x-cm.center.x);
}
浮动垂直距离(常数和厘米)
{
返回标准::abs(center.y-cm.center.y);
}
浮动中心距(常数和厘米)
{
返回std::sqrt(std::pow(center.x-cm.center.x,2)+std::pow(center.y-cm.center.y,2));
}
轮廓矩()=默认值;
~ContourMoments()=默认值;
};
浮动随机浮动(浮动a、浮动b){
浮点随机=((浮点)rand())/(浮点)rand_MAX;
浮差=b-a;
浮动r=随机*差异;
返回a+r;
}
std::vector createData()
{
std::向量cs;
对于(int i=0;i<2000;++i){
std::向量c;
int j_stop=rand()%11;
对于(int j=0;j std::cout我没有仔细检查你的代码。如果你想做的是扫描向量,形成一组连续点,然后按顺序每个组发射一个点,例如
a b c|d e|f g h|i j k|l => a b c d f i l
最简单的方法是就地执行操作
在最后一个发射点后保留一个索引,让n
(最初为0
),每当发射一个新的点时,将其存储在数组[n++]
,覆盖此已处理的元素。最后,调整数组大小
人们可能会想到一种微优化,将n
与当前索引进行比较,并避免用自身覆盖某个元素。无论如何,一旦删除某个元素,测试就会适得其反。我没有仔细检查您的代码。如果您想做的是扫描向量,形成一组连续点并发出每组单点,按顺序,例如
a b c|d e|f g h|i j k|l => a b c d f i l
最简单的方法是就地执行操作
在最后一个发射点后保留一个索引,让n
(最初为0
),每当发射一个新的点时,将其存储在数组[n++]
,覆盖此已处理的元素。最后,调整数组大小
有人可能会想到一种微观优化,将n
与当前索引进行比较,并避免覆盖元素本身。无论如何,一旦元素被删除,测试就会适得其反。对于每个轮廓,您可以预计算中心。然后,您要做的是对轮廓进行聚类。每个中心相距不超过d
的等高线的ir应属于同一簇
这可以通过简单的radius查询完成。如下所示:
for each contour ci in all contours
for each contour cj with cluster center at most d away from ci
merge cluster ci and cj
对于半径查询,我建议使用a.将所有轮廓输入到树中,然后您可以在O(logn)
中查询邻居,而不是像您现在这样在O(n)
中查询邻居
对于合并部分,我建议使用。这样可以在几乎恒定的时间内进行合并。最后,您可以将所有轮廓数据收集到一个大的簇轮廓中。对于每个轮廓,您可以预先计算中心。然后,您要做的是对轮廓进行聚类。每对轮廓的中心最多为相距d
的距离应属于同一簇
这可以通过简单的radius查询完成。如下所示:
for each contour ci in all contours
for each contour cj with cluster center at most d away from ci
merge cluster ci and cj
对于半径查询,我建议使用a.将所有轮廓输入到树中,然后您可以在O(logn)
中查询邻居,而不是像您现在这样在O(n)
中查询邻居
对于合并部分,我建议使用a。这样可以在几乎恒定的时间内进行合并。最后,您可以将所有轮廓数据收集到一个大的簇轮廓中。您可以先根据中心距离对容器进行排序吗?我可以,但这意味着在向量上要进行大量迭代,我确实希望避免,因为出于性能原因。您可以使用lambda函数进行排序,正如@user6386155建议的那样,以加快排序速度。但这不只是隐藏了迭代吗?@i7clock只是一个关于效率的想法……为什么不比较sq