Autor Beitrag
Juniorsatan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: Sa 27.02.10 23:50 
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.
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 75
Erhaltene Danke: 1

Windows 2000
D6, D7, D2007, Lazarus
BeitragVerfasst: So 28.02.10 01:33 
user profile iconJuniorsatan hat folgendes geschrieben Zum zitierten Posting springen:
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.

ausblenden volle Höhe 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1054
Erhaltene Danke: 78

Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
BeitragVerfasst: So 28.02.10 05:59 
user profile iconJuniorsatan hat folgendes geschrieben Zum zitierten Posting springen:
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!

_________________
Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
Juniorsatan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 28.02.10 13:13 
user profile iconJuniorsatan hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: 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.
www.stefan-baur.de/c...e1.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 )
www.delphi-forum.de/...60&highlight=rle

Gruß Horst
Juniorsatan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: So 28.02.10 19:12 
Das macht das Bitmap-Format auch, ich würde also im Vergleich keinen Speicherplatz gewinnen.
Ach man.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 28.02.10 19:40 
Nö, BMP ist normalerweise überhaupt nicht komprimiert.

_________________
>λ=
Juniorsatan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: 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 ;) ...
de.wikipedia.org/wik...k_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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 28.02.10 22:38 
user profile iconJuniorsatan hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 19



BeitragVerfasst: 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?