算法挑战:从图像生成颜色方案

rin*_*ogo 53 algorithm image colors

背景

所以,我正在研究一个新的Web应用程序迭代.并且,我们发现我们的用户沉迷于懒惰.真的很懒.事实上,我们为他们做的工作越多,他们就越喜欢这项服务.现有应用程序的一部分要求用户选择要使用的配色方案.但是,我们有一个图像(用户网站的截图),为什么我们不能只是满足他们的懒惰并为他们做呢?答:我们可以,这将是一个有趣的编程练习!:)

挑战

给定图像,如何创建相应的配色方案? 换句话说,如何选择图像中的主要X颜色(其中X由Web应用程序定义).在我们的特定情况下使用的图像是用户网站的屏幕截图,以全分辨率(例如1280x1024)拍摄.(注意:请简单描述一下您的算法 - 不需要发布实际的伪代码.)

奖励积分(街道积分,而不是实际的SO积分):

  • 描述一种简单而有效的算法.代码是我们创造的方式 - 保持简单和美观.
  • 允许用户根据各种"情绪"调整配色方案,例如"炫彩","明亮","静音","深度"等(a la Kuler)
  • 描述用于可靠地确定网站屏幕截图中使用的主要文本颜色的方法(可能需要其自己的,单独的算法).

灵感

有几个现有的站点执行类似的功能.请随意查看它们并问自己:"我如何复制它?我怎么能改进它?"

Pau*_*ier 26

  1. 要查找主要的X颜色,请使用该应用程序.在图像上运行颜色直方图.直方图中的前X个颜色是主题.编辑:如果使用渐变,您将需要选择不同的颜色"峰值"; 也就是说,如果橙色是渐变中使用的主要颜色之一,您可能会在"橙色"周围拥有一大堆颜色.实际上,只需在直方图中选择的颜色之间执行一定的距离.

  2. 调整配色方案最好在HSV空间中完成; 将您的颜色转换为HSV空间,如果用户希望它"更亮",请增加值,如果他们希望它更"彩色",则增加饱和度等.

  3. 确定文本颜色最好通过表征高可变性区域(傅立叶空间中的高频率)来完成.在这些区域内,你应该有:两种颜色,文字和背景,在这种情况下你的文字是较少使用的颜色; 或者您将拥有多种颜色,文本和背景图像颜色,在这种情况下,文本颜色是最常见的颜色.


小智 8

你可以看看:

https://github.com/dcollien/Dreamcoat

这是在CoffeeScript中做到这一点(有文化的咖啡,所以它有详细记录)

在这里演示:http://dcollien.github.io/Dreamcoat/test.html

它结合了颜色量化方法和KMeans方法.


小智 7

我这样做是为了找到用于图像(艺术品)的调色板.

  1. 我从imagemagick开始,将大图像调整到可调大小(即最大尺寸为400像素).这实际上有助于将细微的局部色差转换为具有这些颜色平均值的较少像素.

  2. 循环遍历调整大小后的图像中的每个像素,读取每个像素的RGB值,将RGB转换为HSB并将HSB值存储到数组中.

  3. 对于找到的每个像素颜色,然后我将Hue范围(0,255)除以16,将饱和度范围(0,100)除以10,将亮度范围(0,100)除以10.将结果向上或向下舍入为整数.这有助于将像素分组为相似颜色的类别.

    因此,HSB为223,64,76的像素将属于类别14,6,8

    在每个类别中,您仍然可以找到每个像素的确切颜色,但在大多数情况下,类别本身与源图像的颜色匹配很近.

    如果您希望从类别中进行更好的颜色复制,请选择将HSB划分为更精细的分区.即.将每个H,S,B除以8,5,5而不是16,10,10.

  4. 计算最流行的颜色类别,排序和显示.我丢弃的像素数很少的颜色类别.

注意:这实际上是为具有相同颜色值的像素非常少的艺术品而设计的(即具有阴影和渐变的绘画.)

