我试图获得图像的最主要颜色(完美的情况:获得最常用的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
答案 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 XYZ和CIE 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;
}
您可以看到原始图像的预览,然后(按此顺序):
答案 3 :(得分:0)
您可能希望在finding dominant colors in an image上查看本教程。 - 这是对问题的更多数学观点。我们的想法是使用图像上的统计数据来确定主要颜色。源代码可用于OpenCV - 因此应该可以使其适用于Processing!