Laden...

Wie kann ich große Datenmengen effizient auf Bild/Panel zeichnen?

Erstellt von Limnfo vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.371 Views
L
Limnfo Themenstarter:in
20 Beiträge seit 2017
vor 6 Jahren
Wie kann ich große Datenmengen effizient auf Bild/Panel zeichnen?

Hallo!

Ich habe folgendes Problem:
Ich möchte ein sehr großes Bild in ein Bitmap oder auf ein (Windows Forms-) Panel zeichnen.
Das resultierende Bild kann extrem groß werden (zb. 50.000 x 2048 px, oder noch größer).
Wie man anhand dieser Ausmaße sehen kann, ist das bereits zu groß für ein Bitmap-Objekt.

Wie komme ich zu den Daten, bzw. zu der Bildgröße?
Es handelt sich um bis zu 50.000 Datensätze, welche eine Länge von ca. 2048 Byte haben können. Jeder Datensatz wäre würde eine Spalte im Bild einnehmen, jedes Byte jedes Datensatzes dann eine Zeile. Angenommen, jede Spalte ist ein Pixel breit, dann wäre jede Zeile, dessen korresponierendes Byte den Wert 0x00 hat, zb. weiß, der Rest zb. grau. Zoomt man nun das Bild, dann codiert jedes Byte, welches nicht 0x00 und nicht 0xFF ist entsprechend des Bitmusters pro Bit für weiß oder grau. Je nachdem wie detailliert ich das Bild also zeichne, desto größer kann das Bild werden...

Wie habe ich es derzeit gelöst?
Momentan zeichne ich sämtliche Daten auf ein Bitmap. Dieses ist, um bei den obigen Angaben zu bleiben, zb. 50.000 x 2048 px groß. Das Bitmap wird in einer WindowsForm in einer Picturebox angezeigt, sodass ich es scrollen kann. Es ist möglich, das Bild zu "zoomen", indem man einen Wert eingeben kann, wie hoch ein Byte gezeichnet wird. Das funktioniert mit Werten zwischen 1 und 5, ab dann bekomme ich meistens natürlich eine OutOfMemoryException... Aus diesem Grund biete ich eine "Zoomfunktion", welche das Bild breiter macht, gar nicht erst an.

Meine Fragen:
gibt es eine Möglichkeit das Problem eleganter und effizienter zu lösen? Das Bitmap benutze ich derzeit eigentlich nur, um einerseits scrollen zu ermöglichen und andererseits nicht nach jedem scroll-Vorgang das Bild neu zu zeichnen. Der Zeichenvorgang nimmt derzeit nur ca. 1-2 Sekunden in Anspruch, das wäre kein Problem. Was ich aber auf jeden Fall gerne erreichen würde, wäre eine Zoom-Funktion - sowohl horizontal als auch vertikal - um eine Detailansicht der Daten zu ermöglichen.
Ich habe bereits etwas im Kopf, aber ich weiß nicht, ob das so sinnvoll, möglich bzw. überhaupt schnell genug ist.
Wäre es unter Umständen sinnvoller, die Paint-Methode zu überschreiben, sodass diese jedes Mal nur jenen Bereich der Daten zeichnet, der aktuell angezeigt gehört? Also zum Beispiel bei einer Panel-Größe von 1000 x 500 px und einem Zoom von 1.0 jeweils die ersten 500 Byte der ersten 1.000 Datensätze. Wie aber könnte ich dann das Bild nach rechts oder unten scrollen? Kann sich jemand vorstellen, wie zeitintensiv das wäre? Zahlt sich das aus, oder hätte man jedes mal längere Wartezeiten?
Fällt sonst jemanden etwas ein, was ich hier tun, oder wo ich weiter recherchieren könnte?

Vielen Dank schonmal im Voraus!
Limnfo

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

da man ja nicht alles selbst machen muss - willst du eventuell mal folgende Komponente testen?: A Zoomable and Scrollable PictureBox

Erfüllt ja scheinbar all deine Anforderungen.

Was das Zeichnen angeht - wenn das Ganze nur 1-2 Sekunden dauert und auch nicht übermäßig riesig im Arbeitsspeicher wird - würde ich es an deiner Stelle so lassen. Nur weil das Bitmap so groß ist heißt das ja nicht, dass die PictureBox auch alles auf den Bildschirm malt - ähnlich wie die von mir verlinkte Komponente.

