有些时候我们需要为一些对象附上随机的颜色,比如我们有这么一个需求,在一个chart里添加显示曲线,刚开始曲线的颜色默认都是黑色的很不好看,后来为了显示的美观我们想给添加的曲线随机的附上颜色,但是有一个要求,曲线的颜色不能太淡,比如不能是白色。因为我们的chart的背景颜色是白色的,如果曲线也是白色那曲线就会看不到了。
我们首先想到的方法是如下:
Color c(rand()%256,rand()%256,rand()%256);
这样可以实现我们对随机颜色的要求,但是不满足我们不能为白色的要求,为了避免白色,我们在对这个颜色进行检查,如果r、g、b分量的值都超过230,表示颜色太淡重新随机,但是这样的方法总让人感觉不那么舒服。
后来想到了在HSL颜色空间里做文章是否会更舒服呢?
于是通过Wiki复习HSL颜色空间的知识。发现在HSL空间里如果L分量大于200,颜色看起来就比较淡了,所以我们可以随机生成小于200的数值作为L分量,再借助强大的Qt于是我们可以这样实现我们的需求:
首先借助Qt的QColor生成一个颜色对象:
QColor qc = QColor::fromHsl(rand()%360,rand()%256,rand()%200);
这里要注意的是H分量的值域是0到359的。
最后得到的颜色为:
Color c(qc.red(),qc.green(),qc.blue());
如果不用Qt的话,网上有很多HSL颜色空间转RGB颜色空间的代码和公式也可是替代上面用到的Qt。这样我们就省略了第一种方法里的循环,实现的方法看起来更加舒服了。
有些时候我们可能会有这样的需求,比如我们想给一张地图上色,相邻的国家的颜色视觉区别要尽可能大,于是我们给的一种或几种颜色,要找到与这些颜色差别最大的颜色,这要怎么实现呢?下面是别人写的代码。我觉得还是有改进的空间的:
1 static ColorType getUniqueColor(const std::vector<ColorType>& excludedColors)
2 {
3 unsigned int i,j,k;
4 ColorType uniqueColor(0,0,0);
5 //如果当前没有颜色
6 if (excludedColors.size()==0)
7 {
8 return uniqueColor; //因为没有颜色所以随便返回一个颜色
9 }
10 //如果当前只有一个颜色
11 if (excludedColors.size()==1)
12 {
13 int maxDist=-1;
14 int red=excludedColors[0].mRed;
15 int green=excludedColors[0].mGreen;
16 int blue=excludedColors[0].mBlue;
17
18 for (i=0;i<256;i+=255)
19 {
20 for (j=0;j<256;j+=255)
21 {
22 for (k=0;k<256;k+=255)
23 {
24 int dist=(i-red)*(i-red)+(j-green)*(j-green)+(k-blue)*(k-blue);
25 if (dist>maxDist)
26 {
27 maxDist=dist;
28 uniqueColor.mRed=i;
29 uniqueColor.mGreen=j;
30 uniqueColor.mBlue=k;
31 }
32 }
33 }
34 }
35 return uniqueColor;
36 }
37
38 std::vector<unsigned int> badColors;
39 badColors.reserve(excludedColors.size()); //预留空间
40
41 std::vector<ColorType>::const_iterator iter;
42 for (iter=excludedColors.begin();iter!=excludedColors.end();iter++)
43 {
44 badColors.push_back((iter->mBlue<<16)+(iter->mGreen<<8)+iter->mRed);
45 }
46
47 std::sort(badColors.begin(),badColors.end());
48
49 unsigned int duplicates=0;
50 unsigned int next;
51
52 for (i=0,next=1;i<badColors.size()-duplicates;i++)
53 {
54 for (j = next; j < badColors.size(); j++)
55 {
56 if (badColors[i] != badColors[j])
57 {
58 badColors[i + 1] = badColors[j];
59 next = j + 1;
60 break;
61 }
62 else
63 {
64 duplicates++;
65 }
66 }
67 }
68 badColors.erase(badColors.begin() + (badColors.size() - duplicates), badColors.end());
69
70 std::vector<unsigned int>::iterator ulit = badColors.begin();
71 unsigned int testColor;
72 for (testColor = 0; testColor < 0xffffff; testColor++)
73 {
74 if (testColor == *ulit)
75 {
76 ulit++;
77 }
78 else
79 {
80 break;
81 }
82 }
83
84 if (testColor == 0x01000000) // 如果搜遍了16.7百万的颜色都没找到的话,则返回无效的颜色
85 {
86 uniqueColor = ColorType();
87 }
88 else
89 {
90 uniqueColor.mBlue = (testColor&0xff0000)>>16;
91 uniqueColor.mGreen = (testColor&0xff00)>>8;
92 uniqueColor.mRed = testColor&0xff;
93 }
94
95 return uniqueColor;
96 }
ColorType是颜色类型,里面包含了三个分量。
如果我们要同时获取多个不同的颜色呢?可以参考下面的代码:
1 /**
2 * 产生一个或多个唯一的颜色
3 * @param count 要产生的颜色的个数
4 * @param colors 用于保存生成颜色的向量
5 * @param excludeColors 要排除的颜色
6 * @return 产生的颜色的个数
7 */
8 static unsigned int getUniqueColors(unsigned int count, std::vector<ColorType>& colors,
9 const std::vector<ColorType>& excludeColors)
10 {
11 unsigned int i, j, k, l;
12 unsigned int numUnique = 0;
13 double slValues[] = {0.0, 1.0, 0.5, 0.8, 0.3, 0.6, 0.9, 0.2, 0.7, 0.4, 0.1};
14 ColorType baseColors[] =
15 {
16 ColorType(0,0,255),
17 ColorType(0,255,0),
18 ColorType(255,0,0),
19 ColorType(0,255,255),
20 ColorType(255,255,0),
21 ColorType(255,0,255),
22 ColorType(255,255,255)
23 };
24
25 for (i = 0; i < sizeof(slValues) / sizeof(slValues[0]); i++)
26 {
27 for (j = 0; j < sizeof(slValues) / sizeof(slValues[0]); j++)
28 {
29 for (k = 0; k < sizeof(baseColors) / sizeof(baseColors[0]); k++)
30 {
31 int newColor[3];
32 int maxValue;
33
34 newColor[0] = (int) (baseColors[k].mRed * slValues[j] + 0.5);
35 newColor[1] = (int) (baseColors[k].mGreen * slValues[j] + 0.5);
36 newColor[2] = (int) (baseColors[k].mBlue * slValues[j] + 0.5);
37
38 maxValue = 0;
39 for (l = 0; l < 3; l++)
40 {
41 if (newColor[l] > maxValue)
42 {
43 maxValue = newColor[l];
44 }
45 }
46
47 maxValue = (int) (maxValue * slValues[i] + 0.5);
48 for (l = 0; l < 3; l++)
49 {
50 if (newColor[l] < maxValue)
51 {
52 newColor[l] = maxValue;
53 }
54 }
55
56 ColorType colorToInsert;
57 colorToInsert.mRed = newColor[0];
58 colorToInsert.mGreen = newColor[1];
59 colorToInsert.mBlue = newColor[2];
60
61 for (l=0; l<excludeColors.size(); l++)
62 {
63 if (excludeColors[l].mRed == colorToInsert.mRed &&
64 excludeColors[l].mGreen == colorToInsert.mGreen &&
65 excludeColors[l].mBlue == colorToInsert.mBlue)
66 {
67 break;
68 }
69 }
70 if (l == excludeColors.size())
71 {
72 for (l = 0; l < colors.size(); l++)
73 {
74 if (colors[l].mRed == colorToInsert.mRed &&
75 colors[l].mGreen == colorToInsert.mGreen &&
76 colors[l].mBlue == colorToInsert.mBlue)
77 {
78 break;
79 }
80 }
81 if (l == colors.size())
82 {
83 colors.push_back (colorToInsert);
84 ++numUnique;
85 if (colors.size() == count)
86 {
87 return numUnique;
88 }
89 }
90 }
91 }
92 }
93 }
94 return numUnique;
95 }