Bitmap mit Kurvendiagramm einlesen und in Tabelle umwandeln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hi, ich möchte eine Grafik wie diese in eine Tabelle umwandeln. Dafür möchte ich Spalte für Spalte den jeweiligen Wert der Kurve ermitteln. Muss ich da Pixel für Pixel nach einer bestimmten Farbe suchen oder gibt es Funktionen, die dabei etwas helfen?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Trichter
User
Beiträge: 45
Registriert: Montag 20. April 2009, 10:21

Bei einer Rastergrafik (png, jpg, gif) wird dir wohl nichts anderes übrig bleiben, als die Koordinaten der Punkte mit einer bestimmten Farbe zu suchen und dir daraus eine Kurve zu interpolieren. In dem von dir gezeigten Beispiel kannst du z. B. die Werte der blauen Kurve an den Stellen, wo sie von der roten überdeckt wird gar nicht direkt auslesen.

Bei einer Vektorgrafik (ps, eps, svg) sollte es möglich sein, die Werte direkt aus der Bilddatei mit einer entsprechenden library oder "per Hand" mit einem Skript auszulesen. Da musst du nur in den Formatspezifikationen nachschauen wo und in welchem Format die Daten für die Kurven abgespeichert sind.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Leider habe ich keine Vektorgrafik. Die Diagramme stammen aus PDF Dateien. Die einzige Möglichkeit, die ich habe, ist die PDF Datei zum Beispiel in Gimp zu importieren und in eine Bitmap zu wandeln. Mit dem fehlenden Bereich bei der Überschneidung komme ich klar. Entweder kopiere ich die Kurven in getrennte Grafiken und fülle die Lücke von Hand oder ich mache anschließend im Programm eine lineare Verbindung von einem Endpunkt zum anderen.

Meine Frage ist: gibt es eine einfachere Methode als Pixel für Pixel nach Farbwerten zu suchen? Wenn ja, wie? Vielleicht gibt es ja eine Library mit einer Funktion, die selbst in der Lage ist, eine Spalte zu "Parsen" und die Pixelposition zurückliefert. Wenn die in C geschrieben wäre ginge es deutlich schneller als wenn ich das von Hand in Python mache.

Aber wenn nein, wie dann? Was ist besser dafür geeignet? PIL oder Image Magick? Hab leider bei beiden noch keine Funktion gefunden, um an einem bestimmten Pixel den Farbwert zurückzuliefern
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Am liebsten wäre mir eine Funktion, der ich die gewünschte Spalte und die zu suchende Farbe übergebe und die mir die Position jedes gefundenen Pixels in einer Liste oder Tuple oder was auch immer zurück gibt, da ich sowieso den Mittelwert berechnen will. Wenn mir die Funktion gleich den Mittelwert liefert umso besser
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das sollte doch mit PIL und Numpy schnell gemacht sein. Bild nach gesuchter Farbe filtern, Spaltenweise den Schwerpunkt bestimmen, Spline durchlegen, Werte auslesen und fertig.
Das Leben ist wie ein Tennisball.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

EyDu hat geschrieben:Das sollte doch mit PIL und Numpy schnell gemacht sein. Bild nach gesuchter Farbe filtern, Spaltenweise den Schwerpunkt bestimmen, Spline durchlegen, Werte auslesen und fertig.
Wozu noch einen Spline? Wegen den Lücken?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
BlackJack

@burli: Wie bekommst Du die Bilder eigentlich aus dem PDF heraus? Die Methode in Gimp-Importieren dürfte nicht die verlustfreieste sein sofern die Daten in dem PDF nicht als Vektorgrafik gespeichert sind. Denn dann bekommst Du höchstens mit sehr viel Glück die Pixeldaten 1:1 in der Auflösung wie sie in das PDF eingebettet wurden, sondern eine skalierte Pixelgrafik. Die Pixel so wie sie im PDF gespeichert sind, bekommt man unter Linux (Debian) wohl am einfachsten mit ``pdfimages`` aus dem `xppf-utils`- beziehungsweise aus dem `poppler-utils`-Paket exportiert.

