Nadesłany przez Tomasz Lubiński, 30 lipca 2009 01:00
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
Dithering - C++/Unit1.cpp:
//Tomasz Lubiński (C) 2009 // www.algorytm.org //Algorytmy Ditheringu //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- typedef struct Pixel { Byte b; Byte g; Byte r; Byte reserved; } TPixel; /* by uniknac indeksow mniejszych od zera w tablicy bledow */ #define SHIFT 3 /* zmienne potrzebne w trakcie obliczen */ TPixel colors[16]; float eb[253][232], eg[253][232], er[253][232]; float dif[11][3][6] = { { {0, 0, 0, 0, 7.0/16.0, 0}, {0, 0, 3.0/16.0, 5.0/16.0, 1.0/16.0, 0}, {0, 0 , 0, 0, 0, 0} }, { {0, 0, 0, 0, 7.0/48.0, 5.0/48.0}, {0, 3.0/48.0, 5.0/48.0, 7.0/48.0, 5.0/48.0, 3.0/48.0}, {0, 1.0/48.0, 3.0/48.0, 5.0/48.0, 3.0/48.0, 1.0/48.0} }, { {0, 0, 0, 0, 8.0/42.0, 4.0/42.0}, {0, 2.0/42.0, 4.0/42.0, 8.0/42.0, 4.0/42.0, 2.0/42.0}, {0, 1.0/42.0, 2.0/42.0, 4.0/42.0, 2.0/42.0, 1.0/42.0} }, { {0, 0, 0, 0, 8.0/32.0, 4.0/32.0}, {0, 2.0/32.0, 4.0/32.0, 8.0/32.0, 4.0/32.0, 2.0/32.0}, {0, 0 , 0, 0, 0, 0} }, { {0, 0, 0, 0, 7.0/16.0, 0}, {0, 1.0/16.0, 3.0/16.0, 5.0/16.0, 0, 0}, {0, 0 , 0, 0, 0, 0} }, { {0, 0, 0, 0, 5.0/32.0, 3.0/32.0}, {0, 2.0/32.0, 4.0/32.0, 5.0/32.0, 4.0/32.0, 2.0/32.0}, {0, 0 , 2.0/32.0, 3.0/32.0, 2.0/32.0, 0} }, { {0, 0, 0, 0, 4.0/16.0, 3.0/16.0}, {0, 1.0/16.0, 2.0/16.0, 3.0/16.0, 2.0/16.0, 1.0/16.0}, {0, 0 , 0, 0, 0, 0} }, { {0, 0, 0, 0, 2.0/4.0, 0}, {0, 0, 1.0/4.0, 1.0/4.0, 0, 0}, {0, 0 , 0, 0, 0, 0} }, { {0, 0, 0, 0, 1.0/8.0, 1.0/8.0}, {0, 0, 1.0/8.0, 1.0/8.0, 1.0/8.0, 0}, {0, 0, 0, 1.0/8.0, 0, 0} }, { {0, 0, 0, 0, 4.0/8.0, 0}, {0, 1.0/8.0, 1.0/8.0, 2.0/8.0, 0, 0}, {0, 0, 0, 0, 0, 0} }, { {0, 0, 0, 0, 8.0/16.0, 0}, {1.0/16.0, 1.0/16.0, 2.0/16.0, 4.0/16.0, 0, 0}, {0, 0, 0, 0, 0, 0} } }; //--------------------------------------------------------------------------- //pobiera kolory zdefiniowane przez uzytkownika void getColors() { int n, i; for (i=0; i<Form1->ComponentCount; i++) { if (Form1->Components[i]->Name.SubString(0, 5) =="Shape") { n = StrToInt(Form1->Components[i]->Name.SubString(6, 2)) - 1; colors[n].b = GetBValue(((TShape*)Form1->Components[i])->Brush->Color); colors[n].g = GetGValue(((TShape*)Form1->Components[i])->Brush->Color); colors[n].r = GetRValue(((TShape*)Form1->Components[i])->Brush->Color); colors[n].reserved = 0; } } } //--------------------------------------------------------------------------- //znajduje kolor w palecie najblizszy zadanemu pikslowi int findNearest(float b, float g, float r, int cnt) { int i, result; float d, tmp; d = (colors[0].b - b) * (colors[0].b - b); d += (colors[0].g - g) * (colors[0].g - g); d += (colors[0].r - r) * (colors[0].r - r); result = 0; for (i=1; i<cnt; i++) { tmp = (colors[i].b - b) * (colors[i].b - b); tmp += (colors[i].g - g) * (colors[i].g - g); tmp += (colors[i].r - r) * (colors[i].r - r); if (d > tmp) { d = tmp; result = i; } } return result; } //--------------------------------------------------------------------------- //ucina podana wartosc do zakresu 0-255 (dopuszczalne wartosci dla piksla) float clip(float x) { if (x > 255) return 255; if (x < 0) return 0; return x; } //--------------------------------------------------------------------------- //propaguje blad do komorek sasiednich void propagateError(int alg, float w, float e[253][232], int i, int j) { e[i+1+SHIFT][j ] = e[i+1+SHIFT][j ] + (w*dif[alg][0][4]); e[i+2+SHIFT][j ] = e[i+2+SHIFT][j ] + (w*dif[alg][0][5]); e[i-3+SHIFT][j+1] = e[i-3+SHIFT][j+1] + (w*dif[alg][1][0]); e[i-2+SHIFT][j+1] = e[i-2+SHIFT][j+1] + (w*dif[alg][1][1]); e[i-1+SHIFT][j+1] = e[i-1+SHIFT][j+1] + (w*dif[alg][1][2]); e[i +SHIFT][j+1] = e[i +SHIFT][j+1] + (w*dif[alg][1][3]); e[i+1+SHIFT][j+1] = e[i+1+SHIFT][j+1] + (w*dif[alg][1][4]); e[i+2+SHIFT][j+1] = e[i+2+SHIFT][j+1] + (w*dif[alg][1][5]); e[i-3+SHIFT][j+2] = e[i-3+SHIFT][j+2] + (w*dif[alg][2][0]); e[i-2+SHIFT][j+2] = e[i-2+SHIFT][j+2] + (w*dif[alg][2][1]); e[i-1+SHIFT][j+2] = e[i-1+SHIFT][j+2] + (w*dif[alg][2][2]); e[i +SHIFT][j+2] = e[i +SHIFT][j+2] + (w*dif[alg][2][3]); e[i+1+SHIFT][j+2] = e[i+1+SHIFT][j+2] + (w*dif[alg][2][4]); e[i+2+SHIFT][j+2] = e[i+2+SHIFT][j+2] + (w*dif[alg][2][5]); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int i,j,cnt,alg; float wb, wg, wr; TPixel *pixelOrg, *pixelNew, white, black; //przygotuj wartosci kolorow z palety getColors(); //przygotuj obrazy wynikowe Image2->Canvas->Brush->Color = clWhite; Image2->Canvas->Rectangle(0, 0, Image2->Width, Image2->Height); Image2->Picture->Bitmap->PixelFormat = pf32bit; Image3->Canvas->Brush->Color = clWhite; Image3->Canvas->Rectangle(0, 0, Image3->Width, Image3->Height); Image3->Picture->Bitmap->PixelFormat = pf32bit; //przygotuj format obrazu zrodlowego Image1->Picture->Bitmap->PixelFormat = pf32bit; //pobierz liczbe kolorow i algorytm do uzycia cnt = StrToInt(Form1->Edit1->Text); alg = Form1->ComboBox1->ItemIndex; //najblizsze sasiedztwo for (j=0; j<230; j++){ pixelOrg = (TPixel *)Image1->Picture->Bitmap->ScanLine[j]; pixelNew = (TPixel *)Image2->Picture->Bitmap->ScanLine[j]; for (i=0; i<248; i++){ *pixelNew = colors[findNearest(pixelOrg->b, pixelOrg->g, pixelOrg->r, cnt)]; pixelOrg++; pixelNew++; } } //dithering memset(eb, 0, sizeof(eb)); memset(eg, 0, sizeof(eg)); memset(er, 0, sizeof(er)); for (j=0; j<230; j++){ pixelOrg = (TPixel *)Image1->Picture->Bitmap->ScanLine[j]; pixelNew = (TPixel *)Image3->Picture->Bitmap->ScanLine[j]; for (i=0; i<248; i++){ *pixelNew = colors[findNearest(clip(pixelOrg->b + eb[i+SHIFT][j]), clip(pixelOrg->g + eg[i+SHIFT][j]), clip(pixelOrg->r + er[i+SHIFT][j]), cnt)]; propagateError(alg, clip(pixelOrg->b + eb[i+SHIFT][j]) - pixelNew->b , eb, i, j); propagateError(alg, clip(pixelOrg->g + eg[i+SHIFT][j]) - pixelNew->g , eg, i, j); propagateError(alg, clip(pixelOrg->r + er[i+SHIFT][j]) - pixelNew->r , er, i, j); pixelOrg++; pixelNew++; } } } //--------------------------------------------------------------------------- // Dialog umozliwiajacy zmiane palety barw void __fastcall TForm1::ShapeMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (ColorDialog1->Execute()) { ((TShape*)Sender)->Brush->Color = ColorDialog1->Color; } } //--------------------------------------------------------------------------- //Pokazywanie i ukrywanie probek z palety barw void __fastcall TForm1::Edit1Change(TObject *Sender) { int cnt, n, i; cnt = StrToInt(Edit1->Text); for (i=0; i<Form1->ComponentCount; i++) { if (Components[i]->Name.SubString(0, 5) =="Shape") { n = StrToInt(Components[i]->Name.SubString(6, 2)); if (n <= cnt) ((TShape*)Components[i])->Visible = true; else ((TShape*)Components[i])->Visible = false; } } } //--------------------------------------------------------------------------- void __fastcall TForm1::Label6Click(TObject *Sender) { ShellExecute(Application->Handle, "open", "http://www.algorytm.org", NULL, NULL, SW_NORMAL); } //---------------------------------------------------------------------------