c++ Kmeans图像压缩底层代码
时间: 2023-07-09 09:21:50 浏览: 118
以下是使用 C++ 底层实现 Kmeans 图像压缩的示例代码:
```c++
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// 计算两个像素点的欧几里得距离
float euclideanDistance(const Vec3b& a, const Vec3b& b)
{
float sum = 0.0;
for (int i = 0; i < 3; i++) {
float diff = a[i] - b[i];
sum += diff * diff;
}
return sqrt(sum);
}
int main()
{
// 读取原始图像
Mat img = imread("lena.jpg");
// 将图像转为一维数组
Mat samples = img.reshape(1, img.cols * img.rows);
// 设置 Kmeans 参数
int K = 16; // 分为 16 类
int max_iter = 10;
float epsilon = 1.0;
int attempts = 3;
// 随机初始化 K 个质心
vector<Vec3b> centers(K);
for (int i = 0; i < K; i++) {
centers[i] = samples.at<Vec3b>(rand() % samples.rows);
}
// 运行 Kmeans 算法
for (int iter = 0; iter < max_iter; iter++) {
// 计算每个像素点到质心的距离,并将其分配到距离最近的质心所在的类别
vector<vector<int>> clusters(K);
for (int i = 0; i < samples.rows; i++) {
float min_dist = FLT_MAX;
int min_idx = -1;
for (int j = 0; j < K; j++) {
float dist = euclideanDistance(samples.at<Vec3b>(i), centers[j]);
if (dist < min_dist) {
min_dist = dist;
min_idx = j;
}
}
clusters[min_idx].push_back(i);
}
// 更新质心的值为其所在类别的所有像素点的平均值
for (int j = 0; j < K; j++) {
Vec3f sum(0.0, 0.0, 0.0);
for (int i : clusters[j]) {
sum += samples.at<Vec3b>(i);
}
if (!clusters[j].empty()) {
centers[j] = sum / (float)clusters[j].size();
}
}
}
// 将每个像素点的值替换为其所属质心值
Mat new_img(img.size(), img.type());
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
float min_dist = FLT_MAX;
int min_idx = -1;
for (int k = 0; k < K; k++) {
float dist = euclideanDistance(img.at<Vec3b>(i, j), centers[k]);
if (dist < min_dist) {
min_dist = dist;
min_idx = k;
}
}
new_img.at<Vec3b>(i, j) = centers[min_idx];
}
}
// 显示压缩后的图像
imshow("compressed image", new_img);
waitKey(0);
return 0;
}
```
需要注意的是,由于使用了随机初始化,每次运行的结果可能不同。因此,为了得到更好的压缩效果,可以多次运行 Kmeans 算法,选择最优的结果。此外,为了提高计算效率,可以考虑使用并行计算或 GPU 加速。
阅读全文