给定BGR值,是否有公式可以确定整体颜色?(使用OpenCV和C ++)

10

我正在使用C++和OpenCV编写一个函数,用于检测图像中像素的颜色,确定其所处的颜色范围,并将其替换为一种通用颜色。例如,绿色可以从深绿到浅绿变化,程序将确定它仍然是绿色,并将其替换为简单的绿色,使输出图像看起来非常简单。所有设置都已完成,但是我在定义每个范围的特征方面遇到了问题,想知道是否有公式可以根据BGR值确定像素的整体颜色。如果没有,我就必须进行大量实验并自己制定这个公式,但如果已经存在某些东西,那就可以节省时间。我已经做了大量研究,到目前为止还没有找到任何东西。


“像素的整体颜色”这个术语有些模糊——你是否想将所有颜色映射到固定数量的颜色中?你可以将每个颜色空间分成k个不同的值,以创建一个可以标记的小空间。例如:int three_reds = int(floor(R / 3)); ... 然后,你只需将每个范围映射到RGB空间中的单个颜色即可。 - Pyrce
虽然有成千上万种方法可以实现这一点,有些比其他方法好得多,但我相信一旦你看到彩色立方体的概念,你应该能够想出至少一个基本的实现。8个角落的颜色是黑白、纯RGB和互补色(所以所有6种彩虹颜色)。只要选择最接近的角落,就可以得到一些展示内容。 - MSalters
有几种方法。请搜索“颜色量化”。 - beaker
3个回答

22

如果您想让图像变得更加简单(例如减少颜色),但又要好看,您有几个选择:

  • 一种简单的方法是通过一个因子 N 进行整数除法运算,然后再乘以一个因子 N

  • 或者您可以使用一些聚类算法,比如在这里展示的 kmeans 算法或中值切割算法,将图像分成 K 种颜色。

原始图像:

enter image description here

减少颜色(量化,N = 64):

enter image description here

减少颜色(聚类,K = 8):

enter image description here

代码量化:

#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;
}

5

-2
如果您想访问所有像素的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);
       }
   }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接