Speicheroperationen / Typsicherheit in C++?
-
Hi,
angenommen ich habe ein 8 Bit Graustufen-Image und möchte dieses spiegeln. Dann wäre der Ansatz in C irgend wie der Gestalt, dass ich mir Zugriff auf den Speicher des Bildes verschaffe und die einzelnen 8-Bit-Pixel irgend wie in der Art hier umkopiere:
for (y=0; y<height; y++) for (x=0; x<width; x++) { imgTargetData[x*width+height]=imgSrcData[...]; }Allerdings ist das ganze weder sauberes C++, noch irgend wie typsicher. Deswegen meine Frage: wie würde ich sowas denn "ordentlich" implementieren?
Ach ja, irgend welche Antworten in Richtung "nimm doch Grafikbibliothek xy, die kann Bilder spiegeln", interessieren mich nicht die Bohne, mir geht es um eine prinzipielle Lösung und wie man sowas in vernünftigem C++ realisiert.
Doug!
-
Das ist so schon voll okay.
Eine gewisse Typsicherheit ist ja auch gegeben.
-
Was hast du denn dagegen? Ist doch alles in Ordnung, wenn ich mal gewisse Annahmen über imgSrcData mache, die sicherlich gegeben sind.
-
OK, ich glaube ich sollte meine Frage ein wenig umformulieren. Mir geht es nur um eine rein theoretische Lösung in C++, die muss meiner C-Mem-Poke-Variante weder in Geschwindigkeit noch in Codeaufwand geschweige denn in Lesbarkeit überlegen sein.
Vielleicht ein anderes Beispiel: ich lade eine Tabelle mit Zahlenwerten im Bereich 0..100 von der Platte, die Tabelle hat 5 Spalten und 60 Zeilen. Dort soll jetzt Spalte 1 und Spalte 5 sowie Spalte 2 und Spalte 3 vertauscht werden (also auch wieder eine Spiegelung).
Hier wäre mein C-Ansatz wieder der gleiche: alles in einen Speicherbereich der Größe 5x60 Bytes laden und dann wie im Codebeispiel oben spiegeln. Die Anzahl der Spalten kann dabei fast beliebig varriieren.
-
Die Frage ist, was du damit erreichen möchtest.
So oder so läuft es aber immer darauf hinaus, dass du auf die Daten zugreifst und in anderer Form/Anordnung wieder ablegst.
-
Thopthes schrieb:
Die Frage ist, was du damit erreichen möchtest.
Ich möchte ein theoretisches Lehrbeispiel in C++ erstellen

-
Ist doch alles wunderbar...
Warum sollten Schleifen und entsprechender Array-Zugriff schlechtes C++ sein?
Viel interessanter ist wohl, dass die entsprechenden Bild-Klassen sauber designed sind.
-
also ich würde sagen, das lässt sich so machen:
#include <vector> struct pixel { char r, g, b, a; }; std::vector<pixel> mirror(std::vector<pixel> const & src) { return std::vector<pixel>(src.rbegin(), src.rend()); }Da die Pixel bei dir offenbar ohnehin linear im Speicher liegen, sollte ein simples Umkehren der Reihenfolge genügen (lediglich die Reihenfolge der Farbwerte innerhalb eines Pixels sollte erhalten bleiben ;-)).
Daher sollte selbst bei deinem Ansatz die innere Schleife unnötig sein:for (int n = 0; n < ((width * height) / 2); ++n) target[n] = src[(width * height) - n - 1];Wenn du die Spiegelung "in-place" machen willst, also du das original direkt bearbeiten möchtest, geht auch std::reverse:
#include <vector> #include <algorithm> // mit vector std::vector<pixel> img_vec(width * height); std::reverse(img_vec.begin(), img_vec.end()); // oder mit rohen arrays/zeigern pixel img_arr[width * height]; std::reverse(img_arr, img_arr + (width * height));
-
DrakoXP schrieb:
also ich würde sagen, das lässt sich so machen:
#include <vector> #include <algorithm> struct pixel { char r, g, b, a; }; std::vector<pixel> mirror(std::vector<pixel> const & src) { return std::vector<pixel>(src.rbegin(), src.rend()); }Da die Pixel bei dir offenbar ohnehin linear im Speicher liegen, sollte ein simples Umkehren der Reihenfolge genügen (lediglich die Reihenfolge der Farbwerte innerhalb eines Pixels sollte erhalten bleiben ;-)).
Daher sollte selbst bei deinem Ansatz die innere Schleife unnötig sein:for (int n = 0; n < ((width * height) / 2); ++n) target[n] = src[(width * height) - n - 1];Solange man nur horizontal spiegelt geht das, bei vertical wird man schon zwei Schleifen brauchen. Das hier hab ich mal gemacht um ne art buchstabentabelle zu verschieben, drehen spiegeln. vieleicht hilft es ja weiter.
std::vector<std::vector<char> > m_Matrix; std::vector<std::vector<char> > m_TempMatrix; int m_Rows; int m_Cols; void roll_matrix_right(int Steps) { m_TempMatrix.clear(); std::vector<char> temp; for(int a = 0; a < m_Rows; a++) { temp.clear(); for(int b = 0; b < m_Cols; b++) { if(b - Steps < 0) { temp.push_back(m_Matrix[a][(m_Cols - Steps) + b]); } else { temp.push_back(m_Matrix[a][b - Steps]); } } m_TempMatrix.push_back(temp); } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void roll_matrix_left(int Steps) { m_TempMatrix.clear(); std::vector<char> temp; for(int a = 0; a < m_Rows; a++) { temp.clear(); for(int b = 0; b < m_Cols; b++) { if(b + Steps >= m_Cols) { temp.push_back(m_Matrix[a][(b + Steps) - m_Cols]); } else { temp.push_back(m_Matrix[a][b + Steps]); } } m_TempMatrix.push_back(temp); } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void roll_matrix_up(int Steps) { m_TempMatrix.clear(); for(int a = 0; a < m_Rows; a++) { if(a + Steps >= m_Rows) { m_TempMatrix.push_back(m_Matrix[(a + Steps) - m_Rows]); } else { m_TempMatrix.push_back(m_Matrix[a + Steps]); } } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void roll_matrix_down(int Steps) { m_TempMatrix.clear(); for(int a = 0; a < m_Rows; a++) { if(a - Steps < 0) { m_TempMatrix.push_back(m_Matrix[(m_Rows - Steps) + a]); } else { m_TempMatrix.push_back(m_Matrix[a - Steps]); } } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void flip_matrix_horizontal(void) { m_TempMatrix.clear(); for(int a = m_Rows - 1; a >= 0; a--) { m_TempMatrix.push_back(m_Matrix[a]); } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void flip_matrix_vertical(void) { m_TempMatrix.clear(); std::vector<char> temp; for(int a = 0; a < m_Rows; a++) { temp.clear(); for(int b = m_Cols - 1; b >= 0; b--) { temp.push_back(m_Matrix[a][b]); } m_TempMatrix.push_back(temp); } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void rotate_matrix_right(void) { m_TempMatrix.clear(); std::vector<char> temp; for(int a = 0; a < m_Rows; a++) { temp.clear(); for(int b = m_Cols - 1; b >= 0; b--) { temp.push_back(m_Matrix[b][a]); } m_TempMatrix.push_back(temp); } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); } void rotate_matrix_left(void) { m_TempMatrix.clear(); std::vector<char> temp; for(int a = m_Rows -1; a >= 0; a--) { temp.clear(); for(int b = 0; b < m_Cols; b++) { temp.push_back(m_Matrix[b][a]); } m_TempMatrix.push_back(temp); } m_Matrix.clear(); m_Matrix = m_TempMatrix; m_TempMatrix.clear(); }
-
Videonauth schrieb:
Solange man nur horizontal spiegelt geht das, bei vertical wird man schon zwei Schleifen brauchen.
Ich spiegele diagonal

Horizontal könnte man das so machen:
// sowohl array als auch vector for (int line = 0; line < height; ++line) std::reverse(&(img[line * height]), &(img[line * height + width - 1]));Vertikal ist hier etwas suboptimal, da man nicht ohne weiteres ganze Zeilen vertauschen kann :S
Hier wird man also um die manuelle Variante mit zwei Schleifen kaum herumkommen.
-
TheDoug schrieb:
Thopthes schrieb:
Die Frage ist, was du damit erreichen möchtest.
Ich möchte ein theoretisches Lehrbeispiel in C++ erstellen

Deine Frage ist sinnlos.
Wenn die Vorgaben die selben sind, und die C-Lösung als korrekt zu betrachten ist, dann ist die selbe Lösung in C++ ebenso korrekt.
Wenn es Bytes zu vertauschen gilt, dann vertauscht man eben Bytes.
Und wenn es longs/chars/strings/... statt Bytes sein können, dann muss man erstmal wissen um was es sich handelt.
Man kann nicht einfach so eine "bessere" Lösung in C++ machen, wenn man das "bessere" Problem gar nicht kennt.
-
Allerdings ist das ganze weder sauberes C++, noch irgend wie typsicher. Deswegen meine Frage: wie würde ich sowas denn "ordentlich" implementieren?
Was Du da beschrieben hast ist eine einzelne Methode, die so sauber ist, wie es die Daten sind mit denen Du arbeitest. Wenn Du das ganze "sauber" machen willst, musst Du dafür sorgen, dass Deine Daten sauber sind.
Also eine Klasse aus dem Bildbuffer machen, die die Daten entsprechend kapselt und die Methoden dazu, die dann Deine Operationen implementieren. Dann hast Du einen neuen sauberen Datentyp definiert und das ist etwas, das über den Standard von C hinausgeht.