Halte 1-2 Sekunden beim Start für absolut vertretbar, solange sicher gestellt ist, dass das Bild nicht unendlich größer werden kann. Zumal danach ja quasi alles flutschen sollte.

LG

L
Limnfo Themenstarter:in
20 Beiträge seit 2017
vor 6 Jahren

Hallo,

vielen Dank für den Tipp, werde mir das mal ansehen.

Allerdings müsste ich dazu das Bild vorerst mal in größter Detailstufe zeichnen und da befürchte ich, dass mir relativ bald mein RAM ausgehen wird. Bereits jetzt deutet ja die OutOfMemoryException bei zu großen "Zoomfaktoren" darauf hin...

LG

D
985 Beiträge seit 2014
vor 6 Jahren

Google Maps haben da ein ähnlich gelagertes Problem und die lösen das mit Kacheln

L
Limnfo Themenstarter:in
20 Beiträge seit 2017
vor 6 Jahren

Aber ein großes Bitmap-Objekt braucht sicher weniger RAM als zB. 200 (Kacheln), oder nicht?

5.658 Beiträge seit 2006
vor 6 Jahren

Hi Limnfo,

du brauchst ja nur die Kacheln zu erzeugen, die du für die Anzeige gerade benötigst. Und es ist besser, viele kleine Bilder im Speicher zu haben, als ein großes. Und ein 50000 x 2048 Pixel großes Bitmap ist sowieso unrealistisch.

Zwischenspeichern mußt du eh nur, wenn das Zeichnen zu lange braucht. Ich nehme mal an, daß du die Daten annähernd in Echtzeit auf die Form zeichnen kannst, wenn du einigermaßen effiziente Algorithmen dafür verwendest. Zum Zeichnen empfehle ich diese Anleitung: [Tutorial] Zeichnen in Windows-Forms-Programmen (Paint/OnPaint, PictureBox).

Zum Scrollen stehen dir unter Windows Forms Scrollbars zur Verfügung. Du mußt halt nur den aktuellen Bildausschnitt und die aktuelle Zoomstufe in deine Berechnung mit einbeziehen.

Weeks of programming can save you hours of planning

L
Limnfo Themenstarter:in
20 Beiträge seit 2017
vor 6 Jahren

Hallo!

vielen Dank für den Tutorial-Link, dieser hilft mir sicher weiter.

Also dann fasse ich das mal so zusammen:
Entweder ich versuche das Bild halbwegs intelligent auf mehrere Kacheln aufzuteilen, welche jeweils nur den aktuellen Ansicht-Ausschnit enthalten und vll einen gewissen Bereich runderhum, ähnlich zu Google Maps. Jedes Mal, wenn dann die Ansicht verschoben oder gezoomt werden würde, müsste ich dann die entsprechenden Kacheln neu zeichnen.

Oder aber ich halte mich an die Tuturial-Anleitung und versuche meine etwas schwammige Idee auszufeilen und mir eine Logik zu überlegen, sodass ich den jeweils anzuzeigenden Bereich direkt auf ein Panel zeichne, welches mittels Scrollbars (und eigenen Buttons) verschiebbar (und zoombar) ist.

Ich werde das nächste Woche mal ausprobieren und mich dann wieder melden!
Vielen Dank erstmal für eure Hilfe!

LG Limnfo

L
Limnfo Themenstarter:in
20 Beiträge seit 2017
vor 6 Jahren

Hallo,

hier bin ich mit der versprochenen Rückmeldung!

Habe mich für Variante 2 entschieden, die die OnPaint-Methode überschrieben und mit einer eigenen Logik versehen, sodass nur jeweils jener Bereich gezeichnet wird, welcher auch gerade angesehen wird.
Es funktioniert großartig! Man merkt wohl, wenn man scrollt oder nach der Minimierung des Fensters dieses wieder maximiert, dass es einen kurzen Augenblick dauert, bis die Daten gezeichnet sind, das ist aber vollkommen klar und nicht weiter störend!

Ich danke euch jedenfalls für die nützlichen Links, bzw Ideen und Kommentare!

LG Limnfo