如何在C ++中使用OpenCV检测多个对象?

时间:2018-09-20 12:37:44

标签: c++ opencv k-means opencv3.0 mean-shift

这个答案herePython的实现,我从中得到了启发,但是我需要C++,这个答案非常有效,我想到的是:{{1 }}得到detectAndCompute,使用keypoints将它们分割成簇,然后对每个簇对每个kmeansmatcher->knnMatch,然后再做其他事情,例如常见的单次检测方法。主要问题是,如何为每个集群的descriptors进程提供descriptors?我认为我们应该将与matcher->knnMatch相对应的其他keypoints的值设置为0(无用),对吗? 在尝试时遇到了一些问题:

  1. 如何估算descriptor的群集数?
  2. 为什么可以为kmeans这样的集群创建Mat数组?

非常感谢您的帮助!


output

Mat descriptors_scene_clusters[3] = { Mat(descriptors_scene.rows, descriptors_scene.cols, CV_8U, Scalar(0)) };

2 个答案:

答案 0 :(得分:3)

我不知道您的问题的解决方案,但是以下内容可能有助于回答您提出的问题。

在评论中说,您可能需要opencv已经拥有的meanshift实现。 Here是示例,here文档带有教程。

  1. clusterCount的{​​{1}}是您要创建link的群集数。我不知道如何估算您要创建的数量,但我想您可能知道。

  2. 您只能使用一个元素来初始化kmeans

descriptors_scene_clusters

当您对其进行迭代时:

Mat descriptors_scene_clusters[3] = { Mat(descriptors_scene.rows, descriptors_scene.cols, CV_8U, Scalar(0)) };

for (int i=0; i<labels.rows; i++) { int clusterIndex = labels.at<int>(i); Point2f pt = keypoints_scene_points.at<Point2f>(i); descriptors_scene_clusters[clusterIndex].at<uchar>(pt) = descriptors_scene.at<uchar>(pt); // ?????? error } 为2,您访问数组中未初始化的元素,结果为clusterIndex

我希望这有助于进一步调查!

答案 1 :(得分:1)

您可以使用简单的群集器直接计算群集,查找群集数和/或对kmeans进行群集中心初始化。在此之下,可能是凝聚式群集器的实现,该群集器将靠近指定距离的点组合在一起-参见构造函数中的dist参数。在您的情况下,dist可能是小图像中关键点之间的最大距离。

头文件:

class PointsClusterer {
public:
     PointsClusterer (int dist, std::vector <cv::Point2f> points);
     bool cluster();
     std::map <int, std::vector <cv::Point2f>> getClusters ();

private:

    double distance (int i, int j);
    void merge (int i, int j);

private:

    std::vector <cv::Point2f> m_Points;
    std::map <int, std::vector <int>> m_Clusters;
    std::map <int, cv::Point2f> m_Sums;
    int m_dist = 0;
};

Cpp文件:

PointsClusterer::PointsClusterer (int dist, std::vector <cv::Point2f> points) :
m_dist(dist), m_Points (points)
{}

bool PointsClusterer::cluster()
{
//initialization
    for (int i = 0; i < m_Points.size(); ++i)
    {
        clusters[i] = std::vector<int>(1, i);
        sum_clusters[i] = m_Points[i];
    }

    bool still_merge = true;
    //Merge clusters
    while (still_merge)
    {
        still_merge = false;
        bool break_i = false;

        for (int i=0; i < m_Clusters.size () && !break_i ;++i)
        for (int j=i+1; j < m_Clusters.size ();++j)
        {
            if (distance(i, j) < m_dist)
            {
                merge(i, j);
                break_i = true;
                still_merge = true;
                break;
            }
        }
    }
//final conversion to std::map <int, std::vector <cv::Point2f>> is missing

}


void PointsClusterer::merge(int i, int j)
{
    auto it = m_Clusters.begin();
    auto iti = it+i;
    auto itj = it+j;

    for (val : itj->second)
    {
         iti->second.push_back(val);
         m_Sums[iti->first]+=m_Points[val];
    }
    m_Clusters.erase(itj);
}

double PointsClusterer::distance(int i, int j)
{
    auto it = m_Clusters.begin();
    auto iti = it + i;
    auto itj = it + j;
    auto vali = m_Sums[iti->first] / iti->second.size();
    auto valj = m_Sums[itj->first] / itj->second.size();
    return cv::norm(vali - valj);
}

群集方法的实现被过分简化,因此很明显它是如何工作的。它的性能可以提高,但是我认为这超出了您的问题范围。