Commits

Sergey Astanin  committed bbd8546

unplot.py: utility to extract tabular data from plots

  • Participants

Comments (0)

Files changed (1)

+#!/usr/bin/env python
+
+"""Convert plot image to tabular data. Inverse operation of plotting.
+
+Usage: unplot.py [options] COLOR x1 x1_px y1 y1_px x2 x2_px y2 y2_px image.png
+
+where
+  COLOR is HTML color of the line to match, e.g. #ff0000 for red
+  (x1_px, y1_px) are coordinates of the lower left corner of the scan area
+  (x2_px, y2_px) are coordinates of the upper right corner of the scan area
+  (x1, y1) and (y1, y2) are real-world quantities corresponding to lower left
+                        and to upper right corners of scan area
+
+options:
+      -h                this message
+      -s NUMBER         acceptable color difference in %  [default: 10%]
+"""
+
+import sys
+
+from getopt import getopt
+from operator import itemgetter
+from itertools import imap, ifilter
+
+from PIL import Image
+
+def html_to_rgb(colorstring):
+    """Convert #RRGGBB to an (R, G, B) tuple.
+    Source: http://code.activestate.com/recipes/266466/"""
+    colorstring = colorstring.strip()
+    if colorstring[0] == '#': colorstring = colorstring[1:]
+    if len(colorstring) != 6:
+        raise ValueError, "input #%s is not in #RRGGBB format" % colorstring
+    r, g, b = colorstring[:2], colorstring[2:4], colorstring[4:]
+    r, g, b = [int(n, 16) for n in (r, g, b)]
+    return (r, g, b)
+
+def color_diff(color1, color2):
+    """Relative difference between two colors."""
+    paired = zip(color1, color2)
+    diff = map(lambda (x,y): abs(x-y)/255.0, paired)
+    return sum(diff)/len(paired)
+
+def usage(where=sys.stdout,msg=None):
+    if msg:
+        print >>where, msg
+    print >>where, __doc__
+    if where == sys.stdout:
+        sys.exit(0)
+    else:
+        sys.exit(1)
+
+if __name__ == '__main__':
+    opts, args = getopt(sys.argv[1:], "hs:")
+    opts = dict(opts)
+
+    if "-h" in opts: usage()
+
+    try:
+        color, x1, x1p, y1, y1p, x2, x2p, y2, y2p, imgfile = args
+    except ValueError:
+        usage(sys.stderr, "Wrong number of arguments: %d" % len(args))
+
+    sensitivity = int(opts.get("-s",10))
+    color = html_to_rgb(color)
+    x1, y1, x2, y2 = map(float, [x1, y1, x2, y2])
+    x1p, y1p, x2p, y2p = map(int, [x1p, y1p, x2p, y2p])
+    xscale, yscale = (x2-x1)/(x2p-x1p), (y2-y1)/(y2p-y1p)
+
+    im = Image.open(file(imgfile))
+    w, h = im.size
+    for i in xrange(x1p,x2p+1):
+        js = xrange(y1p,y2p-1,-1)
+        pixels = map(lambda j: (j, im.getpixel((i,j))), js)
+
+        def similar(px):
+            j, c = px
+            return color_diff(c,color)*100 < sensitivity
+
+        pixels = ifilter(similar, pixels)
+        pixels = sorted(pixels, key=lambda (j,c): -color_diff(c,color))
+        if pixels:
+            j, c = pixels[0]
+            print (i-x1p)*xscale+x1, (j-y1p)*yscale+y1