gpt4 book ai didi

c++ - OpenCV 使用 k-means 对图像进行分色

转载 作者:IT老高 更新时间:2023-10-28 22:14:08 27 4
gpt4 key购买 nike

我想在 C++ 接口(interface)(cv 命名空间)中使用 k-means 和 OpenCV 对图像进行分色,结果很奇怪。我需要它来减少一些噪音。这是我的代码:

#include "cv.h"
#include "highgui.h"

using namespace cv;

int main() {
Mat imageBGR, imageHSV, planeH, planeS, planeV;

imageBGR = imread("fruits.jpg");
imshow("original", imageBGR);

cv::Mat labels, data;
cv::Mat centers(8, 1, CV_32FC1);
imageBGR.convertTo(data, CV_32F);

cv::kmeans(data, 8, labels,
cv::TermCriteria(CV_TERMCRIT_ITER, 10, 1.0),
3, cv::KMEANS_PP_CENTERS, &centers);
imshow("posterized hue", data);
data.convertTo(data, CV_32FC3);

waitKey();
return 0;
}

但我得到了一个奇怪的结果

Fruit

第一张图片:原图

第二张图片:在 k-means 之后。

有什么建议吗?


更新:正确的解决方案。也许有人可以帮助我优化代码?

#include "cv.h"
#include "highgui.h"

#include <iostream>

using namespace cv;
using namespace std;

int main() {
Mat src;

src = imread("fruits.jpg");
imshow("original", src);

blur(src, src, Size(15,15));
imshow("blurred", src);

Mat p = Mat::zeros(src.cols*src.rows, 5, CV_32F);
Mat bestLabels, centers, clustered;
vector<Mat> bgr;
cv::split(src, bgr);
// i think there is a better way to split pixel bgr color
for(int i=0; i<src.cols*src.rows; i++) {
p.at<float>(i,0) = (i/src.cols) / src.rows;
p.at<float>(i,1) = (i%src.cols) / src.cols;
p.at<float>(i,2) = bgr[0].data[i] / 255.0;
p.at<float>(i,3) = bgr[1].data[i] / 255.0;
p.at<float>(i,4) = bgr[2].data[i] / 255.0;
}

int K = 8;
cv::kmeans(p, K, bestLabels,
TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
3, KMEANS_PP_CENTERS, centers);

int colors[K];
for(int i=0; i<K; i++) {
colors[i] = 255/(i+1);
}
// i think there is a better way to do this mayebe some Mat::reshape?
clustered = Mat(src.rows, src.cols, CV_32F);
for(int i=0; i<src.cols*src.rows; i++) {
clustered.at<float>(i/src.cols, i%src.cols) = (float)(colors[bestLabels.at<int>(0,i)]);
// cout << bestLabels.at<int>(0,i) << " " <<
// colors[bestLabels.at<int>(0,i)] << " " <<
// clustered.at<float>(i/src.cols, i%src.cols) << " " <<
// endl;
}

clustered.convertTo(clustered, CV_8U);
imshow("clustered", clustered);

waitKey();
return 0;
}

结果:

Posterized Fruit

最佳答案

我不是 OpenCV 方面的专家,所以我会给出一个与您的问题相关的一般性建议 K-means 采用本质上是一个矩阵的 vector 列表:

[x0, y0, r0, g0, b0]
[x1, y1, r1, g1, b1]
[x2, y2, r2, g2, b2]
.
.
.

你给它的图像是行不通的。您首先必须将图像转换为这种 k-means 矩阵格式。对于源图像的每个像素,您在结果矩阵中有一行。另请注意,您应该缩放这些值,以使它们都具有相似的值。如果不这样做,x 和 y 坐标通常会比颜色具有更高的“重力”,从而导致结果不理想。 C++伪代码:

int pixel_index = 0;
for (int y = 0; y < image height; y++) {
for (int x = 0; x < image width; x++) {
matrix[pixel_index][0] = (float)x / image width;
matrix[pixel_index][1] = (float)y / image height;
matrix[pixel_index][2] = (float)pixel(x, y).r / 255.0f;
matrix[pixel_index][3] = (float)pixel(x, y).g / 255.0f;
matrix[pixel_index][4] = (float)pixel(x, y).b / 255.0f;
}
}
// Pass the matrix to kmeans...

因此,您会获得每个像素的标签,这些标签对应于它被分配到的集群。然后,您需要确定集群的颜色 - 这可以从获取中心像素颜色值到计算集群的平均/中值颜色。确定颜色后,只需遍历图像并将像素设置为它们的集群颜色:

for (int y = 0; y < image height; y++)  {
for (int x = 0; x < image width; x++) {
int index = y * image width + x; // This corresponds to pixel_index above
int cluster_index = labels[index]; // 0 to 7 in your case
Color color = colors[cluster_index]; // Colors is an array of 8 colors of the clusters
image.setpixel(x, y, color)
}
}

如果您更喜欢使用 HSV 而不是 RGB,只需使用 HSV 值而不是 RGB 值。

OpenCV 有可能具有完全执行我上面描述的转换的函数,但我无法使用 Google 快速找到它们。

关于c++ - OpenCV 使用 k-means 对图像进行分色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9575652/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com