OpenCV中kmeans和cvKMeans2算法有什么区别?

我想找到图片上的主要N种颜色。为此我决定使用KMeans算法。我写在C上的项目,就是我用cvKMeans2算法。但它给了我很奇怪的结果。然后我决定在OpenCV C++上尝试kmeans算法。它给了我更准确的结果。那么,我的错在哪里?有人可以向我解释吗?OpenCV中kmeans和cvKMeans2算法有什么区别?

1.我用这张图片进行测试。

2. C.

#include <cv.h> 

#include <highgui.h>

#define CLUSTERS 3

int main(int argc, char **argv) {

const char *filename = "test_12.jpg";

IplImage *tmp = cvLoadImage(filename);

if (!tmp) {

return -1;

}

IplImage *src = cvCloneImage(tmp);

cvCvtColor(tmp, src, CV_BGR2RGB);

CvMat *samples = cvCreateMat(src->height * src->width, 3, CV_32F);

for (int i = 0; i < samples->height; i++) {

samples->data.fl[i * 3 + 0] = (uchar) src->imageData[i * 3 + 0];

samples->data.fl[i * 3 + 1] = (uchar) src->imageData[i * 3 + 1];

samples->data.fl[i * 3 + 2] = (uchar) src->imageData[i * 3 + 2];

}

CvMat *labels = cvCreateMat(samples->height, 1, CV_32SC1);

CvMat *centers = cvCreateMat(CLUSTERS, 3, CV_32FC1);

int flags = 0;

int attempts = 5;

cvKMeans2(samples, CLUSTERS, labels,

cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 10000, 0.005),

attempts, 0, flags, centers);

int rows = 40;

int cols = 300;

IplImage *des = cvCreateImage(cvSize(cols, rows), 8, 3);

int part = 4000;

int r = 0;

int u = 0;

for (int y = 0; y < 300; ++y) {

for (int x = 0; x < 40; ++x) {

if (u >= part) {

r++;

part = (r + 1) * part;

}

des->imageData[(300 * x + y) * 3 + 0] = static_cast<char>(centers->data.fl[r * 3 + 0]);

des->imageData[(300 * x + y) * 3 + 1] = static_cast<char>(centers->data.fl[r * 3 + 1]);

des->imageData[(300 * x + y) * 3 + 2] = static_cast<char>(centers->data.fl[r * 3 + 2]);

u++;

}

}

IplImage *dominant_colors = cvCloneImage(des);

cvCvtColor(des, dominant_colors, CV_BGR2RGB);

cvNamedWindow("dominant_colors", CV_WINDOW_AUTOSIZE);

cvShowImage("dominant_colors", dominant_colors);

cvWaitKey(0);

cvDestroyWindow("dominant_colors");

cvReleaseImage(&src);

cvReleaseImage(&des);

cvReleaseMat(&labels);

cvReleaseMat(&samples);

return 0;

}

3.第C实施实施++。

#include <cv.h> 

#include <opencv/cv.hpp>

#define CLUSTERS 3

int main(int argc, char **argv) {

const cv::Mat &tmp = cv::imread("test_12.jpg");

cv::Mat src;

cv::cvtColor(tmp, src, CV_BGR2RGB);

cv::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<cv::Vec3b>(y, x)[z];

int attempts = 5;

cv::Mat labels;

cv::Mat centers;

kmeans(samples, CLUSTERS, labels, cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 1000, 0.005),

attempts, cv::KMEANS_PP_CENTERS, centers);

cv::Mat colors(cv::Size(CLUSTERS * 100, 30), tmp.type());

int p = 100;

int cluster_id = 0;

for (int x = 0; x < CLUSTERS * 100; x++) {

for (int y = 0; y < 30; y++) {

if (x >= p) {

cluster_id++;

p = (cluster_id + 1) * 100;

}

colors.at<cv::Vec3b>(y, x)[0] = static_cast<uchar>(centers.at<float>(cluster_id, 0));

colors.at<cv::Vec3b>(y, x)[1] = static_cast<uchar>(centers.at<float>(cluster_id, 1));

colors.at<cv::Vec3b>(y, x)[2] = static_cast<uchar>(centers.at<float>(cluster_id, 2));

}

}

cv::Mat dominant_colors;

cv::cvtColor(colors, dominant_colors, CV_RGB2BGR);

cv::imshow("dominant_colors", dominant_colors);

cv::waitKey(0);

return 0;

}

4. C.

的代码结果

5.对C代码结果++。

回答:

我发现我错了。它与IplImage的widthStep字段相关。当我读here宽度步骤由于性能原因被填充到4的倍数。如果widthStep等于30,将填补高达32

int h = src->height; 

int w = src->width;

int c = 3;

int delta = 0;

for (int i = 0, y = 0; i < h; ++i) {

for (int j = 0; j < w; ++j) {

for (int k = 0; k < c; ++k, y++) {

samples->data.fl[i * w * c + c * j + k] = (uchar) src->imageData[delta + i * w * c + c * j + k];

}

}

delta += src->widthStep - src->width * src->nChannels;

}

随着指针

for (int x = 0, i = 0; x < src->height; ++x) { 

auto *ptr = (uchar *) (src->imageData + x * src->widthStep);

for (int y = 0; y < src->width; ++y, i++) {

for (int j = 0; j < 3; ++j) {

samples->data.fl[i * 3 + j] = ptr[3 * y + j];

}

}

}

以上是 OpenCV中kmeans和cvKMeans2算法有什么区别? 的全部内容, 来源链接: utcz.com/qa/263919.html

回到顶部