Использование OpenCV cv :: kmeans () с одномерным вводом

Хотя учебник по питону использует одномерные данные, я не могу сделать то же самое с интерфейсом 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. В чем моя ошибка?

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 затем. (Не забудьте изменить форму обратно)

3

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

Проблема в том, что когда вы передаете вектор чему-то, что принимает InputArray, когда getMat () вызывается для этого InputArray, создается Mat с 1 строкой. Но это не сработает в этом случае по причине, указанной Ксокоацин в источнике. Вы, очевидно, не можете изменить вектор, хотя это было предложено. Если ваш ввод является вектором, и вы не можете это изменить, вам нужно явно преобразовать вектор в Mat из 1 столбца, как показано ниже.

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);
4

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