如何在固定颜色显示器中找到最红的颜色?
How can you find reddest colour in a fixed colour display?
我正在为一台名为 Amiga 的旧计算机编写 UI(有些人可能还记得这些)。他们的显示模式具有固定数量的颜色 - 2、4、8、16 等,您可以使用 0 到 255 的 RGB 设置其中任何一个。
所以在 4 色显示器上你可以:
- 颜色 0 R=0,G=0,B=0(黑色)
- 颜色 1 R=255, G=255, B=255(白色)
- 颜色 2 R=128,G=128,B=128(中灰色)
- 颜色 3 R=255,G=0,B=0(红色)
您可以在 'normal' 显示器上拥有的最大颜色数是 255(有一些特殊的显示模式可以提高这个值,但我不需要担心这些)。
我正在尝试编写一些 C 代码来读取显示器的颜色列表并找到最红、最绿和最蓝的颜色,但我无法理解所涉及的比较。
如果我有 3 个变量 - 红色、绿色和蓝色 - 所有包含当前颜色 rgb 值的整数和另外 3 个 - stored_red、stored_stored_green 和 stored_blue.
我如何编写一个函数来记住相对于其他颜色而言最红的颜色编号?
我试过:
If ((red>stored_red) && ((blue <stored_blue) || (green<stored_green)))
但这行不通。我想我需要研究比率,但就是想不通数学。
有不同的方法来检查最大值 "redness"/"greenness" 等,这里第一个简单的方法是我最初使用的答案:
/* for all palette (color table) entries */
if(red > stored_red) {
max_red_index = current_index;
stored_red = red;
}
if(blue > stored_blue) {
max_blue_index = current_index;
stored_blue = blue;
}
当然绿色也一样。
这只会给出具有最大分量的颜色,但在@Chris Turner 的评论之后我认为这可能不是你想要的。
另一种方法是检查红色与其他颜色的比例(从现在开始我将只使用红色):
redness = red*2/(blue + green + 1)
这给"redness"一个1到510之间的数字,不考虑亮度。例如 R-G-B 50-10-10 比 255-100-100 (2) 更红 (4)。
许多其他公式也是可能的,例如
redness = red*red/(blue + green + 1)
也会考虑亮度,认为比 50-10-10 红 255-100-100。
要使用这些公式,只需将上面的 red
变量设置为红色公式的结果即可。
您应该计算红色的百分比以找到最红的颜色。
这里是一个使用RGB
结构的程序,具有比较两个RGB
结构是否为"reddness"的函数。如果两种颜色的红色百分比相同,则 .r
字段中具有最大值的颜色被视为 "redder"。另一个函数采用指向 RGB
结构的指针数组和 returns 指向被视为 "reddest".
的 RGB 三元组的指针
注意在计算百分比时必须注意检查RGB元组是否全为零(0, 0, 0);这可能会导致尝试除以零。感谢@alain 在我的原始代码中发现了这个错误。
#include <stdio.h>
#include <stdbool.h>
struct RGB {
int r;
int g;
int b;
};
bool is_redder_pct(struct RGB *triple1, struct RGB *triple2);
struct RGB * max_red(struct RGB *triples, size_t num_triples);
int main(void)
{
struct RGB colors[] = { { .r = 125, .g = 0, .b = 0 },
{ .r = 150, .g = 255, .b = 0 },
{ .r = 100, .g = 20, .b = 21 },
{ .r = 255, .g = 21, .b = 22 },
{ .r = 0, .g = 0, .b = 0 },
{ .r = 255, .g = 255, .b = 255 },
{ .r = 128, .g = 128, .b = 128 },
{ .r = 255, .g = 0, .b = 0 } };
size_t num_colors = sizeof colors / sizeof *colors;
struct RGB *reddest = max_red(colors, num_colors);
printf("The reddest color is: (%d, %d, %d)\n",
reddest->r, reddest->g, reddest->b);
return 0;
}
/* Returns true if triple1 is at least as red as triple2 */
bool is_redder_pct(struct RGB *triple1, struct RGB *triple2)
{
bool ret_val;
int triple1_sum = triple1->r + triple1->g + triple1->b;
int triple2_sum = triple2->r + triple2->g + triple2->b;
/* if triple1 is black, triple1 is not redder than triple2 */
if (triple1_sum == 0) {
ret_val = false;
/* otherwise, if triple2 is black, triple1 is redder than triple2 */
} else if (triple2_sum == 0) {
ret_val = true;
/* otherwise the percentages are calculated in a comparison */
} else {
ret_val = triple1->r / (triple1_sum * 1.0)
>= triple2->r / (triple2_sum * 1.0);
}
return ret_val;
}
/* Returns a pointer to the RGB struct in the array TRIPLES
* that compares "reddest" */
struct RGB * max_red(struct RGB *triples, size_t num_triples)
{
struct RGB *max = &triples[0];
for (size_t i = 1; i < num_triples; i++) {
struct RGB *curr = &triples[i];
if (is_redder_pct(curr, max) && curr->r > max->r) {
max = curr;
}
}
return max;
}
程序输出:
The reddest color is: (255, 0, 0)
下面是基于CompuPhase - Colour metric的一个"a low-cost approximation"色差,但是避开了平方根函数(从而测出色差的平方,方便比较),并对结果进行缩放以避免整数除法导致的精度损失。它按照从 "most red" 到 "least red".
的顺序对颜色元组数组进行排序
比较中灰色比黑色更红,黑色比白色更红,这看起来相当随意!
#include <stdio.h>
#include <stdlib.h>
/*
* Sorts an array of RGB color values (each component from 0 to 255)
* in descending order of redness.
*
* Uses a low-cost approximation of color distance from
* <https://www.compuphase.com/cmetric.htm>. It uses a weighted Euclidean
* distance function to measure the distance between colors, where the weight
* factors depend on the mean level of "red":
*
* rmean = (c1.r + c2.r) / 2
* dr = c1.r - c2.r
* dg = c1.g - c2.g
* db = c1.b - c2.b
*
* dc = sqrt(((2 + (rmean / 256)) * dr * dr) + (4 * dg * dg) +
* ((2 + ((255 - rmean) / 256)) * db * db))
*
* Uses a modified version of the above which returns the square of the
* distance between two colors scaled by a silly amount to avoid loss of
* precision caused by integer division.
*/
struct rgb {
unsigned char r; /* red range 0..255 */
unsigned char g; /* green range 0..255 */
unsigned char b; /* blue range 0..255 */
};
/* distance squared between two colors, scaled by some silly amount. */
long color_dist_squared(const struct rgb *c1, const struct rgb *c2)
{
long rsum = c1->r + c2->r;
long dr = (long)c1->r - (long)c2->r;
long dg = (long)c1->g - (long)c2->g;
long db = (long)c1->b - (long)c2->b;
return (((1024 + rsum) * dr * dr) + (2048 * dg * dg) +
((1534 - rsum) * db * db));
}
/* distance squared from pure red, scaled by some silly amount. */
long antiredness_squared(const struct rgb *c)
{
const struct rgb pure_red = { .r = 255, .g = 0, .b = 0 };
return color_dist_squared(&pure_red, c);
}
/*
* qsort() comparison function.
* a and b point to struct rgb values.
* Returns 1 if *a is more anti-red (less red) than *b.
* Returns 0 if *a and *b are equally (anti-)red.
* Returns -1 if *a is less anti-red (more red) than *b.
*/
int compar_antiredness(const void *a, const void *b)
{
const struct rgb *ca = (const struct rgb *)a;
const struct rgb *cb = (const struct rgb *)b;
long ara = antiredness_squared(ca);
long arb = antiredness_squared(cb);
long diff = ara - arb;
return (diff > 0) - (diff < 0);
}
int main(void)
{
struct rgb colors[] = {
{ .r = 125, .g = 0, .b = 0 },
{ .r = 150, .g = 255, .b = 0 },
{ .r = 100, .g = 20, .b = 21 },
{ .r = 255, .g = 21, .b = 22 },
{ .r = 0, .g = 0, .b = 0 },
{ .r = 255, .g = 255, .b = 255 },
{ .r = 128, .g = 128, .b = 128 },
{ .r = 255, .g = 0, .b = 0 },
};
size_t num_colors = sizeof(colors) / sizeof(colors[0]);
size_t i;
printf("Unsorted colors:\n");
for (i = 0; i < num_colors; i++) {
printf("[%zu] R=%u, G=%u, B=%u\n", i, (unsigned)colors[i].r,
(unsigned)colors[i].g, (unsigned)colors[i].b);
}
printf("\n");
qsort(colors, num_colors, sizeof(colors[0]), compar_antiredness);
printf("Colors sorted from most red to least red:\n");
for (i = 0; i < num_colors; i++) {
printf("[%zu] R=%u, G=%u, B=%u\n", i, (unsigned)colors[i].r,
(unsigned)colors[i].g, (unsigned)colors[i].b);
}
return 0;
}
上面的输出:
Unsorted colors:
[0] R=125, G=0, B=0
[1] R=150, G=255, B=0
[2] R=100, G=20, B=21
[3] R=255, G=21, B=22
[4] R=0, G=0, B=0
[5] R=255, G=255, B=255
[6] R=128, G=128, B=128
[7] R=255, G=0, B=0
Colors sorted from most red to least red:
[0] R=255, G=0, B=0
[1] R=255, G=21, B=22
[2] R=125, G=0, B=0
[3] R=100, G=20, B=21
[4] R=128, G=128, B=128
[5] R=0, G=0, B=0
[6] R=150, G=255, B=0
[7] R=255, G=255, B=255
编辑:当然,使用以下函数从最绿到最不绿,或从最蓝到最不蓝排序同样容易:
/* distance squared from pure green, scaled by some silly amount. */
long antigreenness_squared(const struct rgb *c)
{
const struct rgb pure_green = { .r = 0, .g = 255, .b = 0 };
return color_dist_squared(&pure_green, c);
}
/*
* qsort() comparison function.
* a and b point to struct rgb values.
* Returns 1 if *a is more anti-green (less green) than *b.
* Returns 0 if *a and *b are equally (anti-)green.
* Returns -1 if *a is less anti-green (more green) than *b.
*/
int compar_antigreenness(const void *a, const void *b)
{
const struct rgb *ca = (const struct rgb *)a;
const struct rgb *cb = (const struct rgb *)b;
long aga = antigreenness_squared(ca);
long agb = antigreenness_squared(cb);
long diff = aga - agb;
return (diff > 0) - (diff < 0);
}
/* distance squared from pure blue, scaled by some silly amount. */
long antiblueness_squared(const struct rgb *c)
{
const struct rgb pure_blue = { .r = 0, .g = 0, .b = 255 };
return color_dist_squared(&pure_blue, c);
}
/*
* qsort() comparison function.
* a and b point to struct rgb values.
* Returns 1 if *a is more anti-blue (less blue) than *b.
* Returns 0 if *a and *b are equally (anti-)blue.
* Returns -1 if *a is less anti-blue (more blue) than *b.
*/
int compar_antiblueness(const void *a, const void *b)
{
const struct rgb *ca = (const struct rgb *)a;
const struct rgb *cb = (const struct rgb *)b;
long aba = antiblueness_squared(ca);
long abb = antiblueness_squared(cb);
long diff = aba - abb;
return (diff > 0) - (diff < 0);
}
我正在为一台名为 Amiga 的旧计算机编写 UI(有些人可能还记得这些)。他们的显示模式具有固定数量的颜色 - 2、4、8、16 等,您可以使用 0 到 255 的 RGB 设置其中任何一个。
所以在 4 色显示器上你可以:
- 颜色 0 R=0,G=0,B=0(黑色)
- 颜色 1 R=255, G=255, B=255(白色)
- 颜色 2 R=128,G=128,B=128(中灰色)
- 颜色 3 R=255,G=0,B=0(红色)
您可以在 'normal' 显示器上拥有的最大颜色数是 255(有一些特殊的显示模式可以提高这个值,但我不需要担心这些)。
我正在尝试编写一些 C 代码来读取显示器的颜色列表并找到最红、最绿和最蓝的颜色,但我无法理解所涉及的比较。
如果我有 3 个变量 - 红色、绿色和蓝色 - 所有包含当前颜色 rgb 值的整数和另外 3 个 - stored_red、stored_stored_green 和 stored_blue.
我如何编写一个函数来记住相对于其他颜色而言最红的颜色编号?
我试过:
If ((red>stored_red) && ((blue <stored_blue) || (green<stored_green)))
但这行不通。我想我需要研究比率,但就是想不通数学。
有不同的方法来检查最大值 "redness"/"greenness" 等,这里第一个简单的方法是我最初使用的答案:
/* for all palette (color table) entries */
if(red > stored_red) {
max_red_index = current_index;
stored_red = red;
}
if(blue > stored_blue) {
max_blue_index = current_index;
stored_blue = blue;
}
当然绿色也一样。
这只会给出具有最大分量的颜色,但在@Chris Turner 的评论之后我认为这可能不是你想要的。
另一种方法是检查红色与其他颜色的比例(从现在开始我将只使用红色):
redness = red*2/(blue + green + 1)
这给"redness"一个1到510之间的数字,不考虑亮度。例如 R-G-B 50-10-10 比 255-100-100 (2) 更红 (4)。
许多其他公式也是可能的,例如
redness = red*red/(blue + green + 1)
也会考虑亮度,认为比 50-10-10 红 255-100-100。
要使用这些公式,只需将上面的 red
变量设置为红色公式的结果即可。
您应该计算红色的百分比以找到最红的颜色。
这里是一个使用RGB
结构的程序,具有比较两个RGB
结构是否为"reddness"的函数。如果两种颜色的红色百分比相同,则 .r
字段中具有最大值的颜色被视为 "redder"。另一个函数采用指向 RGB
结构的指针数组和 returns 指向被视为 "reddest".
注意在计算百分比时必须注意检查RGB元组是否全为零(0, 0, 0);这可能会导致尝试除以零。感谢@alain 在我的原始代码中发现了这个错误。
#include <stdio.h>
#include <stdbool.h>
struct RGB {
int r;
int g;
int b;
};
bool is_redder_pct(struct RGB *triple1, struct RGB *triple2);
struct RGB * max_red(struct RGB *triples, size_t num_triples);
int main(void)
{
struct RGB colors[] = { { .r = 125, .g = 0, .b = 0 },
{ .r = 150, .g = 255, .b = 0 },
{ .r = 100, .g = 20, .b = 21 },
{ .r = 255, .g = 21, .b = 22 },
{ .r = 0, .g = 0, .b = 0 },
{ .r = 255, .g = 255, .b = 255 },
{ .r = 128, .g = 128, .b = 128 },
{ .r = 255, .g = 0, .b = 0 } };
size_t num_colors = sizeof colors / sizeof *colors;
struct RGB *reddest = max_red(colors, num_colors);
printf("The reddest color is: (%d, %d, %d)\n",
reddest->r, reddest->g, reddest->b);
return 0;
}
/* Returns true if triple1 is at least as red as triple2 */
bool is_redder_pct(struct RGB *triple1, struct RGB *triple2)
{
bool ret_val;
int triple1_sum = triple1->r + triple1->g + triple1->b;
int triple2_sum = triple2->r + triple2->g + triple2->b;
/* if triple1 is black, triple1 is not redder than triple2 */
if (triple1_sum == 0) {
ret_val = false;
/* otherwise, if triple2 is black, triple1 is redder than triple2 */
} else if (triple2_sum == 0) {
ret_val = true;
/* otherwise the percentages are calculated in a comparison */
} else {
ret_val = triple1->r / (triple1_sum * 1.0)
>= triple2->r / (triple2_sum * 1.0);
}
return ret_val;
}
/* Returns a pointer to the RGB struct in the array TRIPLES
* that compares "reddest" */
struct RGB * max_red(struct RGB *triples, size_t num_triples)
{
struct RGB *max = &triples[0];
for (size_t i = 1; i < num_triples; i++) {
struct RGB *curr = &triples[i];
if (is_redder_pct(curr, max) && curr->r > max->r) {
max = curr;
}
}
return max;
}
程序输出:
The reddest color is: (255, 0, 0)
下面是基于CompuPhase - Colour metric的一个"a low-cost approximation"色差,但是避开了平方根函数(从而测出色差的平方,方便比较),并对结果进行缩放以避免整数除法导致的精度损失。它按照从 "most red" 到 "least red".
的顺序对颜色元组数组进行排序比较中灰色比黑色更红,黑色比白色更红,这看起来相当随意!
#include <stdio.h>
#include <stdlib.h>
/*
* Sorts an array of RGB color values (each component from 0 to 255)
* in descending order of redness.
*
* Uses a low-cost approximation of color distance from
* <https://www.compuphase.com/cmetric.htm>. It uses a weighted Euclidean
* distance function to measure the distance between colors, where the weight
* factors depend on the mean level of "red":
*
* rmean = (c1.r + c2.r) / 2
* dr = c1.r - c2.r
* dg = c1.g - c2.g
* db = c1.b - c2.b
*
* dc = sqrt(((2 + (rmean / 256)) * dr * dr) + (4 * dg * dg) +
* ((2 + ((255 - rmean) / 256)) * db * db))
*
* Uses a modified version of the above which returns the square of the
* distance between two colors scaled by a silly amount to avoid loss of
* precision caused by integer division.
*/
struct rgb {
unsigned char r; /* red range 0..255 */
unsigned char g; /* green range 0..255 */
unsigned char b; /* blue range 0..255 */
};
/* distance squared between two colors, scaled by some silly amount. */
long color_dist_squared(const struct rgb *c1, const struct rgb *c2)
{
long rsum = c1->r + c2->r;
long dr = (long)c1->r - (long)c2->r;
long dg = (long)c1->g - (long)c2->g;
long db = (long)c1->b - (long)c2->b;
return (((1024 + rsum) * dr * dr) + (2048 * dg * dg) +
((1534 - rsum) * db * db));
}
/* distance squared from pure red, scaled by some silly amount. */
long antiredness_squared(const struct rgb *c)
{
const struct rgb pure_red = { .r = 255, .g = 0, .b = 0 };
return color_dist_squared(&pure_red, c);
}
/*
* qsort() comparison function.
* a and b point to struct rgb values.
* Returns 1 if *a is more anti-red (less red) than *b.
* Returns 0 if *a and *b are equally (anti-)red.
* Returns -1 if *a is less anti-red (more red) than *b.
*/
int compar_antiredness(const void *a, const void *b)
{
const struct rgb *ca = (const struct rgb *)a;
const struct rgb *cb = (const struct rgb *)b;
long ara = antiredness_squared(ca);
long arb = antiredness_squared(cb);
long diff = ara - arb;
return (diff > 0) - (diff < 0);
}
int main(void)
{
struct rgb colors[] = {
{ .r = 125, .g = 0, .b = 0 },
{ .r = 150, .g = 255, .b = 0 },
{ .r = 100, .g = 20, .b = 21 },
{ .r = 255, .g = 21, .b = 22 },
{ .r = 0, .g = 0, .b = 0 },
{ .r = 255, .g = 255, .b = 255 },
{ .r = 128, .g = 128, .b = 128 },
{ .r = 255, .g = 0, .b = 0 },
};
size_t num_colors = sizeof(colors) / sizeof(colors[0]);
size_t i;
printf("Unsorted colors:\n");
for (i = 0; i < num_colors; i++) {
printf("[%zu] R=%u, G=%u, B=%u\n", i, (unsigned)colors[i].r,
(unsigned)colors[i].g, (unsigned)colors[i].b);
}
printf("\n");
qsort(colors, num_colors, sizeof(colors[0]), compar_antiredness);
printf("Colors sorted from most red to least red:\n");
for (i = 0; i < num_colors; i++) {
printf("[%zu] R=%u, G=%u, B=%u\n", i, (unsigned)colors[i].r,
(unsigned)colors[i].g, (unsigned)colors[i].b);
}
return 0;
}
上面的输出:
Unsorted colors:
[0] R=125, G=0, B=0
[1] R=150, G=255, B=0
[2] R=100, G=20, B=21
[3] R=255, G=21, B=22
[4] R=0, G=0, B=0
[5] R=255, G=255, B=255
[6] R=128, G=128, B=128
[7] R=255, G=0, B=0
Colors sorted from most red to least red:
[0] R=255, G=0, B=0
[1] R=255, G=21, B=22
[2] R=125, G=0, B=0
[3] R=100, G=20, B=21
[4] R=128, G=128, B=128
[5] R=0, G=0, B=0
[6] R=150, G=255, B=0
[7] R=255, G=255, B=255
编辑:当然,使用以下函数从最绿到最不绿,或从最蓝到最不蓝排序同样容易:
/* distance squared from pure green, scaled by some silly amount. */
long antigreenness_squared(const struct rgb *c)
{
const struct rgb pure_green = { .r = 0, .g = 255, .b = 0 };
return color_dist_squared(&pure_green, c);
}
/*
* qsort() comparison function.
* a and b point to struct rgb values.
* Returns 1 if *a is more anti-green (less green) than *b.
* Returns 0 if *a and *b are equally (anti-)green.
* Returns -1 if *a is less anti-green (more green) than *b.
*/
int compar_antigreenness(const void *a, const void *b)
{
const struct rgb *ca = (const struct rgb *)a;
const struct rgb *cb = (const struct rgb *)b;
long aga = antigreenness_squared(ca);
long agb = antigreenness_squared(cb);
long diff = aga - agb;
return (diff > 0) - (diff < 0);
}
/* distance squared from pure blue, scaled by some silly amount. */
long antiblueness_squared(const struct rgb *c)
{
const struct rgb pure_blue = { .r = 0, .g = 0, .b = 255 };
return color_dist_squared(&pure_blue, c);
}
/*
* qsort() comparison function.
* a and b point to struct rgb values.
* Returns 1 if *a is more anti-blue (less blue) than *b.
* Returns 0 if *a and *b are equally (anti-)blue.
* Returns -1 if *a is less anti-blue (more blue) than *b.
*/
int compar_antiblueness(const void *a, const void *b)
{
const struct rgb *ca = (const struct rgb *)a;
const struct rgb *cb = (const struct rgb *)b;
long aba = antiblueness_squared(ca);
long abb = antiblueness_squared(cb);
long diff = aba - abb;
return (diff > 0) - (diff < 0);
}