如何使用OpenCV从图像获取调色板 [英] How to get a color palette from an image using OpenCV

查看:406
本文介绍了如何使用OpenCV从图像获取调色板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想提取图像的调色板,类似于此(从

我需要它来提取特定的颜色,例如黄色,绿色和棕色,并显示该颜色覆盖的面积百分比。另外,我可以添加更多颜色来提取。


如何减少原始图像中的颜色数量,如何获得调色板?

解决方案

这里发生了三种不同的事情。


  1. 减少颜色数量图像的颜色

  2. 获取图像的不同颜色

  3. 获取颜色名称

减少颜色数量


有很多减少颜​​色数量的技术。


使用 kmeans 方法,我得到了还原色图片:



其调色板为:

 颜色:[14,134,225]-面积:5.28457%
颜色:[16,172,251]-面积:27.3851%
颜色:[22、68、101]-区域:3.41029%
颜色:[28、154、161]-区域:3.89029%
颜色:[40、191、252]-区域:22.3429 %
颜色:[87,204,251]-面积:8.704%
颜色:[161,222,251]-面积:3.47429%
颜色:[253,255,255] -面积:25.5086%

您现在可以在列表中搜索最接近的颜色名称,您将得到所需的颜色。如何组成GUI来显示这些信息取决于您:数据就在那里。


代码:

  #include< opencv2\opencv.hpp> 
#include< opencv2\photo.hpp>
#include< iostream>
#include< map>

使用命名空间cv;
使用命名空间std;

// https://stackoverflow.com/a/34734939/5008845
void reduceColor_Quantization(const Mat3b& src,Mat3b& dst)
{
uchar N = 64;
dst = src / N;
dst * = N;
}

// https://stackoverflow.com/a/34734939/5008845
void reduceColor_kmeans(const Mat3b& src,Mat3b& dst)
{
int K = 8;
int n = src.rows * src.cols;
Mat数据= src.reshape(1,n);
data.convertTo(data,CV_32F);

vector< int>标签;
Mat1f颜色;
kmeans(数据,K,标签,cv :: TermCriteria(),1,cv :: KMEANS_PP_CENTERS,颜色);

for(int i = 0; i< n; ++ i)
{
data.at< float>(i,0)= colors(labels [i ],0);
data.at< float>(i,1)=颜色(labels [i],1);
data.at< float>(i,2)=颜色(labels [i],2);
}

Mat减少= data.reshape(3,src.rows);
reduction.convertTo(dst,CV_8U);
}

void reduceColor_Stylization(const Mat3b& src,Mat3b& dst)
{
stylization(src,dst);
}

void reduceColor_EdgePreserving(const Mat3b& src,Mat3b& dst)
{
edgePreservingFilter(src,dst);
}


$ b struct lessVec3b
{
bool operator()(const Vec3b& lhs,const Vec3b& rhs)const {
return (lhs [0]!= rhs [0])吗? (lhs [0]< rhs [0]):((lhs [1]!= rhs [1])?(lhs [1]< rhs [1]):(lhs [2]&rhs [2 ]));
}
};

map< Vec3b,int,lessVec3b> getPalette(const Mat3b& src)
{
map< Vec3b,int,lessVec3b>调色板
for(int r = 0; r< src.rows; ++ r)
{
for(int c = 0; c< src.cols; ++ c)
{
Vec3b color = src(r,c);
if(palette.count(color)== 0)
{
palette [color] = 1;
}
else
{
调色板[颜色] =调色板[颜色] + 1;
}
}
}
返回调色板;
}


int main()
{
Mat3b img = imread( path_to_image);

//减少颜色
Mat3b减少了;

// reduceColor_Quantization(img,减少);
reduceColor_kmeans(img,减少);
// reduceColor_Stylization(img,减少);
// reduceColor_EdgePreserving(img,减少);


//获取调色板
map< Vec3b,int,lessVec3b>调色板= getPalette(减少);

//打印调色板
int area = img.rows * img.cols;

(自动颜色:调色板)
{
cout<< "颜色:" << color.first<< " -t-区域:" << 100.f * float(color.second)/ float(area)<< % <<恩德尔
}

返回0;
}


I'd like to extract the color palette of an image, similar to this (from here):

I need it to extract specific colors, like yellow, green, and brown and display the percentage of the area covered by that color. Also, I can add more colors to extract.

How can I reduce the number of colors in the original image, and how can I get the color palette?

解决方案

There are three different things going on here.

  1. Reduce the number of colors of an image
  2. Get the different colors of an image
  3. Get the color name

Reduce the number of colors

There are many techniques to reduce the number of colors. Here you can see how to use color quantization and kmeans.

Another approach could use the median cut algorithm (not shown here).

OpenCV provides the Non-Photorealistic Rendering module. Here you can see some examples of how to use it.

Get the different colors of an image

This is pretty easy. Just iterate over the whole image. If you see a new color, store its value, with counter equal to 1. If you see a color already seen, increment its counter. A std::map could be useful here.

Get the color name

I won't show it here. But online there are some useful resources. You need a list of all named colors. Keep in mind that not every color has a name. In fact, all possible colors for RGB values would be 256*256*256. So find the closest color in your list, and assign its name to your current color.


For example, with this input image,

using kmeans approach, I get the reduced color image:

And its palette is:

Color: [14, 134, 225]    - Area: 5.28457%
Color: [16, 172, 251]    - Area: 27.3851%
Color: [22, 68, 101]     - Area: 3.41029%
Color: [28, 154, 161]    - Area: 3.89029%
Color: [40, 191, 252]    - Area: 22.3429%
Color: [87, 204, 251]    - Area: 8.704%
Color: [161, 222, 251]   - Area: 3.47429%
Color: [253, 255, 255]   - Area: 25.5086%

You can now search for the closest color name in your list, and you'll get what you need. How to make up the GUI to show these information is up to you: the data is all there.

Code:

#include <opencv2\opencv.hpp>
#include <opencv2\photo.hpp>
#include <iostream>
#include <map>

using namespace cv;
using namespace std;

// https://stackoverflow.com/a/34734939/5008845
void reduceColor_Quantization(const Mat3b& src, Mat3b& dst)
{
    uchar N = 64;
    dst = src / N;
    dst *= N;
}

// https://stackoverflow.com/a/34734939/5008845
void reduceColor_kmeans(const Mat3b& src, Mat3b& dst)
{
    int K = 8;
    int n = src.rows * src.cols;
    Mat data = src.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, src.rows);
    reduced.convertTo(dst, CV_8U);
}

