Я делаю функцию с использованием C ++ и OpenCV, которая будет определять цвет пикселя на изображении, определять его цветовую гамму и заменять его на общий цвет. Например, зеленый может варьироваться от темно-зеленого до светло-зеленого, программа определит, что он все еще зеленый, и заменит его простым зеленым, что сделает выходное изображение очень простым. все настроено, но у меня возникают проблемы с определением характеристик каждого диапазона, и мне было любопытно, если кто-нибудь знает или формула, которая, учитывая значения BGR, может определить общий цвет пикселя. Если нет, мне придется много экспериментировать и делать это самому, но если что-то уже существует, это сэкономит время. Я провел много исследований и пока не нашел ничего.
Если вы хотите сделать свое изображение проще (то есть с меньшим количеством цветов), но хорошо выглядящий, у вас есть несколько вариантов:
Простой подход будет разделить (целочисленное деление) фактором N
изображение, а затем умножить на коэффициент N
,
Или вы можете разделить свое изображение на K
цвета, используя некоторый алгоритм кластеризации, такой как kmeans
показанный здесь, или алгоритм медианного разреза.
Исходное изображение:
Уменьшенные цвета (квантованные, N = 64
):
Уменьшенные цвета (кластеризованные, K = 8
):
Квантование кода:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
imshow("Original", img);
uchar N = 64;
img /= N;
img *= N;
imshow("Reduced", img);
waitKey();
return 0;
}
Код Kmeans:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
imshow("Original", img);
// Cluster
int K = 8;
int n = img.rows * img.cols;
Mat data = img.reshape(1, n);
data.convertTo(data, CV_32F);
vector<int> labels;
Mat1f colors;
kmeans(data, K, labels, cv::TermCriteria(), 1, cv::KMEANS_PP_CENTERS, colors);
for (int i = 0; i < n; ++i)
{
data.at<float>(i, 0) = colors(labels[i], 0);
data.at<float>(i, 1) = colors(labels[i], 1);
data.at<float>(i, 2) = colors(labels[i], 2);
}
Mat reduced = data.reshape(3, img.rows);
reduced.convertTo(reduced, CV_8U);imshow("Reduced", reduced);
waitKey();
return 0;
}
Да, то, что вы, вероятно, подразумеваете под «общим цветом пикселя», является «Оттенок» или «Насыщенность» цвета.
Поэтому вам нужна формула, которая преобразует RGB в HSV (оттенок, насыщенность, значение), и тогда вас будут интересовать только значения оттенка или насыщенности.
Увидеть: Алгоритм преобразования RGB в HSV и HSV в RGB в диапазоне 0-255 для обоих
РЕДАКТИРОВАТЬ: вам может потребоваться максимально увеличить насыщенность, а затем преобразовать ее обратно в RGB и проверить, какое значение является самым высоким (например, (255,0,0) или (255,0255) и т. Д.
Если вы хотите получить доступ к значению RGB всех пикселей, то ниже приведен код,
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat image = imread("image_path");
for(int row = 1; row < image.rows; row++)
{
for(int col = 1; col < image.cols; col++)
{
Vec3b rgb = image.at<Vec3b>(row, col);
}
}
}