Przyśpieszenie grafiki w BCB

0

Mam do was takie pytanie. Jak przyśpieszyć generowanie grafiki w BCB może sie źle wyraziłem ale chodzi mi po prostu o takie coś jak obracanie obrazka o 90 stopni lub inne tego typu funkcje: do obracania obrazka używam takiego kodu

  int x, y;
  int width, height;
  Graphics::TBitmap* tmpBMP = new Graphics::TBitmap;

  tmpBMP->Height = Image1->Height;
  tmpBMP->Width = Image1->Width;
  width = Image1->Width-1;
  height = Image1->Height-1;

  for (y = 0; y <= height; y++)
    for (x = 0; x <= width; x++)
    {
      tmpBMP->Canvas->Pixels[width-x][y] = Image1->Canvas->Pixels[x][y];
      Application->ProcessMessages();
    }

  Image1->Picture->Bitmap->Assign(tmpBMP);
  delete tmpBMP;  

Ale przy większych rysunkach operacja ta trwa bardzo długo nawet parenaście sekund. Za to np: MS Paint robi to parenaście razy szybciej :/ może mi ktoś powiedzieć jak to przyśpieszyć? tylko prosze nie mówcie mi o wstawkach assemblera bo sie na tym kompletnie nie znam :/

0

No niestety to sa uroki Canvas. Ale z drugiej strony zeby to trwalo kilka sekund to az niemozliwe (chyba ze masz 486 :). Przede wszystkim sproboj dopasowac wielkosc obrazka do tego co masz wysiwietlone. Byc moze jest w wysokiej rozdzialce a w okienku jest scisniety, a mimo to komp musi przestawic kazdy pixel.

A co do Canvas to nie osiagniesz na tym piorunujacej szybkosci i jesli chcesz konkretnego przyspieszenia uzyj DirectX albo OpenGL.

0

A tak w ogóle to wydaje mi sie ze nie o przyspieszanie grafiki tu chodzi bo pewnie obrazek wyswietla sie normalnie a nie powoli (np linia po linii). Nalezaloby wiec zopymalizowac kod, tyle ze ten podany przez Ciebie wydaje sie byc OK (nic mu raczej nie brakuje). Jedyne co mi przychodzi do glowy to to ze obrazek jest w za duzej rozdzialce

0

obrazek na którym to testowałem to tapeta (1024*768)

0

Obrazek nie jest duzy i powinien to robic szybko. Ewentulnie wyciagnij z wewnetrznej petli:
Application->ProcessMessages();
Nie potrzeba tego chyba po kazdym pikselu.Wystarczy jak dasz to po kazdej lini, czyli np.pomiedzy petla z "y" a petla z "x". Moze to cos pomoze.

0

Podstawa!
Całkowicie zrezygnuj z Image1->Canvas->Pixels na rzecz ScanLine !

0

też tak chciałem zrobić ale niestety nie zabardzo wiem jak sie uzywa scanline :/ szukałem na google ale tam są strasznie dziwne przykłady :(

0

yy - przecież w helpie masz tak banalny przykład, że już prościej się nie da... :|

0

No ja wiem że tam jest ale znalazłem jeszcze ze 2 strony i na każdej to jest zapisane w inny sposób :/ Ale dzięki pobawie sie tym z Helpa bo to wygląda najlepiej i jest dość krótkie :)

0

No dobrze a co gdy chce zmienić kolor danych pixeli ?? ScanLine jest tylko do odczytu :/ Czytałem troche o Pixels[][] i pisało tam ze to działa tak powoli dlatego że po każdorazowym namalowaniu pixela odświerza obraz i sie zastanawiałem czy nie dało by sie napisać jakiejś funkcji w asm która by najpierw wszystko rysowała na Canvas a potem by była druga funkcja która by odświerzała... nie wiem czy to możliwe bo jak już mówiłem nie znam sie na asm :/

0

Ja bym podszedł do tego inaczej. Trzeba załadować grafikę do pamięci - tzn. nie tyle cały plik, co właściwe dane obrazka. Chociaż to może wymagać znajomości formatu, bo w VCL chyba nie uzyska się dostępu do miejsca w pamięci gdzie jest przechowywana grafika (ale ewentualnie pokombinuj, może da się przez API, bo TBitmap po prostu enkapsuluje pewne jego mechanizmy).
Mając takie dane można je prosto i wydajnie przekształcić w sposób o jaki ci chodzi. Bo robienie tego przez VCL to tak naprawdę wykonywanie masy niepotrzebnego kodu, na który programista nie ma większego wpływu.

0

Acha czyli jeśli dobrze zrozumiałem chodzi ci o to żaby sie dobrać do "kodu" jakiejś bitmapki pozmieniać ją i dopiero wyświetlić ?? Hmmm pomysł ciekawy :)

0

Przypuszczam, że tak właśnie działają wszelakie bardziej profesjonalne (w sensie programistycznym) aplikacje w stylu IrfanView i w ogóle edytujące grafikę.

0

oto funkcja obrotu obrazka o dowolny kat z wykorzystaniem scanline'a:

