最简单的方法是直接将序数索引映射到颜色 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颜色形式<0,n-1>只是每个通道使用值的模数(所以r0,g0,b0或256-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);
}
//---------------------------------------------------------------------------
我只使用了冒泡排序,所以如果您想要更快的速度,请改用快速排序...