使用OpenCV cv::kmeans()处理一维输入数据

3
尽管Python教程使用的是一维数据,但我不能在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。我的错误在哪里?


2
什么是“strengths”?此外,N是输入Mat的元素数量,用于行向量。我只是猜测,但你可能把形状搞错了。strengths.reshape(1,1)应该将其变成一个n个元素,1行输入。 - berak
将其重命名为"data"。输入是一个std::vector(通常应该没问题,因为OpenCV内部知道如何处理向量作为输入)。但它将其转换为一个(1 x data.size())矩阵,其中只有一个通道。这会导致异常,因为kmeans需要一个2通道的输入。 - PhilLab
2
为什么不使用Mat数据而是vector<float>? - berak
1
断言(N>=K)只是确保您至少拥有与要计算的簇数相同数量的样本。您的问题是将向量传递给kmeans而不是cv :: Mat会导致N的错误计算,正如@Xocoatzin在他的答案中所说。 - remi
“为什么不使用Mat?”:我发现向量更容易理解:当您在IDE中悬停在对象上时,您可以直接看到存储的内容。矩阵没有清晰的类型。通常,OpenCV可以处理向量。最终(如答案所建议的),我使用了矩阵。但我认为这是一个OpenCV的错误。 - PhilLab
2个回答

4
问题在于当您将一个向量传递给需要InputArray的函数时,该函数调用getMat()时会创建一个具有1行的Mat。但出于Xocoatzin在源代码中指出的原因,这在此情况下是行不通的。显然,您不能调整向量的形状,尽管有人建议过。如果您的输入是一个向量,并且您无法更改它,则需要明确地将向量转换为一列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);

最终,两个答案都指向了同一个想法 :-) 我现在不再重塑数据,而是直接将数据存储在适当维度的矩阵中,并停止使用向量。 - PhilLab

3

编辑:

我刚刚检查了源代码,它写着:

//...
bool isrow = data.rows == 1 && data.channels() > 1; // MORE THAN ONE CHANNEL
int N = !isrow ? data.rows : data.cols; 
//...

//...
CV_Assert( N >= K );

如果您的数据在单行中,那么您需要在输入矩阵中有多个通道并且比K更多的列。


一个快速解决方法:在调用kmeans之前重塑您的矩阵。

它不会复制任何数据,只是改变矩阵的维度。所以,如果您有:

[12345678] // mat 1 x 8

当您使用2行进行重新整形后:

[1234| // a mat 2 x 4
|5678]

你应该能够调用kmeans函数。(别忘了重新调整形状)

2
我向OpenCV提交了一个修复,并已合并到3.1版本。 - PhilLab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接