Как обнаружить несколько объектов с OpenCV в C ++?

Я получил вдохновение от этого ответа Вот, который является Python реализация, но мне нужно C++, этот ответ работает очень хорошо, я подумал, что: detectAndCompute получить keypointsиспользовать kmeans сегментировать их на кластеры, затем для каждого кластера сделать matcher->knnMatch с каждым descriptors, а затем сделать другие вещи, такие как общий метод обнаружения одного. Основная проблема в том, как обеспечить descriptors для каждого кластера matcher->knnMatch процесс? Я думал, что мы должны установить значение другого keypoints соответствующий descriptor до 0 (бесполезно), я прав?
И у меня возникли проблемы при попытке:

  1. как оценить количество кластеров для kmeans?
  2. Почему можно создать массив Mat для кластеров, как это Mat descriptors_scene_clusters[3] = { Mat(descriptors_scene.rows, descriptors_scene.cols, CV_8U, Scalar(0)) };?

Очень ценю любую помощь, пожалуйста!


выход

#include <stdio.h>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/xfeatures2d.hpp>

using namespace cv;
using namespace cv::xfeatures2d;

#define MIN_MATCH_COUNT 10

int main()
{
Mat img_object = imread("./2.PNG", IMREAD_GRAYSCALE);
Mat img_scene = imread("./1.PNG", IMREAD_GRAYSCALE);

Ptr<ORB> detector = ORB::create();
std::vector<KeyPoint> keypoints_object, keypoints_scene;
Mat descriptors_object, descriptors_scene;
detector->detectAndCompute(img_object, cv::Mat(), keypoints_object, descriptors_object);
detector->detectAndCompute(img_scene, cv::Mat(), keypoints_scene, descriptors_scene);std::cout << descriptors_scene.row(0) << "\n";
std::cout << descriptors_scene.cols << "\n";std::vector<Point2f> keypoints_scene_points_;
for (int i=0; i<keypoints_scene.size(); i++) {
keypoints_scene_points_.push_back(keypoints_scene[i].pt);
}
Mat keypoints_scene_points(keypoints_scene_points_);

Mat labels;
int estimate_cluster_count = 3; // estimated ??????????
kmeans(keypoints_scene_points, estimate_cluster_count, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0), 3, KMEANS_RANDOM_CENTERS);

std::cout << "==================================111111\n";

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

std::cout << "==================================111111------\n";

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
}

std::cout << descriptors_scene_clusters[0] << "\n";
std::cout << "==================================22222222\n";
// return 0;

Mat img_matches = img_scene;
std::vector<DMatch> all_good_matches;
for (int i=0; i<estimate_cluster_count; i++) {
std::cout << "==================================33333\n";

Ptr<flann::IndexParams> indexParams = makePtr<flann::KDTreeIndexParams>(5);
Ptr<flann::SearchParams> searchParams = makePtr<flann::SearchParams>(50);
Ptr<FlannBasedMatcher> matcher = makePtr<FlannBasedMatcher>(indexParams, searchParams);
// BFMatcher matcher;
std::vector<std::vector<DMatch>> matches;

std::cout << "==================================444444\n";
matcher->knnMatch(descriptors_object, descriptors_scene_clusters[i], matches, 2);
std::cout << "==================================555555\n";
std::vector<DMatch> good_matches;

for (auto &match : matches) {
if (match[0].distance < 0.7 * match[1].distance) {
good_matches.push_back(match[0]);
}
}

all_good_matches.insert(all_good_matches.end(), good_matches.begin(), good_matches.end());

std::cout << "==================================66666\n";

if (good_matches.size() > MIN_MATCH_COUNT) {

//-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene;

for (auto &match : good_matches) {
//-- Get the keypoints from the good matches
obj.push_back(keypoints_object[match.queryIdx].pt);
scene.push_back(keypoints_scene[match.trainIdx].pt);
}

Mat H = findHomography(obj, scene, RANSAC);

//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0, 0);
obj_corners[1] = cvPoint(img_object.cols, 0);
obj_corners[2] = cvPoint(img_object.cols, img_object.rows);
obj_corners[3] = cvPoint(0, img_object.rows);
std::vector<Point2f> scene_corners(4);

perspectiveTransform(obj_corners, scene_corners, H);

//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line(img_matches, scene_corners[0] + Point2f(img_object.cols, 0),
scene_corners[1] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[1] + Point2f(img_object.cols, 0),
scene_corners[2] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[2] + Point2f(img_object.cols, 0),
scene_corners[3] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[3] + Point2f(img_object.cols, 0),
scene_corners[0] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 4);

print(scene_corners);
}
}

drawMatches(img_object, keypoints_object, img_scene, keypoints_scene,
all_good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);//-- Show detected matches
imshow("Good Matches & Object detection", img_matches);

waitKey(0);
return 0;
}

15

Решение

Я не знаю решения вашей проблемы, но следующее может помочь ответить на вопросы, которые вы задали.

В комментариях говорится, что вам может понадобиться реализация meanshift, который уже есть у opencv. Вот пример, Вот документация с учебником.

  1. clusterCount за kmeansколичество кластеров, которые вы хотите создать ссылка на сайт. Я не знаю, как оценить число, которое вы хотите создать, но я думаю, вы могли знать.

  2. Вы инициализируете 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
}

clusterIndex равен 2, и вы получаете доступ к неинициализированному элементу в массиве, что приводит к EXEC_BAD_ACCESS error,

Я надеюсь, что это поможет для дальнейшего расследования!

2

Другие решения

Вы можете использовать простой кластер для непосредственного вычисления кластеров, определения количества кластеров и / или инициализации центров кластеров для 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);
}

Реализация кластерного метода была упрощена настолько, что стало очевидно, как он работает. Его производительность можно улучшить, но я считаю, что это выходит за рамки вашего вопроса.

1

По вопросам рекламы [email protected]