Extracting points from images, plots using IDL
written by joehall@pobox.com

(aka, "I've got this dang figure and can't get access to the original data (or at least not fast enough)... how do I extract the data points from the plot / image?")

So you would like to extract points from a figure and you have access to IDL? Well, you're lucky that I've written the code for it:
http://pobox.com/~joehall/export/extract_points.pro


;+
; NAME:
;	extract_points
;
; PURPOSE:
;
;	To facilitate the extraction of data points from a JPEG figure.
;
; EXPLANATION:
;
;	extract_points is pretty simple.  It reads in a JPEG file,
;	re-sizes it, and then prompts the user to do a bunch of
;	clicking to define the axes and then select points to output.
;
; CALLING SEQUENCE:
;
;	 extract_points, file, out_arr $
;	   [, xsize=XSIZE, retain=RETAIN]
;
; INPUTS:
;
;	file - a simple string that holds the JPEG filename.
;
; OPTIONAL INPUT: 
;
;	xsize - the number of x pixels in the display window (tv) used
;	        for clicking. Practically, his is a limit on the
;	        resolution of your output... the fewer pixels you have
;	        the more of a limit on your resolution.  The maximum
;	        resolution is practically the edge of your screen
;	        (unless you can click of the edge of the screen).  The
;	        default is 640 pixels. The y-size is calculated from
;	        measuring the aspect ratio of the inputted image so
;	        there is no need for a 'ysize' input.
;
;	retain - this is just used for the window initialization.  If
;	         you are using the program and find chunks taken out
;	         of your display window when you go back and forth,
;	         set this to two (retain=2).
;
; OUTPUT:
;
;	out_arr - a n x 2 floating point array with n being the number
;	          of points the user clicked on.  The other dimensions
;	          are x and y values respectively (that is,
;	          out_arr[*,0] is all x-values...)
;
; OPERATIONAL NOTES:
;
;	-There's no provisioning for logarithmic axes yet.  I'm sure
;         someone could add this...
;
; PROCEDURES CALLED:
;
;	read_jpeg, congrid(), window, tv, print, cursor, read, sort(),
;	poly(), fltarr().
;
; REVISION HISTORY:
;       Written by:  Joseph Lorenzo Hall, 18 Feb 2003.
;		    Copyright (c) Joseph Lorenzo Hall 2003
;       Modified to handle 24-bit JPEGs; JLH 18 Feb 2003.
;
;###########################################################################
;
; LICENSE
;
;    This program is free software; you can redistribute it and/or
;    modify it under the terms of the GNU General Public License as
;    published by the Free Software Foundation; either version 2 of the
;    License, or (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;    General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program; if not, write to the Free Software
;    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
;    02111-1307 USA
;
;    If the Internet and WWW are still functional when you are using
;    this, you shold be able to access the GPL here: 
;    http://www.gnu.org/copyleft/gpl.html
;-

pro extract_points, file, out_arr, xsize=XSIZE, retain=RETAIN

read_jpeg, file, im			      ;READ IN JPEG
;stop

;RESIZE AND DISPLAY JPEG
if n_elements(xsize) ne 1 then $
   x_pix = 640 else x_pix=xsize			;SET WINDOW SIZE
im_sz = size(im)				;GET IMAGE DIMENSIONS
jpg_type = im_sz[0]

if jpg_type eq 2 then begin			;8-BIT, 16-BIT
im_sz = size(im,/dim)
aspect = float(im_sz[1]) / float(im_sz[0])	;ASPECT RATIO
new_im = congrid(im,x_pix,x_pix*aspect)		;RESIZE IMAGE
endif

if jpg_type eq 3 then begin			;24-BIT
im_sz = size(im,/dim)
aspect = float(im_sz[2]) / float(im_sz[1])	;ASPECT RATIO
new_im = $
    congrid(im,im_sz[0],x_pix,x_pix*aspect)	;RESIZE IMAGE
endif

if (jpg_type ne 2) and (jpg_type ne 3) then message, $
'This program does not know what format your JPEG is in.'

window, retain=retain, xsize=x_pix, $	;OPEN A SIZED WINDOW
	ysize=x_pix*aspect 

CASE StrUpCase(!D.Name) OF		;FANNING SUGGESTS THIS
   'WIN': Device, Decomposed=1
   'MAC': Device, Decomposed=1
    'X' : Device, Decomposed=1
   ELSE:
ENDCASE

if jpg_type eq 3 then $
tv, new_im, true=1			;DISPLAY JPEG IN WINDOW
if jpg_type eq 2 then $
tv, new_im				;DISPLAY JPEG IN WINDOW

;PROMPT TO CLICK ON A TICK LABELS ON X-AXIS
print, ' '
print, ' Please click on the FIRST labeled tick mark on the X-AXIS"
cursor, x1_x, x1_y, /normal, /down	      ;RECORD CLICK
print, ' Please enter the label of this tick mark:"
read, x1_val
print, ' Please click on the LAST labeled tick mark on the X-AXIS"
cursor, x2_x, x2_y, /normal, /down	      ;RECORD CLICK
print, ' Please enter the label of this tick mark:"
read, x2_val

;THE FOLLOWING ALLOWS A TRANFORMATION FROM NORMAL TO DATA COORDINATES
;AS SO: DATA_COORDS = NORMAL_COORDS * X_SCALE + X_INT
x_pix_diff = x2_x - x1_x
x_val_diff = x2_val - x1_val
x_scale = x_val_diff / x_pix_diff	      ;SLOPE
x_int   = x1_val - x1_x * x_scale	      ;INTERCEPT

;PROMPT TO CLICK ON A TICK LABEL ON Y-AXIS
print, ' '
print, ' Please click on the FIRST labeled tick mark on the Y-AXIS"
cursor, y1_x, y1_y, /normal, /down	      ;RECORD CLICK
print, ' Please enter the label of this tick mark:"
read, y1_val
print, ' Please click on the LAST labeled tick mark on the Y-AXIS"
cursor, y2_x, y2_y, /normal, /down	      ;RECORD CLICK
print, ' Please enter the label of this tick mark:"
read, y2_val

;THE FOLLOWING ALLOWS A TRANFORMATION FROM NORMAL TO DATA COORDINATES
;AS SO: DATA_COORDS = NORMAL_COORDS * Y_SCALE + Y_INT
y_pix_diff = y2_y - y1_y
y_val_diff = y2_val - y1_val
y_scale = y_val_diff / y_pix_diff	      ;SLOPE
y_int   = y1_val - y1_y * y_scale	      ;INTERCEPT


cfx = [x_int,x_scale]		;SAVE COEFFS. FOR POLY()
cfy = [y_int,y_scale]

repeat begin			;BEGIN DATA CLICKING/ SELECTION

 print, ' '
 print, ' Begin pixel input.  Click on a data point to add it to your array.'
 print, ' Click on middle or right button to exit.'

 flag = 0			;SET FLAG FOR ARRAY HANDLING
 repeat begin
   cursor, x, y, /normal, /down
   ;SAVE PIXELS WHEN LEFT BUTTON CLICKED
   if !mouse.button eq 1 then begin
    if flag ne 1 then begin	;NEED TO CREATE ARRAY IF NOT PRESENT
     flag = 1
     x_arr = x & y_arr = y
    endif else begin		;DO THIS IF IT'S ALREADY CREATED
     x_arr = [x_arr,x] & y_arr = [y_arr,y]
    endelse
   endif
 endrep until !mouse.button ge 2	;WHEN THE USER CLICKS ANOTHER BUTTON

 npts = n_elements(x_arr)		;NUMBER OF CLICKS
 as = sort(x_arr)			;SORT 'EM
 x_arr = x_arr(as) & y_arr = y_arr(as)	
 out_arr = fltarr(npts,2)		;INITIALIZE OUTPUT ARRAY
 out_arr[*,0] = poly(x_arr,cfx)		;TRANSFORMED X-VALUES
 out_arr[*,1] = poly(y_arr,cfy)		;TRANSFORMED Y-VALUES

 print, "Are you satisfied with your extraction (0=Sure am, 1=Nope)?"
 read, ans

endrep until (ans eq 0)		;END WHEN USER IS SATISFIED

end