在opencv中聚类图像片段

我正在使用opencv进行非静态相机的运动检测。 我正在使用一个非常基本的背景减法和阈值处理方法来广泛了解所有在示例video中移动的内容。 在阈值处理之后,我将所有可分离的白色像素“补丁”存储起来,将它们存储为独立的组件并随机地用红色,绿色或蓝色着色。 下图显示了足球video,其中所有这些组件都是可见的。 移动细分

我在这些检测到的组件上创建了矩形,我得到了这个图像:

原始图像

所以我可以在这看到挑战。 我想将所有“相似”和附近组件聚类成一个单独的实体,以便输出图像中的矩形显示一个整体移动的玩家(而不是他的独立肢体)。 我尝试做K-means聚类,但理想情况下我不知道移动实体的数量,我无法取得任何进展。

请指导我如何做到这一点。 谢谢

这个问题几乎可以通过dbscan聚类算法完美解决。 下面,我提供实现和结果图像。 根据dbscan,灰色blob表示exception值或噪声。 我只是用盒子作为输入数据。 最初,箱中心用于距离function。 但是对于盒子来说,正确表征距离是不够的。 因此,当前距离函数使用两个框的所有8个角的最小距离。

#include "opencv2/opencv.hpp" using namespace cv; #include  #include  template  inline std::string to_string (const T& t) { std::stringstream ss; ss << t; return ss.str(); } class DbScan { public: std::map labels; vector& data; int C; double eps; int mnpts; double* dp; //memoization table in case of complex dist functions #define DP(i,j) dp[(data.size()*i)+j] DbScan(vector& _data,double _eps,int _mnpts):data(_data) { C=-1; for(int i=0;i neighbours = regionQuery(i); if(neighbours.size() neighbours) { labels[p]=C; for(int i=0;i neighbours_p = regionQuery(neighbours[i]); if (neighbours_p.size() >= mnpts) { expandCluster(neighbours[i],neighbours_p); } } } } bool isVisited(int i) { return labels[i]!=-99; } vector regionQuery(int p) { vector res; for(int i=0;i > getGroups() { vector > ret; for(int i=0;i<=C;i++) { ret.push_back(vector()); for(int j=0;j= 1.0f) fH = 0.0f; fH *= 6.0; // sector 0 to 5 fI = floor( fH ); // integer part of h (0,1,2,3,4,5 or 6) iI = (int) fH; // " " " " fF = fH - fI; // factorial part of h (0 to 1) p = fV * ( 1.0f - fS ); q = fV * ( 1.0f - fS * fF ); t = fV * ( 1.0f - fS * ( 1.0f - fF ) ); switch( iI ) { case 0: fR = fV; fG = t; fB = p; break; case 1: fR = q; fG = fV; fB = p; break; case 2: fR = p; fG = fV; fB = t; break; case 3: fR = p; fG = q; fB = fV; break; case 4: fR = t; fG = p; fB = fV; break; default: // case 5 (or 6): fR = fV; fG = p; fB = q; break; } } // Convert from doubles to 8-bit integers int bR = (int)(fR * double_TO_BYTE); int bG = (int)(fG * double_TO_BYTE); int bB = (int)(fB * double_TO_BYTE); // Clip the values to make sure it fits within the 8bits. if (bR > 255) bR = 255; if (bR < 0) bR = 0; if (bG >255) bG = 255; if (bG < 0) bG = 0; if (bB > 255) bB = 255; if (bB < 0) bB = 0; // Set the RGB cvScalar with GBR, you can use this values as you want too.. return cv::Scalar(bB,bG,bR); // R component } int main(int argc,char** argv ) { Mat im = imread("c:/data/football.png",0); std::vector > contours; std::vector hierarchy; findContours(im.clone(), contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); vector boxes; for(size_t i = 0; i < contours.size(); i++) { Rect r = boundingRect(contours[i]); boxes.push_back(r); } DbScan dbscan(boxes,20,2); dbscan.run(); //done, perform display Mat grouped = Mat::zeros(im.size(),CV_8UC3); vector colors; RNG rng(3); for(int i=0;i<=dbscan.C;i++) { colors.push_back(HSVtoRGBcvScalar(rng(255),255,255)); } for(int i=0;i 

结果

我同意Sebastian Schmitz:你可能不应该寻找聚类。

不要指望像k-means这样的不知情的方法为你工作。 尤其是像k-means一样粗略的启发式,并且它存在于理想化的数学世界中,而不是杂乱的实际数据。

你对自己想要的东西有很好的理解。 尝试将这种直觉放入代码中。 在您的情况下,您似乎在寻找连接组件。

考虑将图像下采样到较低分辨率,然后重新运行相同的过程! 或者立即在较低分辨率上运行它(以减少压缩失真,并提高性能)。 或者添加filter ,例如模糊。

通过查看下采样/滤波图像中的连通分量,我期望获得最佳和最快的结果。

我不确定你是否真的在寻找聚类(在数据挖掘意义上)。

聚类用于根据距离函数对相似对象进行分组。 在您的情况下,距离函数将仅使用空间质量。 此外,在k-means聚类中,你必须指定一个你可能事先不知道的ak。

在我看来,你只想合并所有边界比某个预定阈值更接近的矩形。 因此,作为第一个想法尝试合并所有触摸或比一半球员身高更接近的矩形。

您可能希望包含大小检查,以最大限度地降低将两个玩家合并为一个的风险。

编辑:如果您真的想使用聚类算法,请使用一个估算聚类数量的聚类算法。

我想你可以通过使用形态变换来改善你的原始尝试。 请查看http://docs.opencv.org/master/d9/d61/tutorial_py_morphological_ops.html#gsc.tab=0 。 在此之后,你可以为每个实体处理一个封闭的集合,特别是你原始图像中的独立玩家。