1. Sergey Astanin
  2. unplot.py


unplot.py / unplot.py

#!/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

  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

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

if __name__ == '__main__':
    opts, args = getopt(sys.argv[1:], "hs:")
    opts = dict(opts)

    if "-h" in opts: usage()

        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 = imap(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