将 OpenCV cv::kmeans() 与一维输入一起使用
Posted
技术标签:
【中文标题】将 OpenCV cv::kmeans() 与一维输入一起使用【英文标题】:Using OpenCV cv::kmeans() with one-dimensional input 【发布时间】:2014-09-24 12:26:26 【问题描述】:虽然python tutorial 使用一维数据,但我不能对 C++ 接口做同样的事情:
int size=100;
std::vector<float> data(size);
for (size_t i = 0; i < size ; i++)
data[i] = (float)i; //placeholder
std::vector<int> labels;
std::vector<float> centers;
cv::kmeans(data, 3, labels,
cv::TermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 10, 0.1),
3, cv::KMEANS_PP_CENTERS, centers);
由于 cv::kmeans 期望输入是二维的,因此内部断言失败。 CV_Assert(N>=K)
失败,因为 K 为 3,N 为 1。我的错误是什么?
【问题讨论】:
什么是“优势”?此外,N 是行向量的输入 Mat 中的元素数。我只是猜测,但你可能弄错了形状。 strengths.reshape(1,1) 应该使它成为一个 n-elem,1 行输入 将其重命名为“数据”。输入是一个 std::vector (通常应该没问题,因为 OpenCV 内部知道如何处理向量作为输入)。但它将其转换为具有一个通道的 (1 x data.size() ) 矩阵。这会导致异常,因为 kmeans 不包含 2 通道输入。 为什么不使用 Mat 数据而不是矢量问题在于,当您将向量传递给采用 InputArray 的对象时,当在该 InputArray 上调用 getMat() 时,会创建一个具有 1 行的 Mat。但由于 Xocoatzin 在源代码中指出的原因,这在这种情况下不起作用。您显然无法重塑矢量,尽管有人建议这样做。如果您的输入是一个向量,并且您无法更改它,您需要将向量显式转换为 1 列 Mat,如下所示。
int size=100;
std::vector<float> data(size);
for (size_t i = 0; i < size ; i++)
data[i] = (float)i; //placeholder
cv::Mat data_mat(data.size(), 1, CV32FC1, &data[0]); // ** Make 1 column Mat from vector
std::vector<int> labels;
std::vector<float> centers;
cv::kmeans(data_mat, 3, labels, // ** Pass 1 column Mat from Mat to kmeans
cv::TermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 10, 0.1),
3, cv::KMEANS_PP_CENTERS, centers);
【讨论】:
最后,两个答案都指向同一个想法 :-) 我现在没有重新塑造我的数据,而是直接将我的数据存储在适当维度的矩阵中,并停止使用向量。【参考方案2】:编辑:
我刚刚检查了来源,上面写着:
//...
bool isrow = data.rows == 1 && data.channels() > 1; // MORE THAN ONE CHANNEL
int N = !isrow ? data.rows : data.cols;
//...
//...
CV_Assert( N >= K );
因此,如果您的数据位于一行中,则您的输入矩阵中需要有多个通道和多于K
的列。
快速解决方法:reshape 您的矩阵,然后再调用 kmeans
它不复制任何数据,只是改变矩阵的维度。所以如果你有:
[12345678] // mat 1 x 8
用 2 行重塑后:
[1234| // a mat 2 x 4
|5678]
你应该可以打电话给kmeans
。 (别忘了重塑回来)
【讨论】:
我将 fix 推送到 OpenCV 并合并到 3.1 版以上是关于将 OpenCV cv::kmeans() 与一维输入一起使用的主要内容,如果未能解决你的问题,请参考以下文章
Python,OpenCV中的K均值聚类——K-Means Cluster