void reduceColor_Stylization(const Mat3b& src, Mat3b& dst)
{
    stylization(src, dst);
}

void reduceColor_EdgePreserving(const Mat3b& src, Mat3b& dst)
{
    edgePreservingFilter(src, dst);
}


struct lessVec3b
{
    bool operator()(const Vec3b& lhs, const Vec3b& rhs) const {
        return (lhs[0] != rhs[0]) ? (lhs[0] < rhs[0]) : ((lhs[1] != rhs[1]) ? (lhs[1] < rhs[1]) : (lhs[2] < rhs[2]));
    }
};

map<Vec3b, int, lessVec3b> getPalette(const Mat3b& src)
{
    map<Vec3b, int, lessVec3b> palette;
    for (int r = 0; r < src.rows; ++r)
    {
        for (int c = 0; c < src.cols; ++c)
        {
            Vec3b color = src(r, c);
            if (palette.count(color) == 0)
            {
                palette[color] = 1;
            }
            else
            {
                palette[color] = palette[color] + 1;
            }
        }
    }
    return palette;
}


int main()
{
    Mat3b img = imread("path_to_image");

    // Reduce color
    Mat3b reduced;

    //reduceColor_Quantization(img, reduced);
    reduceColor_kmeans(img, reduced);
    //reduceColor_Stylization(img, reduced);
    //reduceColor_EdgePreserving(img, reduced);


    // Get palette
    map<Vec3b, int, lessVec3b> palette = getPalette(reduced);

    // Print palette
    int area = img.rows * img.cols;

    for (auto color : palette)
    {
        cout << "Color: " << color.first << " \t - Area: " << 100.f * float(color.second) / float(area) << "%" << endl;
    }

    return 0;
}

这篇关于如何使用OpenCV从图像获取调色板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