Sollte die Grafik dagegen als Vektorgraphik im PDF stecken kann man das PDF beziehungsweise die Seite mit der Grafik in Inkscape importieren. Da könnte man dann eventuell die beiden Linien sauber voneinander trennen ohne dass es Lücken bei den Überschneidungen gibt.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

@BlackJack: Das PDF, was ich aktuell hab, speichert das wohl als Vektor ab. Aber das kann von Dokument zu Dokument anders aussehen. Deshalb ist die GIMP Methode die einfachste und universellste und funktioniert auch unter Windows.

Und wie bei Inkscape der PDF Import funktioniert weiß ich nicht. Mit "Import" ist mir Inkscape eben jedenfalls heftig abgeschmiert.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

burli hat geschrieben:Wozu noch einen Spline? Wegen den Lücken?
Wegen der Lücken und des Auslesens. Wenn dir natürlich lineare Interpolation reicht und du keine Werte zwischen den "Messungen" haben willst, dann kannst du dir den Schritt natürlich sparen. Da du den Graph diskretisierst, könnte man noch über einen Filter nachdenken, dazu müsste man im Idealfall natürlich das Modell der Messung kennen. Oder du machst es wie ein Igenieur: einfach so lange an den Filterparametern drehen bis es passt :D
Das Leben ist wie ein Tennisball.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ok, vergessen wir mal Splines, Vektoren usw, damit ich mal weiter komme. Gibt es zwischen einfachem Pixel Parsen und Splines noch eine Möglichkeit, den Mittelpunkt der Linie zu finden? Ich will einfach nur für jede Pixelspalte genau einen Wert am Ende heraus bekommen

Wie kann ich "Spaltenweise den Schwerpunkt bestimmen"?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Für einen roten Graphen zum Beispiel so:

Code: Alles auswählen

import Image
import numpy as np
import scipy.ndimage

colorkey = [255, 0, 0]

image = Image.open("graph.png").convert("RGB")
array = np.array(np.asarray(image))

mask = np.logical_and.reduce([(array[:,:,i]==colorkey[i]) for i in range(3)])
rows, cols = mask.shape

out = np.zeros(mask.shape, np.uint8)
for i in range(cols):
    y = scipy.ndimage.measurements.center_of_mass(mask[:,i])[0]
    out[int(y), i] = 255

out = Image.fromarray(out, mode="L")

out.show()
Die (i, y) sind die Werte von Interesse.
Das Leben ist wie ein Tennisball.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Wollte es gerade mal durchlaufen lassen. Bekomme einen ValueError

Code: Alles auswählen

/usr/lib/python2.7/dist-packages/scipy/ndimage/measurements.py:1038: RuntimeWarning: invalid value encountered in double_scalars
  results = [sum(input * grids[dir].astype(float), labels, index) / normalizer for dir in range(input.ndim)]
Traceback (most recent call last):
  File "read.py", line 16, in <module>
    out[int(y), i] = 255
ValueError: cannot convert float NaN to integer
Hab allerdings keine Idee, was der in dem Fall bedeutet
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ganz offensichtlich ist in der Spalte kein Wert enthalten. Da kann man aber auch selber drauf kommen, wenn man sich mal y und i anschaut ;-)

Code: Alles auswählen

for i in range(cols):
    coloumn = mask[:,i]
    
    if coloumn.any():
        y = cog(coloumn)[0]
        out[int(y), i] = 255
Das Leben ist wie ein Tennisball.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Danke, aber es war mein Fehler. Deine erste Version funktioniert, nur der rot Wert hat nicht gestimmt. Es ist nicht 255 sondern nur 192
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ach ja, die blaue Kurve ließt er auch, aber an dem Schnittpunkt produziert er genau den Fehler, den ich erwartet habe. Da dürfte auch mit Splines wenig zu machen sein. Und ich fürchte, dass es bei einigen anderen Grafiken gar nicht funktioniert, weil sich manche Linien über eine noch längere Strecke überlappen.

