[pypy-commit] extradoc extradoc: numpy version of magnify, make example self contained
hakanardo
noreply at buildbot.pypy.org
Mon Aug 22 11:32:43 CEST 2011
Author: Hakan Ardo <hakan at debian.org>
Branch: extradoc
Changeset: r3885:2215bd2c568e
Date: 2011-08-22 11:37 +0200
http://bitbucket.org/pypy/extradoc/changeset/2215bd2c568e/
Log: numpy version of magnify, make example self contained
diff --git a/talk/iwtc11/benchmarks/image/numpy_compare.py b/talk/iwtc11/benchmarks/image/numpy_compare.py
--- a/talk/iwtc11/benchmarks/image/numpy_compare.py
+++ b/talk/iwtc11/benchmarks/image/numpy_compare.py
@@ -1,5 +1,5 @@
from array import array
-import math
+import math, os, re
try:
import numpy
@@ -19,24 +19,54 @@
@property
def height(self):
return self.shape[0]
+
+ class NumpyNNImage(numpy.ndarray):
+ def __getitem__(self, (y, x)):
+ if isinstance(y, slice):
+ return numpy.ndarray.__getitem__(self, (y, x))
+ return numpy.ndarray.__getitem__(self, ((y + 0.5).astype(int),
+ (x + 0.5).astype(int)))
+
+ class NumpyBilinImage(numpy.ndarray):
+ def __getitem__(self, (y, x)):
+ if isinstance(y, slice) or y.dtype==int:
+ return numpy.ndarray.__getitem__(self, (y, x))
+ x0, x1 = numpy.floor(x).astype(int), numpy.ceil(x).astype(int)
+ y0, y1 = numpy.floor(y).astype(int), numpy.ceil(y).astype(int)
+ xoff, yoff = x-x0, y-y0
+ return (1.0-xoff)*(1.0-yoff) * self[y0, x0] + \
+ ( xoff)*(1.0-yoff) * self[y0, x1] + \
+ (1.0-xoff)*( yoff) * self[y1, x0] + \
+ ( xoff)*( yoff) * self[y1, x1]
+
+def wrap_numpy(fn):
+ def f(a):
+ return NumpyImage(fn(a.ndarray()))
+ return f
-
+######################################################################
+
class Image(array):
- def __new__(cls, w, h, typecode='d', fromfile=None):
+ def __new__(cls, w, h, typecode='d', data=None):
self = array.__new__(cls, typecode)
return self
- def __init__(self, w, h, typecode='d', fromfile=None):
+ def __init__(self, w, h, typecode='d', data=None):
self.width = w
self.height = h
- if fromfile is not None:
- self.fromfile(fromfile, w * h)
- else:
+ if data is None:
self.append(0)
self *= w*h
+ elif isinstance(data, file):
+ self.fromfile(data, w * h)
+ else:
+ self.extend(data)
def new(self):
return Image(self.width, self.height, self.typecode)
+
+ def clone(self):
+ return Image(self.width, self.height, self.typecode, self)
def _idx(self, x, y):
if 0 <= x < self.width and 0 <= y < self.height:
@@ -49,9 +79,13 @@
def __setitem__(self, (x, y), val):
array.__setitem__(self, self._idx(x, y), val)
- def pixels(self, border=0):
- for y in xrange(border, self.height-border):
- for x in xrange(border, self.width-border):
+ def pixels(self, border=0, xborder=None, yborder=None):
+ if xborder is None:
+ xborder = border
+ if yborder is None:
+ yborder = border
+ for y in xrange(border, self.height-yborder):
+ for x in xrange(border, self.width-xborder):
yield x, y
def ndarray(self):
@@ -64,12 +98,32 @@
except IndexError:
return 0
-def wrap_numpy(fn):
- def f(a):
- return NumpyImage(fn(a.ndarray()))
- return f
-
-def sobel_magnitude(a):
+class NNImage(Image):
+ def __getitem__(self, (x, y)):
+ return Image.__getitem__(self, (int(x + 0.5), int(y + 0.5)))
+
+ def ndarray(self):
+ return NumpyNNImage((self.height, self.width), self.typecode, self)
+
+class BilinImage(Image):
+ def __getitem__(self, (x, y)):
+ if isinstance(x, float) and isinstance(y, float):
+ x0, x1 = int(math.floor(x)), int(math.ceil(x))
+ y0, y1 = int(math.floor(y)), int(math.ceil(y))
+ xoff, yoff = x-x0, y-y0
+ return (1.0-xoff)*(1.0-yoff) * self[x0, y0] + \
+ (1.0-xoff)*( yoff) * self[x0, y1] + \
+ ( xoff)*(1.0-yoff) * self[x1, y0] + \
+ ( xoff)*( yoff) * self[x1, y1]
+ else:
+ return Image.__getitem__(self, (x, y))
+
+ def ndarray(self):
+ return NumpyBilinImage((self.height, self.width), self.typecode, self)
+
+######################################################################
+
+def sobel_magnitude(a): # pypy: 106 fps, cpython: 0.74 fps
b = a.new()
for x, y in a.pixels(border=1):
dx = -1.0 * a[x-1, y-1] + 1.0 * a[x+1, y-1] + \
@@ -81,7 +135,7 @@
return b
@wrap_numpy
-def sobel_magnitude_numpy(a):
+def sobel_magnitude_numpy(a): # 38 fps
dx = scipy.signal.convolve2d(a, numpy.array([[-1.0, 0.0, 1.0],
[-2.0, 0.0, 2.0],
[-1.0, 0.0, 1.0]]), 'same')
@@ -91,7 +145,7 @@
return numpy.minimum(numpy.sqrt(dx*dx + dy*dy) / 4.0, 255).astype('B')
@wrap_numpy
-def sobel_magnitude_numpy2(a):
+def sobel_magnitude_numpy2(a): # 89 fps
dx = -1.0 * a[0:-3, 0:-3] + 1.0 * a[0:-3, 2:-1] + \
-2.0 * a[1:-2, 0:-3] + 2.0 * a[1:-2, 2:-1] + \
-1.0 * a[2:-1, 0:-3] + 1.0 * a[2:-1, 2:-1]
@@ -100,9 +154,82 @@
res = numpy.zeros(a.shape)
res[1:-2, 1:-2] = numpy.minimum(numpy.sqrt(dx*dx + dy*dy) / 4.0, 255)
return res.astype('B')
+
+######################################################################
+
+def magnify(img): # pypy: 86 fps, cpython: 3.4 fps (NNImage)
+ # pypy: 78 fps, cpython: 2.1 fps (BilinImage)
+ out = img.clone()
+ maxr = img.height/3
+ for x, y in img.pixels(xborder=img.width/2 - maxr, yborder=img.height/2 - maxr):
+ dx, dy = x - img.width/2, y - img.height/2
+ a = math.atan2(dy, dx)
+ r = math.sqrt(dx ** 2 + dy ** 2)
+ if r < maxr:
+ nr = r*r / maxr
+ nx, ny = nr*math.cos(a), nr*math.sin(a)
+ out[x,y] = min(int(img[nx + img.width/2, ny + img.height/2]), 255)
+ else:
+ out[x,y] = img[x,y]
+ return out
+
+ at wrap_numpy
+def magnify_numpy(img): # 83 fps (NNImage), 62 fps (BilinImage)
+ out = img.copy()
+ maxr = img.shape[0]/3
+ x, y = numpy.meshgrid(range(img.shape[1]/2 - maxr, img.shape[1]/2 + maxr),
+ range(img.shape[0]/2 - maxr, img.shape[0]/2 + maxr))
+ dx, dy = x - img.shape[1]/2, y - img.shape[0]/2
+ a = numpy.arctan2(dy, dx)
+ r = numpy.sqrt(dx ** 2 + dy ** 2)
+ nr = r*r / maxr
+ nx, ny = nr*numpy.cos(a) + img.shape[1]/2, nr*numpy.sin(a) + img.shape[0]/2
+ outsub = out[img.shape[0]/2 - maxr : img.shape[0]/2 + maxr,
+ img.shape[1]/2 - maxr : img.shape[1]/2 + maxr]
+ outsub[r<maxr] = img[ny[r<maxr], nx[r<maxr]]
+ return numpy.minimum(out, 255).astype('B')
+
+######################################################################
+
+def mplayer(Image, fn='tv://', options=''):
+ f = os.popen('mplayer -really-quiet -noframedrop ' + options + ' '
+ '-vo yuv4mpeg:file=/dev/stdout 2>/dev/null </dev/null ' + fn)
+ hdr = f.readline()
+ m = re.search('W(\d+) H(\d+)', hdr)
+ w, h = int(m.group(1)), int(m.group(2))
+ while True:
+ hdr = f.readline()
+ if hdr != 'FRAME\n':
+ break
+ yield Image(w, h, 'B', f)
+ f.read(w*h/2) # Color data
+
+class MplayerViewer(object):
+ def __init__(self):
+ self.width = self.height = None
+ def view(self, img):
+ assert img.typecode == 'B'
+ if not self.width:
+ self.mplayer = os.popen('mplayer -really-quiet -noframedrop - ' +
+ '2> /dev/null ', 'w')
+ self.mplayer.write('YUV4MPEG2 W%d H%d F100:1 Ip A1:1\n' %
+ (img.width, img.height))
+ self.width = img.width
+ self.height = img.height
+ self.color_data = array('B', [127]) * (img.width * img.height / 2)
+ assert self.width == img.width
+ assert self.height == img.height
+ self.mplayer.write('FRAME\n')
+ img.tofile(self.mplayer)
+ self.color_data.tofile(self.mplayer)
+
+default_viewer = MplayerViewer()
+
+def view(img):
+ default_viewer.view(img)
+
if __name__ == '__main__':
- from io import mplayer, view
from time import time
try:
@@ -112,10 +239,12 @@
pass
start = start0 = time()
- for fcnt, img in enumerate(mplayer(Image, 'test.avi', '-benchmark')):
+ for fcnt, img in enumerate(mplayer(BilinImage, 'test.avi', '-benchmark')):
#view(img)
#view(sobel_magnitude(img))
- view(sobel_magnitude_numpy2(img))
+ #view(sobel_magnitude_numpy(img))
+ #view(magnify(img))
+ view(magnify_numpy(img))
print 1.0 / (time() - start), 'fps, ', (fcnt-2) / (time() - start0), 'average fps'
start = time()
if fcnt==2:
More information about the pypy-commit
mailing list