这个问题是特定于OpenCV的:OpenCV的文档中给出的k均值例如具有2信道矩阵 - 为对特征矢量的各维度一个通道。 但是,某些其他示例似乎说,它应该与连同一列用于每个样品列特征的一个信道矩阵。 哪一个是正确的?
如果我有一个5维特征向量,应该是什么,我使用的输入矩阵:这一个:
cv::Mat inputSamples(numSamples, 1, CV32FC(numFeatures))
或这一个:
cv::Mat inputSamples(numSamples, numFeatures, CV_32F)
正确的答案是cv::Mat inputSamples(numSamples, numFeatures, CV_32F)
关于OpenCV的文档kmeans
说 :
样本 - 输入样本的浮点矩阵,每采样1行
因此,这不是n维浮标作为另一种选择浮点矢量。 其实例提出这样的行为?
这里也是由我一个小例子,显示k均值如何使用。 它簇的图像的像素并显示结果:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
int main( int argc, char** argv )
{
Mat src = imread( argv[1], 1 );
Mat samples(src.rows * src.cols, 3, CV_32F);
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
for( int z = 0; z < 3; z++)
samples.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y,x)[z];
int clusterCount = 15;
Mat labels;
int attempts = 5;
Mat centers;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );
Mat new_image( src.size(), src.type() );
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
{
int cluster_idx = labels.at<int>(y + x*src.rows,0);
new_image.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
new_image.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
new_image.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}
imshow( "clustered image", new_image );
waitKey( 0 );
}
作为替代手动重塑输入矩阵,可以使用的OpenCV 重塑函数来实现类似的结果用更少的代码。 这里是减少颜色的我的工作实现数与K-means方法(在Java中):
private final static int MAX_ITER = 10;
private final static int CLUSTERS = 16;
public static Mat colorMapKMeans(Mat img, int K, int maxIterations) {
Mat m = img.reshape(1, img.rows() * img.cols());
m.convertTo(m, CvType.CV_32F);
Mat bestLabels = new Mat(m.rows(), 1, CvType.CV_8U);
Mat centroids = new Mat(K, 1, CvType.CV_32F);
Core.kmeans(m, K, bestLabels,
new TermCriteria(TermCriteria.COUNT | TermCriteria.EPS, maxIterations, 1E-5),
1, Core.KMEANS_RANDOM_CENTERS, centroids);
List<Integer> idx = new ArrayList<>(m.rows());
Converters.Mat_to_vector_int(bestLabels, idx);
Mat imgMapped = new Mat(m.size(), m.type());
for(int i = 0; i < idx.size(); i++) {
Mat row = imgMapped.row(i);
centroids.row(idx.get(i)).copyTo(row);
}
return imgMapped.reshape(3, img.rows());
}
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Highgui.imwrite("result.png",
colorMapKMeans(Highgui.imread(args[0], Highgui.CV_LOAD_IMAGE_COLOR),
CLUSTERS, MAX_ITER));
}
OpenCV的读取图像到二维,3信道矩阵。 第一次调用reshape
- img.reshape(1, img.rows() * img.cols());
- 基本上解开3个通道成列。 在所得的矩阵的一行对应于输入图像的一个像素,和3列对应于RGB分量。
之后K-means算法完成其工作,并且颜色映射得到了应用,我们称之为reshape
再次- imgMapped.reshape(3, img.rows())
但现在滚动体列回通道,减少行数原始图像行数,从而取回原始矩阵格式,但只具有降低的色。