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

