在加工过程中获得主导色彩

时间:2016-01-11 14:32:20

标签: colors processing average

我试图获得图像的最主要颜色(完美的情况:获得最常用的5种主色调)。有没有办法在处理过程中做到这一点?我已经尝试了一个我找到的代码,但是我只得到了平均颜色:

color extractColorFromImage(PImage img) 
{ 
    img.loadPixels(); 
    int r = 0, g = 0, b = 0; 
    for (int i=0; i<img.pixels.length; i++) 
    { 
        color c = img.pixels[i]; 
        r += c>>16&0xFF; 
        g += c>>8&0xFF; 
        b += c&0xFF;
    } 
    r /= img.pixels.length; g /= img.pixels.length; b /= img.pixels.length;
    return color(r, g, b);
}

所以它并不是我需要的东西。我已经读过,我可以用HSV,k-means等等来做这件事....还有什么方法可以在处理中做到这一点?

示例:这里我想将红色作为主色,上面的例子我得到一个深橙色。 Red-Blue Picture

4 个答案:

答案 0 :(得分:1)

这个怎么样? 在位图中设置图像并分析每个像素。只需将像素在图像中的次数相加即可。

static Dictionary<Color, int> CalcImageColors(Bitmap image)
    {
        var frequency = new Dictionary<Color, int>();
        for (var h = 0; h < image.Height; h++)
        {
            for (var w = 0; w < image.Width; w++)
            {
                var pixel = image.GetPixel(w, h);
                if (frequency.ContainsKey(pixel))
                {
                    frequency[pixel]++;
                }
                else
                {
                    frequency.Add(pixel, 1);
                }
            }
        }
       return frequency.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
    }

答案 1 :(得分:0)

将问题分解为更小的步骤。

第1步:您可以迭代图像中的像素吗?查看get() function以获得帮助。或者您可以在代码中使用for循环。但首先,尝试打印出每个单元格的RGB值。

第2步:当您开始工作时,请尝试跟踪您看到的每种颜色的数量。你这样做的方式取决于你想要做什么:应该(255,0,0)和(200,0,0)都算作红色?但有一种方法可能是使用跟踪每种颜色计数的HashMap<color, Integer>

第3步:根据每种颜色的计数,现在您可以输出主色。如何执行此操作取决于您在步骤2中使用的数据结构。

如果您遇到某个特定步骤,请发布MCVE,我们会从那里开始。祝你好运!

答案 2 :(得分:0)

RGB色彩空间可能无法始终如您在混合/平均色彩方面所期望的那样工作。您应该转换为感知色彩空间,如CIE LAB。要做到这一点,您需要先从RGB转换为CIE XYZ,然后从CIE XYZ转换为CIE RGB。有关详情,请查看CIE XYZCIE LAB上的这些页面。

在处理方面,这里是使用来自this answer的RGB&lt;&gt; CIE XYZ&lt;&gt; CIE LAB颜色转换代码的原型(在处理IDE中进行小的调整(这是很烦人的)使用static关键字)):

void setup(){
  PImage src = loadImage("http://i.stack.imgur.com/0H1OM.png");

  size(src.width*4,src.height);
  noStroke();

  //display original image
  image(src,0,0);

  //display RGB average color
  fill(extractColorFromImage(src));
  rect(src.width,0,src.width,src.height);

  //display (perceptual)Lab average color
  fill(extractAverageColorFromImage(src));
  rect(src.width*2,0,src.width,src.height);

  //display the most dominant colour
  fill(extractDominantColorFromImage(src));
  rect(src.width*3,0,src.width,src.height);

}

color extractDominantColorFromImage(PImage img){
  //create a hashmap - the key is the colour, the value associated is the number of pixels per colour
  HashMap<Integer,Integer> colorCounter = new HashMap<Integer,Integer>();
  int numPixels = img.pixels.length;

  for (int i=0; i<numPixels; i++){
    int colorKey = img.pixels[i];
    //if the colour has already been added to the hashmap, increment the count
    if(colorCounter.containsKey(colorKey)){
      colorCounter.put(colorKey,colorCounter.get(colorKey)+1);
    }else{//otherwise count it as 1
      colorCounter.put(colorKey,1);
    }
  }
  //find the most dominant colour - note you can implement this to return more than one if you need to
  int max = 0;//what's the highest density of pixels per one colour
  int dominantColor = 0;//which colour is it

  //for each key (colour) in the keyset  
  for(int colorKey : colorCounter.keySet()){
    //get the pixel count per colour
    int count = colorCounter.get(colorKey);
    //if this one is the highest, updated the max value and keep track of the colour
    if(count > max){
      max = count;
      dominantColor = colorKey; 
    }
  }
  //return the winner (colour with most pixels associated)
  return dominantColor;
}

