У меня есть Qvector, содержащий пиксельные координаты изображения. Основной целью было бы сгруппировать эти пиксели по их расстоянию друг от друга и получить прямоугольник из этих групп пикселей. Каждый пиксель в векторе не близко друг к другу, и именно поэтому я хотел бы сгруппировать их.
Я использую openCv и Qt. Я хотел бы избежать blobDetector из OpenCV, который довольно медленный, и сделать это самостоятельно, если это возможно.
У кого-нибудь есть идеи, как с этим справиться?
РЕДАКТИРОВАТЬ:
Допустим, белые точки расположены по пикселям близко друг к другу. Основной целью было бы обнаружить, что эти пиксели расположены близко друг к другу и смогут получить прямоугольник этих пикселей. Это возможно ?
EDIT2:
После получения кластеров я попытался обвести ограничивающие прямоугольники вокруг этих кластеров с помощью следующего кода. Возможно, я не правильно использую эту функцию.
cv::partition(cvCoordsTable, testVector, Dist(eqludianThreshold));
std::vector<cv::Rect> rectTable;
for(int in = 0; in < testVector.size(); in++)
{
rectTable.push_back(cv::boundingRect(cvCoordsTable.at(in)));
}
Спасибо за помощь
Это проблема кластеризации в первую очередь. Поскольку вы не знаете количество кластеров (групп), вы должны использовать некоторый алгоритм, который не требует количества кластеров в качестве входных данных. Вы можете сделать простой резюме :: раздел который имеет следующую подпись в C ++:
int cv::partition(const vector<_Tp>& vec, vector<int>& labels, _EqPredicate predicate=_EqPredicate())
Пример использования:
std::vector<cv::Point> pixelCoordinatesTable,
std::vector<int> labelsTable;
double threshold= 5;//Max eqludian distance between one cluster points
cv::partition(pixelCoordinatesTable, labelsTable, [&threshold](auto const& l, auto const& r){
return cv::norm(l - r))<threshold;
});
Другим более зрелым вариантом будет использование реального алгоритма кластеризации, такого как DBSCAN. Какой алгоритм кластеризации на основе плотности. и вы можете найти C ++ реализация здесь.
После того, как вы получили кластеры (любым способом), просто примените cv::boundingRect
вокруг каждого cluster
чтобы получить rectangle
ты хочешь.
РЕДАКТИРОВАТЬ:
Чтобы решить проблему с прямоугольником:
auto cluster_count = cv::partition(cvCoordsTable, testVector, Dist(eqludianThreshold)); // gettting the number of clusters
std::vector<cv::Rect> rectTable;
rectTable.reserve(cluster_count);//Optimiaztion
for(int in = 0; in < cluster_count; in++){
std::vector<cv::Point> temp;
temp.reserve(testVector.size());
for(size_t i=0;i<testVector.size();++i){
if(testVector[i]==in){
temp.emplace_back(rectTable[i]);
}
}
rectTable.emplace_back(cv::boundingRect(temp));
}
Я уверен, что есть лучший и более быстрый способ, я просто объяснял идею, и вы можете оптимизировать ее, как можете.
@Humam Helfawi победил меня здесь, но в любом случае, если у вас есть список центральных точек, используйте cv :: partition для кластеризации (без присмотра):
struct Dist
{
double D;
Dist(double d) : D(d) {}
bool operator()(const Point &a, const Point &b)
{
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) < D;
}
};
vector<Point> centers; // e.g. from findContours -> boundingRect
vector<int> labels;
cv::partition(centers,labels,Dist(800));
cerr << Mat(labels).t() << endl;
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ]