opencv assertion_error ai_generated true

cv::error: (-215:Assertion failed) centers.cols == data.cols in function 'cv::kmeans'

ID: opencv/kmeans-initial-centers-mismatch

Also available as: JSON · Markdown · 中文
88%Fix Rate
84%Confidence
1Evidence
2023-03-10First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
opencv-4.5.5 active
opencv-4.8.0 active
opencv-4.9.0 active

Root Cause

When providing initial cluster centers to kmeans, the number of columns (features) in the centers matrix does not match the number of columns in the data matrix.

generic

中文

当向 kmeans 提供初始聚类中心时,中心矩阵的列数(特征数)与数据矩阵的列数不匹配。

Official Documentation

https://docs.opencv.org/4.x/d5/d38/group__core__cluster.html

Workarounds

  1. 90% success Ensure the centers matrix has the same number of columns as the data matrix. For example, if data is a 100x3 matrix (100 samples, 3 features), centers should be Kx3. Initialize centers as: cv::Mat centers(K, data.cols, CV_32FC1); for (int i = 0; i < K; i++) { data.row(rand() % data.rows).copyTo(centers.row(i)); } Then call kmeans(data, K, labels, criteria, attempts, KMEANS_USE_INITIAL_LABELS, centers);
    Ensure the centers matrix has the same number of columns as the data matrix. For example, if data is a 100x3 matrix (100 samples, 3 features), centers should be Kx3. Initialize centers as: cv::Mat centers(K, data.cols, CV_32FC1); for (int i = 0; i < K; i++) { data.row(rand() % data.rows).copyTo(centers.row(i)); } Then call kmeans(data, K, labels, criteria, attempts, KMEANS_USE_INITIAL_LABELS, centers);
  2. 80% success Convert data to CV_32F type if it is CV_64F: data.convertTo(data, CV_32F); and ensure centers is also CV_32F.
    Convert data to CV_32F type if it is CV_64F: data.convertTo(data, CV_32F); and ensure centers is also CV_32F.
  3. 95% success Use KMEANS_RANDOM_CENTERS flag instead of providing initial centers: kmeans(data, K, labels, criteria, attempts, KMEANS_RANDOM_CENTERS);
    Use KMEANS_RANDOM_CENTERS flag instead of providing initial centers: kmeans(data, K, labels, criteria, attempts, KMEANS_RANDOM_CENTERS);

中文步骤

  1. Ensure the centers matrix has the same number of columns as the data matrix. For example, if data is a 100x3 matrix (100 samples, 3 features), centers should be Kx3. Initialize centers as: cv::Mat centers(K, data.cols, CV_32FC1); for (int i = 0; i < K; i++) { data.row(rand() % data.rows).copyTo(centers.row(i)); } Then call kmeans(data, K, labels, criteria, attempts, KMEANS_USE_INITIAL_LABELS, centers);
  2. Convert data to CV_32F type if it is CV_64F: data.convertTo(data, CV_32F); and ensure centers is also CV_32F.
  3. Use KMEANS_RANDOM_CENTERS flag instead of providing initial centers: kmeans(data, K, labels, criteria, attempts, KMEANS_RANDOM_CENTERS);

Dead Ends

Common approaches that don't work:

  1. Transpose the data matrix using data.t() 85% fail

    kmeans expects data as rows of samples (each row is a sample). Transposing changes the shape incorrectly, leading to centers.cols != data.cols in a different way.

  2. Set the number of clusters K to a smaller value 95% fail

    The error is about feature dimension mismatch, not the number of clusters. Changing K doesn't affect the column count.

  3. Use cv::Mat::reshape to flatten the data to 1 column 90% fail

    Flattening to 1 column changes the feature space entirely, causing centers.cols (still original features) to mismatch.