schneller Zugriff auf Bild
-
Ich mache das bisher so:
Ich lade ein Bild von der Festplatte in ein TImage und mache dann was mit dem Image.
Z.B.
for (int x = 0; x < Image1->Width; x++) for (int y = 0; y < Image1->Height; y++) Image1->Canvas->Pixels[x][y]++;Das dauert aber extrem lange!
Wie geht das schneller?
Vielen Dank & Liebe Grüße!
-
TBitmap::ScanLine
-
Vielen Dank für die Antwort ... damit kann man schnell zeichnen ...
aber wie kann ich folgendes machen?
Ich habe ein Image und möchte ein neues Image erstellen ...
Dabei soll jeder Pixel im neuen Bild aus den Pixel vom originalbild und den 8 Pixeln die um den zu bearbeiten Pixel liegen zusammen setzten ... es soll also ein durchschnitt der ach Pixel gebildet werden.
Vielen Dank & Liebe Grüße!
-
Das ist doch eine einfache Mathematik-Frage, was hat das mit dem BCB zu tun!?
-
Ich lade das Bild aus einem TImage == CBuilder
gibt es noch eine schnellere Möglichkeit als TBitmap::ScanLine?
-
Kann es sein, dass das nur mit bestimmten Datentypen richtig funktioniert ... benutze ich ein s/w Bild als ausgangsbild funktioniert alles wunderbar ... hingegen bei einem farbbild wird nur das 1. viertel bearbeitet ...
-
Hallo
Thoms schrieb:
gibt es noch eine schnellere Möglichkeit als TBitmap::ScanLine?
Möglicherweise mit WinAPI anstelle von TBitmap.
Kann es sein, dass das nur mit bestimmten Datentypen richtig funktioniert ... benutze ich ein s/w Bild als ausgangsbild funktioniert alles wunderbar ... hingegen bei einem farbbild wird nur das 1. viertel bearbeitet ...
Die Anwort ist ganz klar : dein Code ist fehlerhaft.
(Und ich hoffe du verstehst die Anspielung)bis bald
akari
-
Ein SW-Bild (oder allgemein 8 bit, 256 Graustufen/Farben) hat 1 Byte pro Pixel, ein Farbbild (32bit, 16.7 Mio Farben) eben 4 Byte pro Pixel.
ScanLine ist die schnellste Variante, die die VCL bietet. Ob die WinAPI (BitBlt o.ä.) da mehr leistet kann ich nicht sagen, das wäre vielleicht eine Frage für's Spiele/Grafik-Forum hier. Bei Bedarf verschiebe ich dich gern dorthin.
/Edit: getrödelt ...
-
akari schrieb:
Die Anwort ist ganz klar : dein Code ist fehlerhaft.
(Und ich hoffe du verstehst die Anspielung)Beziehst du dich auf den Code?
for (int x = 0; x < Image1->Width; x++) for (int y = 0; y < Image1->Height; y++) Image1->Canvas->Pixels[x][y]++;Dass der nicht geht is mir auch klar ... leider habe ichs nur zu spät gemerkt ... ich habe gedacht man versteht meine Zielstellung trotzdem ...
Möglicherweise wäre ich tatsächlich in einem anderem Forum besser aufgehoben aber ob nu das WinAPI oder spiele/grafik weiß ich nicht so recht ... mit BCB hat mein Problem nicht viel zu tun!
-
Hallo
Ja ich meinte den Code... das du den hier mal posten sollst. Und zwar allen relevanten und nur den.
Ich glaube das Jansen recht hat mit der Farbtiefe. Bei einem Grau-Bild liest du pro Piexel 1 Byte. Bei einem 32-bit Bild must du aber 4 byte pro Pixel lesen. Machst du das nicht bearbeitest du in der Tat nur 1/4 des Bildes (Auf Scanline bezogen... bei Zugriff über Pixels[][] sollte das nicht auftreten).Möglicherweise wäre ich tatsächlich in einem anderem Forum besser aufgehoben aber ob nu das WinAPI oder spiele/grafik weiß ich nicht so recht ...
Je nachdem ob du beim reinen Betriebssystem bleiben willst (WinAPI) und auf Basis von reinem C alles selber optimieren willst oder mit extra Bibliotheken (DirectX...) arbeiten und die eventuell schon vorhandenen optimierten Sturkturen benutzen willst.
bis bald
akari
-
akari schrieb:
Ich glaube das Jansen recht hat mit der Farbtiefe. Bei einem Grau-Bild liest du pro Piexel 1 Byte. Bei einem 32-bit Bild must du aber 4 byte pro Pixel lesen. Machst du das nicht bearbeitest du in der Tat nur 1/4 des Bildes (Auf Scanline bezogen... bei Zugriff über Pixels[][] sollte das nicht auftreten).
Pixels[][] funktioniert auch prima ... lediglich der hohe Zeitfaktor ist der Grund, warum diese Möglichkeit ausscheidet.
Hier mal mein Code:
Graphics::TBitmap *pOriginalBitmap = new Graphics::TBitmap(); Graphics::TBitmap *pNewBitmap = new Graphics::TBitmap(); Byte *ptrOriginal; Byte *ptrNew; pOriginalBitmap->Assign(Image1->Picture); pNewBitmap->Assign(Image1->Picture); DWORD t = ::timeGetTime(); try { for (int y = 0; y < pOriginalBitmap->Height; y++) { ptrOriginal = (Byte *)pOriginalBitmap->ScanLine[y]; ptrNew = (Byte *)pNewBitmap->ScanLine[y]; for (int x = 0; x < pOriginalBitmap->Width; x++) ptrNew[x] = 0xFFFFFF-(Byte)ptrNew[x]; } } catch (...) { ShowMessage("Bitmap konnte nicht geladen oder geändert werden!"); } Form1->Caption = (::timeGetTime() - t) / 1000.0; Form1->Caption = Form1->Caption + " " + IntToStr(pNewBitmap->PixelFormat); Image2->Canvas->Draw(0,0,pNewBitmap); delete pNewBitmap; delete pOriginalBitmap;Liebe Grüße!
-
Hallo
Genau das Problem das Jansen angesprochen hat, in dieser Schleife
for (int x = 0; x < pOriginalBitmap->Width; x++) ptrNew[x] = 0xFFFFFF-(Byte)ptrNew[x];Und selbt die Behandlung von einem Byte ist unsauber. 0xFFFFFF entspricht 4 (es gibt keine 3 Byte-Datentypen) Bytes, und du ziehst davon eine Zahl der Breite 1 Byte ab. Daraus wird natürlich eine 4 Byte Zahl, die erst wieder zurückgecastet werden muß wenn es wieder ins Array zurückgeschrieben wird (zu deinem Glück werden dazu ddas 'unterste' Byte genommen, deshalb merkst du davon nichts)
1 Byte reicht aber gerade mal für 255 Werte.. und entspricht damit genau einem Farbkanel bzw. Schwarz-Weiß. Wenn du also nun ein Bild mit 32-bit Farbtiefe (3 Farbkanäle + 1 Alpha/Müll) einliest kann das gar nicht richtig funktionieren. Den nun hast du durch Scanline ein Array bekommen das pro Pixel 4 Bytes beinhaltet. Da du aber trotzdem nur 1 Byte pro Pixel liest bearbeitet deine Funktion grade mal 1/4 der Bildbreite.
Also must du erstmal aus der Eigenschaft TBitmap::PixelFormat auslesen wieviel Bytes pro Pixel verwendet werden. Dann must du darauf hin die Ausleseschleife anpassen.bis bald
akari
-
Vielen Dank für die Erklärung ... das habe ich verstanden