bool __fastcall RotateBitmap(Graphics::TBitmap* bmpin, Graphics::TBitmap* bmpout,int deg,int hdeg,int crx,int cry,TColor back)
<font color="blue">//bmpin - obraz wejsciowy
//bmpout - obraz wynikowy
//deg - stopnie do obrotu (0..359)
//hdeg - setneczesci stopnia (0..99)
//crx, cry - punkt srodka obrotu zazwyczaj ustawiony na srodek obrazka
//back - kolor tla</span>

{
double Rad;
double sinRad;
double cosRad;
int x,y;
int k,i,l;
Byte* linein;
Byte* lineout;
int xOrg,yOrg;
int xPr,yPr;
int xPrRot,yPrRot;

bmpout->Width=bmpin->Width;
bmpout->Height=bmpin->Height;
bmpout->PixelFormat=pf24bit;

Rad=-((double)deg+(double)hdeg/100)*M_PI/180;
cosRad=cos(Rad);
sinRad=sin(Rad);

try {
for(y=0;y<bmpout->Height;y++) {
lineout=(Byte*)bmpout->ScanLine[y];
yPr=2*(y-cry)+1;
for(x=0;x<bmpout->Width;x++) {
xPr=2*(x-crx)+1;
xPrRot=(int)floor(xPrcosRad-yPrsinRad);
yPrRot=(int)floor(xPrsinRad+yPrcosRad);
xOrg=(xPrRot-1)/2+crx;
yOrg=(yPrRot-1)/2+cry;
if((xOrg>=0)&&(xOrg<bmpin->Width)&&(yOrg>=0)&&(yOrg<bmpin->Height)) {
linein=(Byte*)bmpin->ScanLine[yOrg];
k=x;
k+=k<<1;
l=xOrg;
l+=l<<1;
for(i=0;i<3;i++)
lineout[k+i]=linein[l+i];
} else {
k=x;
k+=k<<1;
lineout[k]=(Byte)GetBValue(back);
lineout[k+1]=(Byte)GetGValue(back);
lineout[k+2]=(Byte)GetRValue(back);
}
}
}
}
catch(...) {
Application->MessageBox(<font color="blue">"Błąd podczas wykonania funkcji GetScanLine."</span>,<font color="blue">"Filtrowanie - Błąd obrazu"</span>,MB_OK|MB_ICONHAND);
return false;
}
return true;
}

funkcja dziala bardzo szybko nawet duze obrazki obraca w kilkaset milisekund... (robilem testu :-P)

0

Ehhh...
Mówili ci ScanLine?

//zmienna globalna:
unsigned char** Bmp;

//wwal te funkcje w program:
void MapBitmap(Graphics::TBitmap *Bmp, unsigned char**& PP)
{
PP = new unsigned char*[Bmp->Height];
for(int i=0; i<Bmp->Height; i++)
  PP[i] = (unsigned char*)Bmp->ScanLine[i];
}

void DeMapBitmap(unsigned char**& PP)
{
delete[] PP;
}

typedef struct _COLOR {
   unsigned char R;
   unsigned char G;
   unsigned char B;
  } COLOR;

inline COLOR* GetPixel(unsigned x, unsigned y, unsigned char**& PP)
{
return (COLOR*)(&(PP[y][x*3]));
}

//zainicjuj zmienna Bmp:
MapBitmap(Image1->Picture->Bitmap,Bmp);

//tu dokonujesz operacji na pamięci TBitmap:
(*GetPixel(10,10,Bmp)).R = 255;
(*GetPixel(10,10,Bmp)).G = 255; // te funkcje zmieniają kolor pixela[10][10] na biały
(*GetPixel(10,10,Bmp)).B = 255;

//i odśwez Image1:
Image1->Refresh();

//no, a na koniec zwolnij pamięc:
DeMapBitmap(Bmp);

Mam nadzieję, że się nigdzie nie machnąłem...
Jako, że pisane było to w 5 min. to nie chciało mi się bardziej motać funkcji GetPixel(...), więc ta jest przeznaczona tylko dla palety 24-bit, gdzie jeden pixel jest reprezentowany przez 3 kolejne bajty.

To tyle.

0

ScanLine jest tylko do odczytu :/

8-0 od kiedy?? Właśnie głównie do zapisu to się stosuje. To po prostu bezpośrednie odwołanie do pamięci. Czytaj pomoc uważniej!!

0

sam ScanLine jest tylko do odczytu w BCB ... __property Byte* ScanLine = {read GetScanLine}; tak jest w helpie BCB .... wiec nie da sie zapisac bezposrednio do tej wlasnosci nowej linii bajtow .... nie mozna zrobic czego takiego Bitmapa->ScanLine=nowalinia;

jednakze ScanLine zwraca nam WSKAZNIK i tu jest pelna dowolnosc zminy danych pod tym wskaznikiem a ze to jest bezposrednie miejsce w pamieci obrazka wiec dziala nardzo szybko :-P

0

No przecież o to mi chodziło.
Bez przesady, że trzeba wszystko tłumaczyć. To tak jakbyś się przyczepił, że nie nie można zapisać nic do zmiennej. Bo zapisujemy pod adres w pamięci, gdzie ona wskazuje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1