如何从图像使用opencv获得调色板? [英] How to get color palette from image using opencv?

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

问题描述

我想提取图片的调色板,类似这样(从



我需要它来提取特定的颜色,如黄色,绿色和棕色,并显示该颜色覆盖的区域的百分比。



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

解决方案

这里有3种不同的事情。


  1. 减少图片的颜色数量

  2. 取得图片的不同颜色

  3. 取得颜色 >

减少颜色数量



有很多技术可以减少颜色数量。



使用 kmeans



img src =http://i.stack.imgur.com/PDdKZ.pngalt =输入图片说明here>



及其调色板是:

 颜色:[14,134,225]  - 面积:5.28457%
颜色: 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% b $ b颜色:[253,255,255] - 面积:25.5086%

为您的列表中最接近的颜色名称,你会得到你所需要的。



代码:

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

using namespace cv;
using namespace std;

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

// http://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>标签;
Mat1f颜色;
kmeans(data,K,labels,cv :: TermCriteria(),1,cv :: KMEANS_PP_CENTERS,colors);

for(int i = 0; i {
data.at< float>(i,0)= colors ],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){
return lhs [0]!= rhs [0])? (lhs [0] }
};

map< Vec3b,int,lessVec3b> getPalette(const Mat3b& src)
{
map for(int r = 0; r {
for(int c = 0; 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);

//减少颜色
Mat3b reduced;

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


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

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

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

return 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 3 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 Median Cut algorithm (not shown here).

OpenCV provides the Non-Photorealistic Rendering module. Here you can see some examples on 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 equals 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 it's up to you: data are all there.

Code:

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

using namespace cv;
using namespace std;

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

// http://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) {
        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天全站免登陆