在大多数情况下,HTML页面可能具有与特定颜色值完全匹配的更多像素(即背景颜色,文本颜色等在它们出现的任何地方都将是相同的颜色.)


for*_*sto 6

颜色量化与用于选择低色彩GIF调色板的过程相同.为了从摄影图像中获取调色板,我使用了Nick Rabinowitz的quantize.js,它基于Leptonica的MMCQ(修改的中值切割量化).

meemoo屏幕截图 现场的Web应用程序,有关.


max*_*llb 5

  1. 将屏幕图像划分为r个多个矩形的网格,以n×m"网格",每个具有宽度(总宽度/ n)和高度(总高度/ m).

    1A.为屏幕的高调区域指定权重,例如左偏离中心区域.

    1B.对于每个矩形,将像素分配到(颜色,频率)的空间

  2. 对于每个矩形R,频率分布f_R和权重W_R:

    2A.通过扫描每个块的"顶部频率","第二频率"( f_R [ i,:])来确定第i个方案颜色(例如,i = 1 - 背景颜色).

    2B.对于每个i,将其放入得分表(color_i,得分),其中得分= f_R [ i,"频率"]*W_R

    2C.每个i的最佳得分手将是第i个方案颜色.

从理论上讲,如果你有很多"蓝白色"或"红黑",你应该得到白色的初级,蓝色次级或黑色初级,红色次级,例如.

对于文本颜色,可以直接根据背景颜色计算,也可以选择二次颜色,如果HSV的V差太小,则将颜色基于计算出的方案颜色,但增加V值.

伪代码:

float[][] weights = 
    { { 1.0, 3.0, 5.0, 5.0, 3.0, 1.0, 1.0, 1.0, 1.0 },
      { 2.0, 6.0, 7.0, 7.0, 6.0, 2.0, 3.0, 3.0, 2.0 },
      { 2.0, 8.0, 9.0, 9.0, 7.0, 3.0, 6.0, 6.0, 3.0 },
      { 2.0, 8.0, 9.0, 9.0, 7.0, 2.0, 3.0, 3.0, 2.0 },
      { 2.0, 7.0, 9.0, 9.0, 7.0, 2.0, 1.0, 1.0, 1.0 },
      { 2.0, 6.0, 7.0, 7.0, 6.0, 2.0, 3.0, 3.0, 1.0 },
      { 1.0, 3.0, 5.0, 5.0, 3.0, 2.0, 6.0, 6.0, 2.0 },
      { 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 6.0, 6.0, 2.0 },
      { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 3.0, 1.0 } };

// Leave the following implementations to the imagination:
void DivideImageIntoRegions( Image originalImage, out Image[][] regions );
void GetNthMostCommonColorInRegion( Image region, int n, out Color color );
TKey FindMaximum<TKey, TValue>( Map<TKey, TValue> map );

// The method:
Color[] GetPrimaryScheme( Image image, int ncolors, int M = 9, int N = 9 )
{
    Color[] scheme = new Color[ncolors];
    Image[][] regions = new Image[M][N];

    DivideImageIntoRegions( image, regions );

    for( int i = 0; i < ncolors; i++ )
    {
        Map<Color, float> colorScores = new Map<Color, float>();

        for( int m = 0; m < M; m++ )
        for( int n = 0; n < N; n++ )
        {
            Color theColor;
            GetNthMostCommonColorInRegion( region, i, theColor );

            if( colorScores[theColor] == null )
            { colorScores[theColor] = 0; }

            colorScores[theColor] += weights[m][n];
        }

        scheme[i] = FindMaximum( colorScores );
    }

    return scheme;
}
Run Code Online (Sandbox Code Playgroud)

综上所述,很明显,如果存在一个变化很小的区域,它将具有与最常见颜色相同的第二常见颜色.要进行调整,在这种情况下,第二种最常见的颜色可能为空,这可以防范:

            if( theColor != null )
                continue;

            if( colorScores[theColor] == null )
            { colorScores[theColor] = 0; }

            colorScores[theColor] += weights[m][n];
        }
Run Code Online (Sandbox Code Playgroud)