如何找到起始颜色以执行混色操作

时间:2019-06-12 06:40:15

标签: algorithm colors

我正在尝试与this一起使用:

  

为了能够混合到c0,每个通道的c1必须小于或等于c0。例如,随机的较小颜色:

r1 = (Random(256)*r0)>>8;
g1 = (Random(256)*g0)>>8;
b1 = (Random(256)*b0)>>8;

所以说您有一种颜色00aa00。您想知道什么颜色混合形成这种颜色。该答案的实现方式是通过生成随机的初始颜色(“第一混合值”)使所有RGB通道的颜色均小于00aa00输入/起始值。但是我想对第一个混合值有更多的控制。我想说要生成一个调色板,例如使用chroma.js,以便颜色可以很好地融合在一起。然后,我将这些颜色中的一个用作第一个混合值,并按照等式获得组合成00aa00的第二个混合值。就这么简单。

但是问题是我不知道如何从调色板中找出哪种颜色的RGB通道都小于输入值。我可以使用tinycolor之类的库将十六进制转换为RGB没问题,但是我不知道如何定义所用颜色的调色板,使它们全部(或至少其中一些)适合图案它们的所有RGB通道都小于输入值。

想知道是否可以演示如何执行此操作或解释其工作原理。如何以一种使调色板中的所有或大多数颜色符合其RGB通道均小于输入值的RGB通道的约束的方式生成调色板。

1 个答案:

答案 0 :(得分:1)

最简单的方法是将序号索引直接映射到颜色c1 ...

对于所有颜色,只需使用增量(例如,在通道为数字的bignum算术上递增)。

如果您想要突出一些颜色,则计算每个已使用通道的可用模数的顺序模数...在 C ++ / VCL 中类似这样:

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
int xs=0,ys=0;                  // resolution
Graphics::TBitmap *bmp=NULL;    // screen back buffer
//---------------------------------------------------------------------------
const int _r=2; // channel order
const int _g=1;
const int _b=0;
const int _a=3;
union color
    {
    BYTE db[4]; // channel access
    DWORD dd;   // all 32 bit of color
    };
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    bmp=new Graphics::TBitmap;
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    sb_rgbChange(this);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::sb_rgbChange(TObject *Sender)
    {
    if ((!xs)||(!ys)) return;   // not initialized window yet?
    int i,n,x,y,yy,sz=10;
    DWORD **p,a;
    color c0,c1,c2,c;
    // direct pixel access
    p=new DWORD*[ys];
    for (y=0;y<ys;y++) p[y]=(DWORD*)bmp->ScanLine[y];
    bmp->Canvas->Font->Height=sz;
    bmp->Canvas->Font->Color=clWhite;
    bmp->Canvas->Brush->Style=bsClear;
    // clear screen
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
      p[y][x]=0;
    x=0; y=sz;
    // get c0 color from R,G,B sliders
    c0.db[_r]=255-sb_r->Position;
    c0.db[_g]=255-sb_g->Position;
    c0.db[_b]=255-sb_b->Position;
    c0.db[_a]=0;
    Caption=AnsiString().sprintf("Target color: %08Xh",c0.dd);
    // additive
    n=(c0.db[_r]+1)*(c0.db[_g]+1)*(c0.db[_b]+1);    // c1 all usable colors
    for (x=0;x<xs;x++)                              // chose xs colors from n
        {
        // colors
        a=x*(n-1)/(xs-1);                           // compute c1 as conversion x -> R,G,B
        c1.db[_a]=0;
        c1.db[_r]=a%(c0.db[_r]+1); a/=(c0.db[_r]+1);
        c1.db[_g]=a%(c0.db[_g]+1); a/=(c0.db[_g]+1);
        c1.db[_b]=a%(c0.db[_b]+1); a/=(c0.db[_b]+1);
        for (i=0;i<3;i++) c2.db[i]=c0.db[i]-c1.db[i]; c2.db[_a]=0;  // compute c2 = c0 - c1
        for (i=0;i<3;i++)  c.db[i]=c1.db[i]+c2.db[i];  c.db[_a]=0;  // verify  c  = c1 + c2
        // render to bitmap
        yy=y;                                       // remember last y
        bmp->Canvas->TextOutA(xs>>1,y+sz,"+");
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c1.dd;     y+=sz;
        bmp->Canvas->TextOutA(xs>>1,y+sz,"=");
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c2.dd;     y+=sz;
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c .dd;     y+=sz;
        y=yy;                                       // restore last y
        }
    y+=7*sz;

    // substractive
    n=(256-c0.db[_r])*(256-c0.db[_g])*(256-c0.db[_b]);  // c1 all usable colors
    for (x=0;x<xs;x++)                              // chose xs colors from n
        {
        // colors
        a=x*(n-1)/(xs-1);                           // compute c1 as conversion x -> R,G,B
        c1.db[_a]=0;
        c1.db[_r]=c0.db[_r]+(a%(c0.db[_r]+1)); a/=(c0.db[_r]+1);
        c1.db[_g]=c0.db[_g]+(a%(c0.db[_g]+1)); a/=(c0.db[_g]+1);
        c1.db[_b]=c0.db[_b]+(a%(c0.db[_b]+1)); a/=(c0.db[_b]+1);
        for (i=0;i<3;i++) c2.db[i]=c1.db[i]-c0.db[i]; c2.db[_a]=0;  // compute c2 = c1 - c0
        for (i=0;i<3;i++)  c.db[i]=c1.db[i]-c2.db[i];  c.db[_a]=0;  // verify  c  = c1 - c2
        // render to bitmap
        yy=y;                                       // remember last y
        bmp->Canvas->TextOutA(xs>>1,y+sz,"-");
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c1.dd;     y+=sz;
        bmp->Canvas->TextOutA(xs>>1,y+sz,"=");
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c2.dd;     y+=sz;
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c .dd;     y+=sz;
        y=yy;                                       // restore last y
        }
    y+=7*sz;

    bmp->Canvas->Brush->Style=bsSolid;
    Canvas->Draw(0,0,bmp);
    delete[] p;
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    xs=ClientWidth-pan_right->Width;
    ys=ClientHeight;
    bmp->SetSize(xs,ys);
    sb_rgbChange(this);
    }
//---------------------------------------------------------------------------

代码基于我对上一个问题的回答(在OP中链接)。因此,我从所有可用颜色中线性选择了random(呈现调色板的宽度),而不是xs

screenshot

您可以看到算法正常工作。

这个想法是要计算n变量中有多少种可用颜色,然后任何i的颜色形式<0,n-1>只是每个通道使用的值的模(因此{ {1}}或r0,g0,b0

您知道是否要将3个整数变量256-r0,...打包到其中

x,y,z

然后:

x = <0,xs)
y = <0,ys)
z = <0,zs)

并返回:

w = x + xs*y + xs*ys*z

PS。如果要更好地对颜色进行排序,可以将选择的颜色转换为 HSV ,然后按值,饱和度,色相(即顺序对我来说最好...色相必须排在最后!!!):

HSV sorted

x = w%xs
y = (w/xs)%ys
z = (w/(xs*ys))%zs

我只是使用冒泡排序,所以如果您想提高速度,请改用快速排序...