今天继续整理记录关于K-Means聚类算法的一个小应用,那就是对图像进行主色彩提取,从而建立属于图像的主色卡。关于K-Means算法的一些介绍,可以看我之前的博文《OpenCV4学习笔记(50)》。
有时候我们想要知道图像中有哪些主要色彩,尤其是在印刷、印制的时候,如果有针对模板图像的主色卡做参考,那么取色的时候能更加精准,避免色差。
利用K-Means聚类算法实现图像主色卡建立的步骤如下:
(1)先进行K-Means图像分割,可以参考《OpenCV4学习笔记(51)——基于K-Means聚类算法实现的图像分割》。
(2)然后计算每一种类别的像素点在整幅图像中所占的比率及其中心RGB值。
(3)根据每张类别颜色占整幅图像的比率来绘制每种主要色彩,从而建立图像的主色卡。
代码演示如下:
//读取图像并制作数据集
Mat test_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\opencv-logo.png");
resize(test_image, test_image, Size(600, 600));
int width = test_image.cols;
int height = test_image.rows;
int samplesNum = width * height;
Mat data = test_image.reshape(3, samplesNum);
data.convertTo(data, CV_32F);
//进行K-Means聚类
int K = 5;
Mat bestLabels, centers;
TermCriteria criteria = TermCriteria(TermCriteria::Type::COUNT + TermCriteria::Type::EPS, 10, 0.01);
kmeans(data, K, bestLabels, criteria, K, KMEANS_PP_CENTERS, centers);
//计算每一种类别像素点在图像中所占的比例
vector<float>color_radio(K);
for (int i = 0; i < samplesNum; i++)
{
color_radio[bestLabels.at<int>(i, 0)]++;
}
for (int j = 0; j < K; j++)
{
color_radio[j] = color_radio[j] / samplesNum;
}
//绘制图像的主色卡
Mat color_card = Mat::zeros(Size(width, 50), test_image.type());
int x = 0, y = 0;
for (int k = 0; k < K; k++)
{
int color_width = int(color_radio[k] * width);
int color_height = color_card.rows;
Rect color(x, y, color_width, color_height);
uchar b = uchar(centers.at<float>(k, 0));
uchar g = uchar(centers.at<float>(k, 1));
uchar r = uchar(centers.at<float>(k, 2));
color_card(color) = Scalar(b, g, r);
x += color_width;
cout << "色彩所占比例:" << color_radio[k] << endl;
}
//合并显示
Mat dst = Mat::zeros(Size(width, height + 50), test_image.type());
Rect c_card(0, 0, width, 50);
Mat roi_c_card = dst(c_card);
color_card.copyTo(roi_c_card);
Rect img(0, 50, width, height);
Mat roi_img = dst(img);
test_image.copyTo(roi_img);
imshow("dst", dst);
下面是对不同图像建立主色卡的效果:
下方显示的是输入图像,上方的小长方形就是提取出的主色卡了,包含了图像中的主要颜色及其大致占比,从控制台中也可以看到各种颜色所占的具体比例是多少。不过前提是,我们需要事先设定好要将图像分为几种颜色,也即是K个颜色分类,这是由于K-Means聚类算法的特性所决定的。
好了,本次笔记到此结束,谢谢阅读~
PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!