0
我想找到圖片上的主要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代碼結果++。
有沒有區別,它的代碼相同的底層位。有什麼不同的是你調用它們的參數 - TermCriteria和flags。最重要的是,C和C++實現之間還有其他幾個細微差別。 –
我認爲標準之間沒有顯着差異。所以我意識到我犯了錯誤。 IplImage有一個字段寬度步驟。它被填充到4的倍數。 –