【问题标题】:How to find a starting color to perform color mixing operation如何找到起始颜色进行混色操作
【发布时间】:2019-06-12 06:40:15
【问题描述】:

我正在尝试跟随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 通道的约束。

【问题讨论】:

  • 调色板中只有一种颜色怎么样,我不明白。
  • @LancePollard 我添加了排序的调色板代码和预览......只有c1 是粗略的......看起来像弗劳恩霍夫在visible spectra 之上的线条:)

标签: algorithm colors


【解决方案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 中链接)。所以我从所有可用颜色中线性选择了xs(渲染调色板的宽度)而不是random

如您所见,算法正常工作。

这个想法是计算n变量中有多少可用颜色,然后任何i-th颜色形式&lt;0,n-1&gt;只是每个通道使用值的模数(所以r0,g0,b0256-r0,... )

您知道是否要将 3 个整数变量 x,y,z 打包到一个中

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

然后:

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

然后返回:

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

PS。如果您想更好地对可以转换为 HSV 的颜色进行排序,并按 值、饱和度、色调(即订单对我来说是最好的......色调必须最后排序!!!)像这样:

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.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;
const int _h=2;
const int _s=1;
const int _v=0;
union color
    {
    BYTE db[4]; // channel access
    DWORD dd;   // all 32 bit of color
    };
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void rgb2bgr(color &c)
    {
    BYTE a;
    a                =c.db[_r];
    c.db[_r]=c.db[_b];
    c.db[_b]=a;
    }
//---------------------------------------------------------------------------
void rgb2hsv(color &c)
    {
    double r,g,b,min,max,del,h,s,v,dr,dg,db;
    r=c.db[_r]; r/=255.0;
    g=c.db[_g]; g/=255.0;
    b=c.db[_b]; b/=255.0;
    min=r; if (min>g) min=g; if(min>b) min=b;
    max=r; if (max<g) max=g; if(max<b) max=b;
    del=max-min;
    v=max;
    if (del<=1e-10) { h=0; s=0; }   // grayscale
    else{
        s=del/max;
        dr=(((max-r)/6.0)+(del/2.0))/del;
        dg=(((max-g)/6.0)+(del/2.0))/del;
        db=(((max-b)/6.0)+(del/2.0))/del;
        if      (fabs(r-max)<1e-10) h=db-dg;
        else if (fabs(g-max)<1e-10) h=(1.0/3.0)+dr-db;
        else if (fabs(b-max)<1e-10) h=(2.0/3.0)+dg-dr;
        if (h<0.0) h+=1.0;
        if (h>1.0) h-=1.0;
        }
    c.db[_h]=h*255.0;
    c.db[_s]=s*255.0;
    c.db[_v]=v*255.0;
    }
//---------------------------------------------------------------------------
void hsv2rgb(color &c)
    {
    int i;
    double r,g,b,h,s,v,vh,v1,v2,v3,f;
    h=c.db[_h]; h/=255.0;
    s=c.db[_s]; s/=255.0;
    v=c.db[_v]; v/=255.0;
    if (s<=1e-10) { r=v; g=v; b=v; }    // grayscale
    else{
        vh=h*6.0;
        if (vh>=6.0) vh=0.0;
        f=floor(vh); i=f;
        v1=v*(1.0-s);
        v2=v*(1.0-s*(    vh-f));
        v3=v*(1.0-s*(1.0-vh+f));
             if (i==0) { r=v ; g=v3; b=v1; }
        else if (i==1) { r=v2; g=v ; b=v1; }
        else if (i==2) { r=v1; g=v ; b=v3; }
        else if (i==3) { r=v1; g=v2; b=v ; }
        else if (i==4) { r=v3; g=v1; b=v ; }
        else           { r=v ; g=v1; b=v2; }
        }
    c.db[_r]=r*255.0;
    c.db[_g]=g*255.0;
    c.db[_b]=b*255.0;
    }
//---------------------------------------------------------------------------
__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;
    color *pal=new color[xs];   // palette size equal to rendered window width
    // 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]
    // compute c1 into pal[]
    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
        {
        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);
        pal[x]=c1;
        }

    // sort pal (_h must be last to sort by)
    for (x=0;x<xs;x++) rgb2hsv(pal[x]);
    i=_v; for (yy=1,n=xs;(n>=2)&&(yy);n--) for (yy=0,x=1;x<n;x++) if (pal[x].db[i]>pal[x-1].db[i]) { c=pal[x]; pal[x]=pal[x-1]; pal[x-1]=c; yy=1; }
    i=_s; for (yy=1,n=xs;(n>=2)&&(yy);n--) for (yy=0,x=1;x<n;x++) if (pal[x].db[i]>pal[x-1].db[i]) { c=pal[x]; pal[x]=pal[x-1]; pal[x-1]=c; yy=1; }
    i=_h; for (yy=1,n=xs;(n>=2)&&(yy);n--) for (yy=0,x=1;x<n;x++) if (pal[x].db[i]>pal[x-1].db[i]) { c=pal[x]; pal[x]=pal[x-1]; pal[x-1]=c; yy=1; }
    for (x=0;x<xs;x++) hsv2rgb(pal[x]);

    // render c1, c2 and c1+c2
    bmp->Canvas->TextOutA(xs>>1,y+1*sz,"+");
    bmp->Canvas->TextOutA(xs>>1,y+3*sz,"=");
    for (x=0;x<xs;x++)                              // chose xs colors from n
        {
        // colors
        c1=pal[x];
        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
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c1.dd;     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]
    // compute c1 into pal[]
    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
        {
        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);
        pal[x]=c1;
        }

    // sort pal (_h must be last to sort by)
    for (x=0;x<xs;x++) rgb2hsv(pal[x]);
    i=_v; for (yy=1,n=xs;(n>=2)&&(yy);n--) for (yy=0,x=1;x<n;x++) if (pal[x].db[i]>pal[x-1].db[i]) { c=pal[x]; pal[x]=pal[x-1]; pal[x-1]=c; yy=1; }
    i=_s; for (yy=1,n=xs;(n>=2)&&(yy);n--) for (yy=0,x=1;x<n;x++) if (pal[x].db[i]>pal[x-1].db[i]) { c=pal[x]; pal[x]=pal[x-1]; pal[x-1]=c; yy=1; }
    i=_h; for (yy=1,n=xs;(n>=2)&&(yy);n--) for (yy=0,x=1;x<n;x++) if (pal[x].db[i]>pal[x-1].db[i]) { c=pal[x]; pal[x]=pal[x-1]; pal[x-1]=c; yy=1; }
    for (x=0;x<xs;x++) hsv2rgb(pal[x]);

    // render c1, c2 and c1-c2
    bmp->Canvas->TextOutA(xs>>1,y+1*sz,"-");
    bmp->Canvas->TextOutA(xs>>1,y+3*sz,"=");
    for (x=0;x<xs;x++)                              // chose xs colors from n
        {
        c1=pal[x];
        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
        for (i=0;(y<ys)&&(i<sz);y++,i++) p[y][x]=c1.dd;     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;
    delete[] pal;
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    xs=ClientWidth-pan_right->Width;
    ys=ClientHeight;
    bmp->SetSize(xs,ys);
    sb_rgbChange(this);
    }
//---------------------------------------------------------------------------

我只使用了冒泡排序,所以如果您想要更快的速度,请改用快速排序...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 2022-01-18
    相关资源
    最近更新 更多