color extractColorFromImage(PImage img) 
{ 
    img.loadPixels(); 
    int r = 0, g = 0, b = 0; 
    for (int i=0; i<img.pixels.length; i++) 
    { 
        color c = img.pixels[i]; 
        r += c>>16&0xFF; 
        g += c>>8&0xFF; 
        b += c&0xFF;
    } 
    r /= img.pixels.length; g /= img.pixels.length; b /= img.pixels.length;
    return color(r, g, b);
}

color extractAverageColorFromImage(PImage img){
  float[] average = new float[3];
  CIELab lab = new CIELab();

  int numPixels = img.pixels.length;
  for (int i=0; i<numPixels; i++){
    color rgb = img.pixels[i];

    float[] labValues = lab.fromRGB(new float[]{red(rgb),green(rgb),blue(rgb)});

    average[0] += labValues[0];
    average[1] += labValues[1];
    average[2] += labValues[2];
  }

  average[0] /= numPixels;
  average[1] /= numPixels;
  average[2] /= numPixels;

  float[] rgb = lab.toRGB(average);

  return color(rgb[0] * 255,rgb[1] * 255,rgb[2] * 255);
}

//from https://stackoverflow.com/questions/4593469/java-how-to-convert-rgb-color-to-cie-lab
import java.awt.color.ColorSpace;

public class CIELab extends ColorSpace {

    @Override
    public float[] fromCIEXYZ(float[] colorvalue) {
        double l = f(colorvalue[1]);
        double L = 116.0 * l - 16.0;
        double a = 500.0 * (f(colorvalue[0]) - l);
        double b = 200.0 * (l - f(colorvalue[2]));
        return new float[] {(float) L, (float) a, (float) b};
    }

    @Override
    public float[] fromRGB(float[] rgbvalue) {
        float[] xyz = CIEXYZ.fromRGB(rgbvalue);
        return fromCIEXYZ(xyz);
    }

    @Override
    public float getMaxValue(int component) {
        return 128f;
    }

    @Override
    public float getMinValue(int component) {
        return (component == 0)? 0f: -128f;
    }    

    @Override
    public String getName(int idx) {
        return String.valueOf("Lab".charAt(idx));
    }

    @Override
    public float[] toCIEXYZ(float[] colorvalue) {
        double i = (colorvalue[0] + 16.0) * (1.0 / 116.0);
        double X = fInv(i + colorvalue[1] * (1.0 / 500.0));
        double Y = fInv(i);
        double Z = fInv(i - colorvalue[2] * (1.0 / 200.0));
        return new float[] {(float) X, (float) Y, (float) Z};
    }

    @Override
    public float[] toRGB(float[] colorvalue) {
        float[] xyz = toCIEXYZ(colorvalue);
        return CIEXYZ.toRGB(xyz);
    }

    CIELab() {
        super(ColorSpace.TYPE_Lab, 3);
    }

    private double f(double x) {
        if (x > 216.0 / 24389.0) {
            return Math.cbrt(x);
        } else {
            return (841.0 / 108.0) * x + N;
        }
    }

    private double fInv(double x) {
        if (x > 6.0 / 29.0) {
            return x*x*x;
        } else {
            return (108.0 / 841.0) * (x - N);
        }
    }

//    private Object readResolve() {
//        return getInstance();
//    }

//    private static class Holder {
//        static final CIELab INSTANCE = new CIELab();
//    }

//    private static final long serialVersionUID = 5027741380892134289L;

    private final ColorSpace CIEXYZ =
        ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);

    private final double N = 4.0 / 29.0;

}

您可以看到原始图像的预览,然后(按此顺序):

  • RGB平均值
  • LAB平均值
  • 最主要的颜色

Average and dominant colour in an image

答案 3 :(得分:0)

您可能希望在finding dominant colors in an image上查看本教程。 - 这是对问题的更多数学观点。我们的想法是使用图像上的统计数据来确定主要颜色。源代码可用于OpenCV - 因此应该可以使其适用于Processing!