Pierwsze kilka pytań, aby lepiej wyjaśnić swoje wątpliwości:
- jaką chcesz interpolacji: liniowa/sześcienny/inny?
- Jakie są ograniczenia punktów? na przykład czy zawsze będzie tylko jeden region zamknięty przez te punkty kontrolne, czy też mogą być w nim punkty?
Dla prostego interpolacji liniowej i arbitralne (ale co najmniej 3 punkty nie na jednej linii) chciałbym spróbować to: obszar punkty kontrolne
triangulacji
do nie nakładania się trójkąty obejmujące cały określony obszar.
renderowania trójkątów
Więc po prostu rasterize zobaczyć Algorithm to fill triangle i wszystkie sublinks. Powinieneś interpolować również R,G,B
wraz ze współrzędnymi.
Tworzenie do 2 kopii gradientu i przenieść jedną z H i druga z linii V
Tak przemiatania wszystkich H poziomych linii gradientu, a w przypadku stwierdzenia 2 Znany pikseli wystarczająco daleko od siebie (na przykład ćwiartka lub połowa wielkości gradientu), a następnie ekstrapoluj całą linię nieznanych kolorów. Więc jeśli znaleziono znane punkty końcowe (Red) są (x0,y,r0,g0,b0),(x1,y,r1,g1,b1)
następnie ustawić wszystkie nieznane kolory w tej samej linii co:
r = r0+(r1-r0)*(x-x0)/(x1-x0)
g = g0+(g1-g0)*(x-x0)/(x1-x0)
b = b0+(b1-b0)*(x-x0)/(x1-x0)
Podobnie zrobić to samo w kopii gradientu dla linii pionowej V-teraz. Więc punkty są teraz (x, y0, R0, G0, B0), (x, y1, R1, g1, b1) `i ekstrapolacja:
r = r0+(r1-r0)*(y-y0)/(y1-y0)
g = g0+(g1-g0)*(y-y0)/(y1-y0)
b = b0+(b1-b0)*(y-y0)/(y1-y0)
Po to porównać obie kopie i jeśli nieznany punkt jest obliczany w obu ustawić go jako średnią obu kolorów w obrazie gradientu docelowego. Zapętlaj cały ten proces (# 3), dopóki nie dodasz nowego piksela gradientowego.
stosowanie pojedynczego ekstrapolowanych kolor dla odpoczynku
zależności od sposobu zdefiniowania punktów kontrolnych niektóre obszary będą miały tylko 1 ekstrapolować kolor (albo z H lub linii V, ale nie oba), więc używać tylko pojedynczy obliczony kolor dla tych (po wykonaniu # 3).
Oto przykład tego, co rozumiem przez to wszystko:
Jeśli chcesz coś prostego zamiast (ale nie dokładnie), to możesz krwawić znanych punktów kontrolnych kolory (z gładką filtry) do sąsiednich pikseli, dopóki cały gradient nie zostanie wypełniony i nasycony.
- wypełnienia nieznany gradientu pikseli z predefiniowanych kolorów rozumieniu nie obliczane
ustawić każdy piksel średnich obliczonych swoich sąsiadów
Można to zrobić w osobnym obrazek, aby uniknąć przesunięcia.
punktów
zespół sterowania z powrotem do pierwotnego koloru
pętli 2 aż obszar wypełniony/nasycony/lub ustalonej liczby iteracji
[Edit1] Drugie rozwiązanie
Ok Położyłem to razem w C++ ze swoich punktów/kolory i wielkości gradientu Oto jak to wygląda (I krwawić 100 razy 4-sąsiedzi krwawienia bez obciążników):
Obraz po lewej stronie jest wejściowy macierz gdzie zakodowany do alfa kanał (najwyższe 8 bitów), jeśli piksel jest punktem odniesienia, obliczony lub jeszcze nieokreślony. Obraz po prawej stronie jest po 100-krotnym nałożeniu krwawienia. Upuszczanie jest proste, po prostu weź dowolny punkt odniesienia i przelicz go jako średnią wszystkich użytecznych pikseli wokół i siebie (ignorując nieokreślone kolory).
Oto kod C++ można zignorować GDI materiał do renderowania (uwaga moja Mapa gradientu ma x
koordynować pierwszy masz y
!)
//---------------------------------------------------------------------------
const int mxs=7,mys=7,msz=16; // gradient resolution x,y and square size for render
DWORD map[mxs][mys]; // gradient matrix ... undefined color is >= 0xFF000000
// 0x00?????? - reference color
// 0xFF?????? - uncomputed color
// 0xFE?????? - bleeded color
//---------------------------------------------------------------------------
void map_clear() // set all pixels as uncomputed (white with alpha=255)
{
int x,y;
for (x=0;x<mxs;x++)
for (y=0;y<mys;y++)
map[x][y]=0xFFFFFFFF;
}
void map_bleed() // bleed computed colors
{
int x,y,r,g,b,n;
DWORD tmp[mxs][mys],c;
for (x=0;x<mxs;x++)
for (y=0;y<mys;y++)
{
c=map[x][y];
n=0; r=0; g=0; b=0; if (DWORD(c&0xFF000000)==0) { tmp[x][y]=c; continue; } if (DWORD(c&0xFF000000)!=0xFF000000) { r+=c&255; g+=(c>>8)&255; b+=(c>>16)&255; n++; }
x++; if ((x>=0)&&(x<mxs)&&(y>=0)&&(y<mys)) c=map[x][y]; else c=0xFF000000; if (DWORD(c&0xFF000000)!=0xFF000000) { r+=c&255; g+=(c>>8)&255; b+=(c>>16)&255; n++; }
x--; y--; if ((x>=0)&&(x<mxs)&&(y>=0)&&(y<mys)) c=map[x][y]; else c=0xFF000000; if (DWORD(c&0xFF000000)!=0xFF000000) { r+=c&255; g+=(c>>8)&255; b+=(c>>16)&255; n++; }
x--; y++; if ((x>=0)&&(x<mxs)&&(y>=0)&&(y<mys)) c=map[x][y]; else c=0xFF000000; if (DWORD(c&0xFF000000)!=0xFF000000) { r+=c&255; g+=(c>>8)&255; b+=(c>>16)&255; n++; }
x++; y++; if ((x>=0)&&(x<mxs)&&(y>=0)&&(y<mys)) c=map[x][y]; else c=0xFF000000; if (DWORD(c&0xFF000000)!=0xFF000000) { r+=c&255; g+=(c>>8)&255; b+=(c>>16)&255; n++; }
y--; if (!n) { tmp[x][y]=0xFFFFFFFF; continue; }
c=((r/n)|((g/n)<<8)|((b/n)<<16))&0x00FFFFFF;
tmp[x][y]=c;
}
// copy tmp back to map
for (x=0;x<mxs;x++)
for (y=0;y<mys;y++)
map[x][y]=tmp[x][y];
}
void map_draw(TCanvas *can,int x0,int y0) // just renders actual gradient map onto canvas (can ignore this)
{
int x,y,xx,yy;
for (x=0,xx=x0;x<mxs;x++,xx+=msz)
for (y=0,yy=y0;y<mys;y++,yy+=msz)
{
can->Pen->Color=clBlack;
can->Brush->Color=map[x][y]&0x00FFFFFF;
can->Rectangle(xx,yy,xx+msz,yy+msz);
}
}
//---------------------------------------------------------------------------
A tu wykorzystanie (Twój przykład):
// clear backbuffer
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
// init your gradient with reference points
map_clear();
// x y R G B
map[6][0] = (239)|(238<<8)|(185<<16);
map[1][1] = (120)|(131<<8)|(125<<16);
map[6][4] = (184)|(191<<8)|(171<<16);
map[2][6] = (150)|(168<<8)|(158<<16);
map[5][6] = (166)|(180<<8)|(166<<16);
map_draw(bmp->Canvas,msz,msz); // render result (left)
// bleed
for (int i=0;i<100;i++) map_bleed();
map_draw(bmp->Canvas,(mxs+2)*msz,msz); // render result (right)
// refresh window with backbufer (anti-flickering)
Main->Canvas->Draw(0,0,bmp);
Ponownie można zignorować wszystkie renderowane elementy. Liczba spadów powinna być 2x większa niż piksele w przekątnej, więc krwawienie pokrywa wszystkie piksele. Im więcej powtórzeń tym bardziej nasycone wynik staram 100
tylko dla przykładu i wynik wygląda dobrze .. więc nie grałem z nim już ...
[Edit2] i tu algorytm dla drugiego podejścia
dodać flagi interpolowanej matrycy
trzeba wiedzieć, jeśli piksel jest reference,undefined
lub interpolated
. Możesz zakodować to na kanale alfa lub użyć maski (osobnej matrycy 2D).
upustowy/gładka matrycy
zasadzie dla każdego piksela nie reference
obliczyć nową wartość jako średnią z wszystkich nie undefined
pikseli wokół sąsiadów (4/8) i na jej miejsce. Nie używaj pikseli undefined
i przechowuj wyliczoną wartość na tymczasowej matrycy (nie zmyślaj kolejnych pikseli, w przeciwnym razie efekt krwawienia/wygładzania przesuwałby piksele zazwyczaj po przekątnej). W ten sposób niezdefiniowane obszary pikseli zmniejszą się o 1 piksel. Po wykonaniu całej macierzy należy skopiować zawartość macierzy tymczasowej do oryginalnej macierzy (lub zamienić wskaźniki).
pętli 2 aż wyniku jest nasycony lub specyficzna liczba iteracji
ilość zliczeń powinna wynosić co leas 2 razy większy niż liczba pikseli ukośnych propagacji piksel odniesienia na całej matrycy. Kontrola nasycenia może być wykonana w # 2 podczas kopiowania tablicy temp do oryginalnej (może zrobić różnicę abs między klatkami i jeśli zero lub w pobliżu zatrzyma się).
Dziękuję @Spektre za poświęcenie swojego czasu na to dokładnej odpowiedzi! Nigdy nie pomyślałbym o triangulacji w tym celu. Z pewnością spróbuję. Chociaż muszę przyznać, że spodziewałem się (z powodu mojej zwykłej ignorancji) łatwiejszego rozwiązania dla macierzy i niestrukturalnych danych, w jakiś sposób bazując na '' 'griddata'''' 'BivariateSpline''' (http://stackoverflow.com/a/5147409/1230358). Muszę przemyśleć i eksperymentować z Twoimi sugestiami. W każdym razie dziękuję za poświęcony czas i pomoc !!! Z przyjemnością przyjmuję twoją odpowiedź, jeśli nikt nie wymyśli łatwiejszego rozwiązania ... – hetsch
... które może być oparte na numpy lub scipy i macierzach. http://stackoverflow.com/q/5146025/1230358 dał mi kilka wskazówek, ale wciąż walczę, aby to zadziałało. – hetsch
Dodałem lepsze ilustracje papieru, z którego mam oryginalny pomysł. Z tego co rozumiem, pracują z odległością od punktu odniesienia do punktu, który ma być kolorowy. Wydaje się być podobnym do pierwszego rozwiązania, które zasugerowałeś. – hetsch