簡體   English   中英

如何在固定的彩色顯示屏中找到最紅的顏色?

[英]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(紅色)

“普通”顯示器上可以顯示的最大顏色數為255(有一些特殊的顯示模式可以將其推高,但我不需要擔心這些)。

我正在嘗試編寫一些C代碼,它將通過顯示器的顏色列表讀取並找到最紅,最環保和最藍的顏色,但我無法理解所涉及的比較。

如果我有3個vars -red,綠色和藍色 - 所有包含當前顏色rgb vals和3個以上的整數 - stored_red,stored_stored_green和stored_blue。

如何編寫一個能夠記住與其他顏色相比紅色最多的顏色編號的函數?

我試過了:

If ((red>stored_red) && ((blue <stored_blue) || (green<stored_green)))

但這不起作用。 我想我需要研究比率,但卻無法弄清楚數學。

有不同的方法來檢查最大的“發紅”/“綠色”等,這個第一個簡單的方法是我最初使用的答案:

/* 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)

對於“發紅”,這給出1到510之間的數字,它不考慮亮度。 例如,RGB 50-10-10比255-100-100(2)更紅(4)。

許多其他公式是可能的,類似於

redness = red*red/(blue + green + 1)

也會考慮亮度,並考慮比50-10-10更多的紅色255-100-100。

要使用這些公式,只需將red變量從上方設置為red公式的結果。

你應該計算紅色的百分比來找到最紅的顏色。

這是一個使用RGB結構的程序,其功能是比較兩個RGB結構的“reddness”。 如果兩種顏色具有相同的紅色百分比,則.r字段中具有最大值的顏色被視為“更紅”。 另一個函數接受一個指向RGB結構的指針數組,並返回指向被認為是“reddest”的RGB三元組的指針。

請注意,在計算百分比時,必須注意檢查全部為零(0,0,0)的RGB元組; 這可能導致嘗試除零。 感謝@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的顏色差異的“低成本近似” - 顏色度量 ,但避免了平方根函數(從而測量色差的平方,這對於比較目的來說很好),並且縮放結果避免整數除法造成的精度損失。 它按照從“最紅”到“最小紅”的順序對一組顏色元組進行排序。

比較使得中灰色比黑色更紅,黑色比白色更紅,這看起來相當隨意!

#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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM