Entwickler-Ecke
Dateizugriff - Delphi 3: Dynamisches zweidim. Array in Datei speichern
Juniorsatan - Sa 27.02.10 23:50
Titel: Delphi 3: Dynamisches zweidim. Array in Datei speichern
Ich habe ein Problem dabei, ein zweidimensionales Array mit Delphi 3 in eine Datei zu speichern.
Normalerweise würde ich das über Konstanten lösen, da dynamische Arrays erst ab Version 5 wirklich unterstützt werden.
Quelltext
1: 2: 3: 4: 5: 6:
| const i = 10000; j = 10000;
var tabelle2: array[1..i, 1..j] of Integer; |
Das Problem, die Aufgabe meines Programmes ist Bildkompression, mir kommt es also auf die Dateigröße an, die dabei herauskommt. Um genauer zu werden: Prinzipiell wird in dem 2dim. Array ein Bild gespeichert, bzw. die Farbwerte jedes einzelnen Pixels (ähnlich wie es der Bitmapdatentyp schon tut). Da sich die Bildgröße unterscheidet, hat das zu speichernde Array keine fixe Größe.
In meinem späteren Programm sollen anstatt der absoluten Werte dann die Differenzen zum benachbarten Pixel stehen, dass ist der Hintergrund meiner Kompressionsmethode, dass Programm errechnet daraus dann wieder die absoluten Werte und stellt das Bild dar.
Welche weiteren Möglichkeiten gibt es prinzipiell, Daten mit solch einem Hintergrund zu speichern? Außer dieser Methode haben ich schulischerseits nur noch das Speichern von linearen Listen mit auf den Weg bekommen, andere Methoden sind mir fremd. Ich weiß jedoch nicht, inwiefern die Speicherung von linearen Listen bei Delphi effizient genug ist, damit ein Kompressionserfolg zu verzeichnen ist.
Dank im voraus.
jaenicke - So 28.02.10 01:03
Um da wirklich schnell arbeiten zu können reserviere dir einfach eine entsprechende Menge Speicher und greife direkt darauf zu.
Dann kannst du direkt mit Pointern arbeiten und hast direkten Zugriff auf die Daten.
Die Speicherung in der Datei hat mit der Datenstruktur im Arbeitsspeicher aber nichts zu tun. In die Datei kannst du das ja unabhängig davon in einen Stream speichern wie du es gerne hättest im Dateiformat.
Astat - So 28.02.10 01:33
Juniorsatan hat folgendes geschrieben : |
| Ich habe ein Problem dabei, ein zweidimensionales Array mit Delphi 3 in eine Datei zu speichern. |
Hallo Juniorsatan, das Speichern kann auf diese Art erfolgen.
Jedoch solltest du wegen der Performance, es in etwa so aufbauen, wie jaenicke schon geschrieben hat.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| const i = 10000; j = 10000;
var tabelle2: array[1..i, 1..j] of Integer;
procedure TForm1.Button1Click(Sender: TObject); var k, l, m: integer; ms: TMemoryStream; begin m := 1; for k := 1 to i do begin for l := 1 to j do begin tabelle2[k, l] := m; inc(m); end; end;
ms := TMemoryStream.Create; ms.Write(tabelle2, i * j * 4); ms.SaveToFile('d:\ausgabe\test.dat'); ms.Free;
ZeroMemory(@tabelle2, i * j * 4);
ms := TMemoryStream.Create; ms.LoadFromFile('d:\ausgabe\test.dat'); ms.Read(tabelle2, i * j * 4); ms.Free;
end; |
lg. Astat
Juniorsatan - So 28.02.10 02:37
Ich danke euch erstmal unglaublich für die Antworten, sie helfen mir super weiter.
Das mit dem Speichern über Streams sieht nach ner richtig guten Sache aus.
In einem Tutorial las ich, dass man bei Recordvariablen jedes einzelne Element auch einzeln speichern muss. Bei Arrays, insbesondere bei zweidimensionalen Arrays ist dies nicht der Fall, wenn ich die Zeile
Quelltext
1:
| ms.Write(tabelle2, i * j * 4); |
von dir richtig verstehe?!
Zwei weitere Fragen habe ich außerdem noch:
Wie kommst du bei der Größe des zweidim. Arrays auf den Term ' i * j * 4?
' i * j ' für die Tabellengröße ("Spalte * Zeilen") und 4 für die Integervariable m?
Würde ein sizeof(tabelle2) genauso gut funktionieren?
Somit belegt jede Integervariable beim Speichern in der Datei den gleichen Speicherplatz, egal wie groß die darin zu speichernde Zahl ist? eine 0 also genauso viel wie eine 255? Wenn ich mir das jetzt weiter vorstelle heißt das im Endeffekt, dass mein Kompressionsalgorithmus gar nicht funktioniert, da genau dieser ja darauf abzielt, dass die erzielten Differenzen zwischen 2 Pixeln kleinere Zahlen sind als die absoluten Zahlen. Liege ich mit der Annahme richtig?
platzwart - So 28.02.10 05:59
Juniorsatan hat folgendes geschrieben : |
| Wenn ich mir das jetzt weiter vorstelle heißt das im Endeffekt, dass mein Kompressionsalgorithmus gar nicht funktioniert, da genau dieser ja darauf abzielt, dass die erzielten Differenzen zwischen 2 Pixeln kleinere Zahlen sind als die absoluten Zahlen. Liege ich mit der Annahme richtig? |
Richtig, es wird so nicht funktionieren!
Juniorsatan - So 28.02.10 11:04
Und wie würde es funktionieren?
Die zu speichernden Zahlen ins Binärsystem umwandeln und inkl. Trennzeichen in einem String speichern? Und diesen Dann im Stream speichern? Das sollte Platzersparnis bringen, oder?
jaenicke - So 28.02.10 13:13
Juniorsatan hat folgendes geschrieben : |
| Die zu speichernden Zahlen ins Binärsystem umwandeln und inkl. Trennzeichen in einem String speichern? Und diesen Dann im Stream speichern? Das sollte Platzersparnis bringen, oder? |
Ja, sicher, das geht. So komprimierst du dann z.B. einen Integerwert von 4 Byte in 32 Byte... Denn jeder Buchstabe im String ist schließlich 1 Byte...
Juniorsatan - So 28.02.10 13:52
Na das wird ja immer besser.
Und wie stelle ich es dann am Besten an, um die Kompression wirklich zu erhalten? Gibt es eine Möglichkeit, die Zahl konkret im Binärsystem zu speichern, die auch nur soviel Speicherplatz verbraucht, wie sie in Anspruch nimmt?
Kha - So 28.02.10 13:59
Das geht schon, aber dann brauchst du jeweils mindestens zwei zusätzliche Bits, um dann die Bytelänge des nachfolgenden Integers zu speichern.
Mal ganz grundsätzlich: Was erwartest du dir denn von deiner Kompression? Die Differenz von zwei 3-Byte(24-Bit)-Farben wird in 99% der Fälle wieder 3 Byte belegen, oder wie oft besitzen benachbarte Pixel gleiche Rotwerte? Mit dem Ansatz wird das Bild also unter Garantie lediglich größer.
Juniorsatan - So 28.02.10 14:13
Das Programm soll keinen reellen Nutzen haben. Es ist Teil meiner Abiturprüfung und soll lediglich meine Fähigkeiten im Fach Informatik darlegen. Mein Lehrer segnete das ab und meinte, dass wär für mich im Bereich des Machbaren.
Im Moment sieht es eher anders aus und das macht mich ein wenig unruhig. Ich ging mit der falschen Annahme heran, dass die Zahlen binär "einfacher" gespeichert werden können und sich die Differenz größer bemerkbar macht.
Jetzt wurde mir quasi der Wind aus den Segeln genommen und ich weiß nicht mehr wirklich weiter.
Horst_H - So 28.02.10 15:17
Hallo,
dann such doch mal nach RLE Run length encoding als Alternative.Dabei werden aber nur gleiche Farben zusammengefasst.
http://www.stefan-baur.de/cs.algo.rle1.html?glstyle=2006
Das geht gut bei Bildschirminhalten von Komputern, da dort große Flächen eine Farbe haben, aber nicht bei detaillreichen/Farbreichen(rauschen) Fotos.
Da war mal ein Problem den Bildschirminhalt des einen Rechners, auf einem anderen per Netzwerk zu übertragen ( Remote Control ähnlich ).Da ist die Bandbreite ja beschränkt ( meist beim Hochladen )
http://www.delphi-forum.de/viewtopic.php?t=55660&highlight=rle
Gruß Horst
Juniorsatan - So 28.02.10 19:12
Das macht das Bitmap-Format auch, ich würde also im Vergleich keinen Speicherplatz gewinnen.
Ach man.
Kha - So 28.02.10 19:40
Nö, BMP ist normalerweise überhaupt nicht komprimiert.
Juniorsatan - So 28.02.10 19:47
| Zitat: |
| Windows-Bitmaps werden entweder unkomprimiert oder verlustfrei mit RLE-Komprimierung (Lauflängenkodierung) gespeichert. Dies ist ein eher schwaches Verfahren, sodass BMP-Dateien wesentlich größer sind als andere Formate wie PNG und kaum für das World Wide Web genutzt werden. |
Quelle:
http://de.wikipedia.org/wiki/Windows_Bitmap
Wer hat nun Recht? Die Bilder, die ich zur Verfügung stehen habe, sind größer als Länge * Breite * 3 Bytes, was ich mir nur durch RLE-Komprimierung erklären kann.
Kha - So 28.02.10 20:46
Wie gesagt,
normalerweise - dass das nur für 4- und 8-bpp-Bilder funktioniert, sollte zeigen, dass BMP grundsätzlich als unkomprimiertes Format gedacht ist :) .
So oder so wirst du mit deinem Verfahren wohl kaum RLE schlagen können, aber vielleicht kannst du beide kombinieren ;) ...
| http://de.wikipedia.org/wiki/Portable_Network_Graphics#Vorfilter hat folgendes geschrieben: |
Um die Kompression der Bilddaten zu verbessern, unterstützt das PNG-Format verschiedene sogenannte Vorfilter, die auf die Bilddaten angewendet werden, bevor die eigentliche Komprimierung stattfindet.
In vielen Bildern unterscheiden sich benachbarte Pixel nur wenig voneinander. Das bedeutet, dass die Differenzwerte dieser Pixel vom Betrag her recht klein sind. Werden nun statt der originalen Pixeldaten die Differenzwerte zu den vorangegangenen Pixeln verarbeitet, treten oft Folgen gleicher Werte auf; große Änderungen kommen nur relativ selten vor (etwa an Objektkanten). Dies begünstigt die Komprimierbarkeit der Daten und ist einer der Gründe für die geringe Größe von PNG-Dateien. |
Juniorsatan - So 28.02.10 20:51
Um den von dir zitierten Effekt zu erzielen (was ich ja auch vorhatte :)), müsste ich wissen, wie ich Zahlen mit Delphi so speichern kann, dass kleinere Zahlen auch wirklich weniger Speicherplatz belegen. Als Integervariable ist dies nicht der Fall und als String in Binärformat auch nicht. Kannst du mir einen Tipp geben?
Horst_H - So 28.02.10 21:38
Hallo,
bei den ganzen Überlegungen nicht vergessen, in welchem pixelformat man arbeitet.
Bei RGB15/16/24 oder 32 Bit macht es wenig Sinn zwei aufeinanderfolgende Bytes auf Gleicheit zu testen, sondern aufeinanderfolgende Farbpunkte.
Also erst in einheitliches Format und dann loslegen.
In dem Link von Stefan Baur war auch ein RLE32 angegeben.
Gruß Horst
Kha - So 28.02.10 22:38
Juniorsatan hat folgendes geschrieben : |
| Um den von dir zitierten Effekt zu erzielen (was ich ja auch vorhatte :))[...] |
Das ist aber nicht, was ich zitiert habe ;) . Du wolltest doch die Differenzen berechnen, um "kleine Integer" zu schaffen, was ich nach wie vor für nicht sinnvoll halte :) . Im Zitat geht es aber darum, dadurch mehr Wiederholungen für RLE bzw. im Fall von PNG dessen großen Bruder LZ77 zu erreichen.
Juniorsatan - Sa 06.03.10 18:36
Die Idee mit Laufzeilenkodierung ist soweit gut umgesetzt, ich frage mich aber immernoch wie ich dieses am effizientesten dann in einer Datei speichern kann.
Mir fehlt dabei leider das Wissen. mein Programm zielt darauf ab, dass es dann das Pixel + Markierungszeichen + Anzahl der Wiederholungen speichert. In einem String ist es ja nachwievor ineffizient, richtig? Wenn fünf schwarze Pixel nebeneinander stehen, wäre das dann sowas wie FFFFFF@5 . Die 6 F symbolisieren [255, 255, 255], dass @ ist der Markierer, der anzeigt dass die nachfolgende Zahl eine Wiederholung ist und dann kommt die Anzahl der Wiederholungen (5). Danach würde es mit dem nächsten Pixel weitergehen. Ist das so umzusetzen und zu speichern?
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!