Also muss ich doch versuchen, die Verktorgrafiken aus dem PDF zu holen
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich habe es gerade mal mit einem kubischen Spline getestet, da kann man bei einfachen Überschneidungen schon einiges rausholen. Es hängt, wie zu erwarten, von der dicke der gezeichneten Linien und dem Schnittwinkel ab, wie gut die Qualität ist. Prinzipiell kann man die Dicke natürlich recht leicht schätzen, ob man das will und ob es nötig ist, ist natürlich eine andere Frage.

Wenn beliebig lange Verdeckungen möglich sind, dann wären natürlich die Vektorgrafiken schon sehr von Vorteil.
Das Leben ist wie ein Tennisball.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ja, aber ich suche verzweifelt nach einem Weg, an die Kurven zu kommen. Ich bin anscheinend nicht der erste, der sich daran versucht. Ich hab es mit Inkscape versucht, aber der importiert die Kurven nur als ein Objekt. Da bin ich genauso weit wie jetzt. Hab es auch mit PDFMiner und PDFEdit versucht, aber auch da kommt ich nicht weit
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das hier könnte dir vielleicht helfen. Das pdf wird zunächst in ein svg umgewandelt und anschließend muss nur noch nach path-Elementen gesucht werden. Die Daten sehen erstmal lesbar aus, scheint aber auch ein wenig davon abzuhängen, wie der Graph erzeugt wurde. Bei einem Paper bei mir war ein Graph enthalten aber nicht zu finden. Ich tippe mal darauf, dass er als eps eingebunden wurde und daher als Ressource irgendwie im pdf liegt - aber nur mal wild geraten ^^ Probiers am besten mal mit deinen pdfs aus.

Nun muss ich aber weiter arbeiten. Oder ich beobachte das Eichhörnchen, welches vor dem Fenster Futter vergräbt ...
Das Leben ist wie ein Tennisball.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich hab leider keinen Adobe Illustrator. Das einzige Programm, mit dem das gehen könnte, wäre Inkscape, aber das importiert wie gesagt alle Kurven in einem Objekt und es scheint auch keine Gruppe zu sein, die man aufteilen könnte.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Bei mir kommt mit Inkscape so etwas raus:

Code: Alles auswählen

<path
           d="m 91.26,295.74 220.8,0 0,-149.64 -220.8,0 0,149.64 z m 13.62,-14.7 194.1,0 0,-115.44 -194.1,0 0,115.44 0,-115.44 1.38,0 m -1.38,16.5 1.38,0 m -1.38,16.5 1.38,0 m -1.38,16.5 1.38,0 m -1.38,16.44 1.38,0 m -1.38,16.5 1.38,0 m -1.38,16.5 1.38,0 m -1.38,16.5 1.38,0 m -1.38,-115.44 194.1,0 m -194.1,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44 m 7.8,-1.44 0,1.44 m 7.74,-1.44 0,1.44"
           inkscape:connector-curvature="0"
           id="path20"
           style="fill:none;stroke:#231f20;stroke-width:0.06;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" />

<path
           d="m 108.78,268.08 7.74,-16.68 7.8,-19.44 7.74,-2.94 7.74,-4.86 7.8,-2.52 7.74,6.78 7.74,0.66 7.8,-2.1 7.74,-4.74 7.8,1.2 7.74,-1.86 7.8,-9.78 7.74,-2.22 7.74,-21.48 7.8,0.9 7.74,0.06 7.8,9.06 7.74,1.56 7.74,-1.44 7.74,0.36 7.8,-3.96 7.74,1.68 7.8,3.06 7.74,1.14"
           inkscape:connector-curvature="0"
           id="path22"
           style="fill:none;stroke:#231f20;stroke-width:0.62599999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" />
Irgendwie müssen die Kurven auch trennbar sein, denn die Farbinformation sollte eine Kurve mehr oder weniger eindeutig identifizieren. Hast du vielleicht ein pdf als Beispiel bei dem es Probleme gibt, da könnte man vielleicht mal einen Blick drauf werfen. Oder eben auf das erzeugte svg.
Das Leben ist wie ein Tennisball.
Antworten