Ich habe den Code jetzt so abgeändert:
class CMaske { public: int x; int y; float **data; CMaske(TStringGrid *StringGrid) : x(StringGrid->ColCount), y(StringGrid->RowCount) { data = new float*[x]; for (int i = 0; i < x; i++) data[i] = new float[y]; for (int i = 0; i < x; i++) for (int j = 0; j < y; j++) data[i][j] = StrToFloat(StringGrid->Cells[i][j]); } ~CMaske() { for (int i = 0; i < x; i++) delete[] data[i]; delete[] data; } }; #include "mmsystem.h" void __fastcall TForm1::Button2Click(TObject *Sender) { bool negatig = CheckBox1->Checked; CMaske maske(StringGrid1); Graphics::TBitmap *pOriginalBitmap = new Graphics::TBitmap(); Graphics::TBitmap *pNeuBitmap = new Graphics::TBitmap(); RGBTRIPLE *ptrOriginal; RGBTRIPLE *ptrNeu; Graphics::TBitmap* BildQuelle; Graphics::TBitmap* BildZiel; pOriginalBitmap->Assign(Image1->Picture); pNeuBitmap->PixelFormat = pOriginalBitmap->PixelFormat; pNeuBitmap->Palette = pOriginalBitmap->Palette; pNeuBitmap->Height = pOriginalBitmap->Height; pNeuBitmap->Width = pOriginalBitmap->Width; int rcolor; int gcolor; int bcolor; DWORD t = ::timeGetTime(); try { for (int y = 0; y < pOriginalBitmap->Height; y++) { ptrOriginal = static_cast<RGBTRIPLE*>(pOriginalBitmap->ScanLine[y]); ptrNeu = static_cast<RGBTRIPLE*>(pNeuBitmap->ScanLine[y]); for (int x = 0; x < pOriginalBitmap->Width; x++) { unsigned char rcolor = 0; unsigned char gcolor = 0; unsigned char bcolor = 0; for (int a = 0; a < maske.x; a++) for (int b = 0; b < maske.y; b++) if (x - maske.x/2 >= 0 && x + maske.x/2 < pOriginalBitmap->Width && y - maske.y/2 >= 0 && y + maske.y/2 < pOriginalBitmap->Height) { RGBTRIPLE *ptrHilfe = static_cast<RGBTRIPLE*>(pOriginalBitmap->ScanLine[y - maske.y/2 + b]); rcolor += ptrHilfe[x - maske.x/2 + a].rgbtBlue * maske.data[a][b]; gcolor += ptrHilfe[x - maske.x/2 + a].rgbtGreen * maske.data[a][b]; bcolor += ptrHilfe[x - maske.x/2 + a].rgbtRed * maske.data[a][b]; } ptrNeu[x].rgbtBlue = rcolor; ptrNeu[x].rgbtGreen = gcolor; ptrNeu[x].rgbtRed = bcolor; } } } catch (...) { ShowMessage("Bitmap konnte nicht geladen oder geändert werden!"); } Form1->Caption = (::timeGetTime() - t) / 1000.0; Image2->Canvas->Draw(0,0,pNeuBitmap); delete pNeuBitmap; delete pOriginalBitmap; }.. aber das dauert so verdammt lange, dass es z.b. für Videos in Echtzeit ungeeignet ist...
Gibt es also noch eine Möglichkeit, die schneller ist?
Liebe Grüße!