A simple tool that converts images with a rectilinear projection (ordinary photos, game screenshots etc) to a stereographic (angle-preserving) projection, and displays the result. My first attempt at an image manipulation tool, now a guinea pig for displaying code on a website. Requires the scipy and matplotlib packages. Takes two arguments: source image filename and source image horizontal field-of-view in degrees.
Source: stereo_img.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#! python2.7 # Convert rectilinear image to stereographic projection # By Oscar Francis # Created Mon 26 Aug 2013 using Python 2.7.5 # Usage: stereo_img.py <imagename> <source image horizontal FOV in degrees> from __future__ import division from math import * import sys import time from scipy import misc import matplotlib.pyplot as plt img = misc.imread( sys.argv[1] ) imgh, imgw, bits = img.shape wh = int( imgw / 2 ) hh = int( imgh / 2 ) img2 = img.copy() img2[0:imgh] = (0,0,0) def getcentre( p ): return (p[0] - wh, p[1] - hh) def decentre ( p ): return (int( p[0] + wh ), int( p[1] + hh )) def polar ( p ): return (sqrt( p[0]**2 + p[1]**2 ), atan2( p[1], p[0] )) def cartesian( p ): return (p[0] * cos( p[1] ), p[0] * sin( p[1] )) def normalize( p ): return (radians( hfov ) * (p[0]/wh), radians( hfov ) * (p[1]/wh)) def spaceout ( p ): return ((p[0] * wh) / radians( hfov ), (p[1] * wh) / radians( hfov )) fov = int( sys.argv[2] ) hfov = fov / 2 scale = 1.0 - ((fov - 90) / 340) ** 1.5 if fov > 90 else 1.0 start_time = time.clock() for y in range( imgh ): for x in range( imgw ): p = polar( normalize( getcentre( (x, y) ) ) ) p = (tan( 2*atan( p[0]/2 ) ) * scale, p[1]) p = decentre( spaceout( cartesian( p ) ) ) if p[1] >= 0 and p[1] < imgh and p[0] > 0 and p[0] < imgw: img2[y,x] = img[p[1],p[0]] print time.clock() - start_time plt.imshow( img2 ) plt.show() |