From 7fcf5aaaf1fd3af01feaf047d597cba69bc9a7c1 Mon Sep 17 00:00:00 2001 From: "zhou.xu" Date: Thu, 9 May 2024 14:06:59 +0800 Subject: [PATCH] FIX:upgrade cluster algorithm to remove duplicate labels jira: none Change-Id: I4d68d8cd8e080932c7c308bc8f69e27546ffe309 --- src/libslic3r/ObjColorUtils.hpp | 109 ++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/ObjColorUtils.hpp b/src/libslic3r/ObjColorUtils.hpp index 4fe924fab..ea4418adf 100644 --- a/src/libslic3r/ObjColorUtils.hpp +++ b/src/libslic3r/ObjColorUtils.hpp @@ -27,7 +27,8 @@ public: cv::Mat image8UC3; convert_color_space(flatten_image8UC3, image8UC3, color_space); cv::Mat image32FC3(image8UC3.rows, 1, CV_32FC3); - for (int i = 0; i < image8UC3.rows; i++) image32FC3.at(i, 0) = image8UC3.at(i, 0); + for (int i = 0; i < image8UC3.rows; i++) + image32FC3.at(i, 0) = image8UC3.at(i, 0); apply(image32FC3, num_cluster, color_space); repalce_centers_aplha(ori_image, new_image); @@ -43,16 +44,25 @@ public: convert_color_space(this->m_centers8UC3, this->m_centers8UC3, color_space, true); } - void apply(const std::vector> &ori_colors, std::vector> & cluster_results, std::vector & labels, int num_cluster = -1, + int max_cluster = 15, int color_space = 2) { // 0~255 cv::Mat flatten_image8UC3 = flatten_vector(ori_colors); + this->apply(flatten_image8UC3, cluster_results, labels, num_cluster, max_cluster, color_space); + } + void apply(const cv::Mat & flatten_image8UC3, + std::vector> &cluster_results, + std::vector & labels, + int num_cluster = -1, + int max_cluster = 15, + int color_space = 2) + { cv::Mat image8UC3; convert_color_space(flatten_image8UC3, image8UC3, color_space); @@ -60,36 +70,44 @@ public: for (int i = 0; i < image8UC3.rows; i++) image32FC3.at(i, 0) = image8UC3.at(i, 0); - int best_cluster = 1; - double cur_score, best_score = 100; - int max_cluster = ori_colors.size(); - num_cluster = fmin(num_cluster, max_cluster); + int best_cluster = 1; + double cur_score = 0, best_score = 100; + num_cluster = fmin(num_cluster, max_cluster); if (num_cluster < 1) { - cur_score = kmeans(image32FC3, 1, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS); + if (!this->more_than_request(image8UC3, max_cluster)) max_cluster = compute_num_colors(image8UC3); + num_cluster = fmin(num_cluster, max_cluster); + cur_score = cv::kmeans(image32FC3, 1, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS); best_score = cur_score; - for (int cur_cluster = 2; cur_cluster < 16; cur_cluster++) { - if (cur_cluster > max_cluster) + + for (int cur_cluster = 2; cur_cluster < max_cluster + 1; cur_cluster++) { + cv::Mat centers32FC3; + cur_score = cv::kmeans(image32FC3, cur_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, + cv::KMEANS_PP_CENTERS, centers32FC3); + if (this->repeat_center(cur_cluster, centers32FC3, color_space)) break; - cur_score = kmeans(image32FC3, cur_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, - cv::KMEANS_PP_CENTERS); best_cluster = cur_score < best_score ? cur_cluster : best_cluster; best_score = cur_score < best_score ? cur_score : best_score; } - } else + } else if (this->more_than_request(image8UC3, num_cluster)) best_cluster = num_cluster; + else { + best_cluster = compute_num_colors(image8UC3); + std::cout << "num of image color is " << best_cluster << ", less than custom number " << num_cluster << std::endl; + } cv::Mat centers32FC3; - kmeans(image32FC3, best_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS, - centers32FC3); + cv::kmeans(image32FC3, best_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS, + centers32FC3); this->m_centers8UC3 = cv::Mat(best_cluster, 1, CV_8UC3); - for (int i = 0; i < best_cluster; i++) - this->m_centers8UC3.at(i) = centers32FC3.at(i); - + for (int i = 0; i < best_cluster; i++) { + auto center = centers32FC3.row(i); + this->m_centers8UC3.at(i) = {uchar(center.at(0)), uchar(center.at(1)), uchar(center.at(2))}; + } convert_color_space(this->m_centers8UC3, this->m_centers8UC3, color_space, true); cluster_results.clear(); labels.clear(); - for (int i = 0; i < ori_colors.size(); i++) + for (int i = 0; i < flatten_image8UC3.rows; i++) labels.emplace_back(this->m_flatten_labels.at(i, 0)); for (int i = 0; i < best_cluster; i++) { cv::Vec3f center = this->m_centers8UC3.at(i, 0); @@ -97,6 +115,59 @@ public: } } + bool more_than_request(const cv::Mat &image8UC3, int target_num) + { + std::vector uniqueImage; + cv::Vec3b cur_color; + for (int i = 0; i < image8UC3.rows; i++) { + cur_color = image8UC3.at(i, 0); + if (!is_in(cur_color, uniqueImage)) { + uniqueImage.emplace_back(cur_color); + if (uniqueImage.size() >= target_num) return true; + } + } + return false; + } + + int compute_num_colors(const cv::Mat &image8UC3) + { + std::vector uniqueImage; + cv::Vec3b cur_color; + for (int i = 0; i < image8UC3.rows; i++) { + cur_color = image8UC3.at(i, 0); + if (!is_in(cur_color, uniqueImage)) uniqueImage.emplace_back(cur_color); + } + + return uniqueImage.size(); + } + + bool is_in(const cv::Vec3b &cur_color, const std::vector &uniqueImage) + { + for (auto &color : uniqueImage) + if (cur_color[0] == color[0] && cur_color[1] == color[1] && cur_color[2] == color[2]) return true; + return false; + } + + bool repeat_center(int cur_cluster, const cv::Mat ¢ers32FC3, int color_space) + { + cv::Mat centers8UC3 = cv::Mat(cur_cluster, 1, CV_8UC3); + for (int i = 0; i < cur_cluster; i++) { + auto center = centers32FC3.row(i); + centers8UC3.at(i) = {uchar(center.at(0)), uchar(center.at(1)), uchar(center.at(2))}; + } + convert_color_space(centers8UC3, centers8UC3, color_space, true); + std::vector unique_centers; + cv::Vec3b cur_center; + for (int i = 0; i < cur_cluster; i++) { + cur_center = centers8UC3.at(i, 0); + if (!is_in(cur_center, unique_centers)) + unique_centers.emplace_back(cur_center); + else + return true; + } + return false; + } + void replace_centers(cv::Mat &ori_image, cv::Mat &new_image) { for (int i = 0; i < ori_image.rows; i++) { @@ -126,7 +197,7 @@ public: } } - void convert_color_space(cv::Mat &ori_image, cv::Mat &image, int color_space, bool reverse = false) + void convert_color_space(const cv::Mat &ori_image, cv::Mat &image, int color_space, bool reverse = false) { switch (color_space) { case 0: image = ori_image; break;