Как найти начальный цвет для выполнения операции смешивания цветов - PullRequest
1 голос
/ 12 июня 2019

Я пытаюсь следовать вместе с этим :

, чтобы иметь возможность микширования до 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 для преобразования hex в RGB без проблем, но я не знаю, как определить палитру цветов, которые я использую таким образом, чтобы они (или, по крайней мере, некоторые из них) соответствовали шаблону. что все их RGB-каналы меньше входных значений.

Хотите знать, можно ли продемонстрировать, как это сделать, или объяснить, как это работает? Как создать цветовую палитру таким образом, чтобы все или большинство цветов в ней соответствовали ограничению, что все их каналы RGB меньше, чем каналы RGB входного значения.

1 Ответ

1 голос
/ 12 июня 2019

проще всего напрямую отобразить порядковый индекс на цвет c1 ...

Для всех цветов просто используйте приращение (как приращение в арифметике Бигнума, где канал - это цифра).

Если вы хотите просто выделить некоторые цвета, тогда вычислите последовательность по модулю подсчета используемых значений каждого используемого канала ... примерно так в 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);
    }
//---------------------------------------------------------------------------

Код основан на моем ответе на ваш предыдущий вопрос (ссылка в ОП).Поэтому вместо random я выбрал xs (ширина отображаемой палитры) из всех используемых цветов линейно:

screenshot

Как видите,работает правильно.

Идея состоит в том, чтобы вычислить, сколько используемых цветов есть в переменной n, и тогда любая i -ая цветовая форма <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 и отсортировать по значению, насыщенности, оттенку (для меня этот порядок выглядит лучше ... оттенок должен быть отсортирован последним !!!) вот так:

HSV sorted

//$$---- 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);
    }
//---------------------------------------------------------------------------

Я использовалпросто пузырьковая сортировка, так что если вам нужна большая скорость, используйте быструю сортировку ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...