From b74b0b2afb283f59f31d6e3fcb37cb98525365f6 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 12 Jul 2013 20:46:18 -0700 Subject: [PATCH 1/2] Make warp.panorama() much faster. ch3_panorama now runs in less than 1 minute, instead of > 8min (after which I killed it). The output should be the same as before. Do this by doing the perspective image mapping using PIL instead of scipy. Also fix a FIXME about x and y being swapped (since this wasn't mentioned in the bug, this was pretty confusing to me), since that's no longer necessary. --- PCV/geometry/warp.py | 40 +++++++++++++++++----------------------- PCV/tools/imtools.py | 8 ++++++++ examples/ch3_panorama.py | 9 +++------ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/PCV/geometry/warp.py b/PCV/geometry/warp.py index 6ed199d..a917d77 100644 --- a/PCV/geometry/warp.py +++ b/PCV/geometry/warp.py @@ -4,6 +4,7 @@ from numpy import * from PCV.geometry import homography +from PCV.tools import imtools def image_in_image(im1,im2,tp): @@ -104,49 +105,42 @@ def panorama(H,fromim,toim,padding=2400,delta=2400): # check if images are grayscale or color is_color = len(fromim.shape) == 3 - # homography transformation for geometric_transform() - def transf(p): - p2 = dot(H,[p[0],p[1],1]) - return (p2[0]/p2[2],p2[1]/p2[2]) - - if H[1,2]<0: # fromim is to the right + if H[0,2]<0: # fromim is to the right print 'warp - right' # transform fromim if is_color: # pad the destination image with zeros to the right - toim_t = hstack((toim,zeros((toim.shape[0],padding,3)))) - fromim_t = zeros((toim.shape[0],toim.shape[1]+padding,toim.shape[2])) - for col in range(3): - fromim_t[:,:,col] = ndimage.geometric_transform(fromim[:,:,col], - transf,(toim.shape[0],toim.shape[1]+padding)) + toim_t = hstack((toim, zeros((toim.shape[0], padding, 3)))) + fromim_t = imtools.Htransform( + fromim, H, (toim.shape[0], toim.shape[1] + padding)) else: # pad the destination image with zeros to the right toim_t = hstack((toim,zeros((toim.shape[0],padding)))) - fromim_t = ndimage.geometric_transform(fromim,transf, - (toim.shape[0],toim.shape[1]+padding)) + fromim_t = imtools.Htransform( + fromim, H, (toim.shape[0], toim.shape[1] + padding)) else: print 'warp - left' # add translation to compensate for padding to the left - H_delta = array([[1,0,0],[0,1,-delta],[0,0,1]]) + H_delta = array([[1,0,-delta],[0,1,0],[0,0,1]]) H = dot(H,H_delta) # transform fromim if is_color: # pad the destination image with zeros to the left - toim_t = hstack((zeros((toim.shape[0],padding,3)),toim)) - fromim_t = zeros((toim.shape[0],toim.shape[1]+padding,toim.shape[2])) - for col in range(3): - fromim_t[:,:,col] = ndimage.geometric_transform(fromim[:,:,col], - transf,(toim.shape[0],toim.shape[1]+padding)) + toim_t = hstack((zeros((toim.shape[0], padding, 3)), toim)) + fromim_t = imtools.Htransform( + fromim, H, (toim.shape[0], toim.shape[1] + padding)) else: # pad the destination image with zeros to the left toim_t = hstack((zeros((toim.shape[0],padding)),toim)) - fromim_t = ndimage.geometric_transform(fromim, - transf,(toim.shape[0],toim.shape[1]+padding)) + fromim_t = imtools.Htransform( + fromim, H, (toim.shape[0], toim.shape[1] + padding)) # blend and return (put fromim above toim) if is_color: - # all non black pixels - alpha = ((fromim_t[:,:,0] * fromim_t[:,:,1] * fromim_t[:,:,2] ) > 0) + # Three separate checks instead of a * b * c > 0 because of uint8 overflow. + alpha = ((fromim_t[:, :, 0] > 0) * + (fromim_t[:, :, 1] > 0) * + (fromim_t[:, :, 2] > 0)) for col in range(3): toim_t[:,:,col] = fromim_t[:,:,col]*alpha + toim_t[:,:,col]*(1-alpha) else: diff --git a/PCV/tools/imtools.py b/PCV/tools/imtools.py index 416a47c..b69dabb 100644 --- a/PCV/tools/imtools.py +++ b/PCV/tools/imtools.py @@ -48,6 +48,14 @@ def imresize(im,sz): return array(pil_im.resize(sz)) +def Htransform(im, H, out_size): + """ Applies a homography transform to im.""" + pil_im = Image.fromarray(im) + pil_size = out_size[1], out_size[0] + return array(pil_im.transform( + pil_size, Image.PERSPECTIVE, H.reshape(9)[0:8] / H[2,2], Image.LINEAR)) + + def histeq(im,nbr_bins=256): """ Histogram equalization of a grayscale image. """ diff --git a/examples/ch3_panorama.py b/examples/ch3_panorama.py index 0569625..bfa8bb8 100644 --- a/examples/ch3_panorama.py +++ b/examples/ch3_panorama.py @@ -40,9 +40,6 @@ def convert_points(j): ndx2 = [int(matches[j][i]) for i in ndx] tp = homography.make_homog(l[j][ndx2,:2].T) - # switch x and y - TODO this should move elsewhere - fp = vstack([fp[1],fp[0],fp[2]]) - tp = vstack([tp[1],tp[0],tp[2]]) return fp,tp @@ -69,13 +66,13 @@ def convert_points(j): im2 = array(Image.open(imname[2]), "uint8") im_12 = warp.panorama(H_12,im1,im2,delta,delta) -im1 = array(Image.open(imname[0]), "f") +im1 = array(Image.open(imname[0]), "uint8") im_02 = warp.panorama(dot(H_12,H_01),im1,im_12,delta,delta) -im1 = array(Image.open(imname[3]), "f") +im1 = array(Image.open(imname[3]), "uint8") im_32 = warp.panorama(H_32,im1,im_02,delta,delta) -im1 = array(Image.open(imname[4]), "f") +im1 = array(Image.open(imname[4]), "uint8") im_42 = warp.panorama(dot(H_32,H_43),im1,im_32,delta,2*delta) From e5f4388d6c9acc82ffed7327fee7af0252a6fbad Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 12 Jul 2013 20:52:25 -0700 Subject: [PATCH 2/2] simplify; the PIL-based warp can handle color and grayscale images --- PCV/geometry/warp.py | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/PCV/geometry/warp.py b/PCV/geometry/warp.py index a917d77..442bf70 100644 --- a/PCV/geometry/warp.py +++ b/PCV/geometry/warp.py @@ -104,37 +104,24 @@ def panorama(H,fromim,toim,padding=2400,delta=2400): # check if images are grayscale or color is_color = len(fromim.shape) == 3 + + if is_color: + toim_zeros = zeros((toim.shape[0], padding, 3)) + else: + toim_zeros = zeros((toim.shape[0], padding)) if H[0,2]<0: # fromim is to the right print 'warp - right' - # transform fromim - if is_color: - # pad the destination image with zeros to the right - toim_t = hstack((toim, zeros((toim.shape[0], padding, 3)))) - fromim_t = imtools.Htransform( - fromim, H, (toim.shape[0], toim.shape[1] + padding)) - else: - # pad the destination image with zeros to the right - toim_t = hstack((toim,zeros((toim.shape[0],padding)))) - fromim_t = imtools.Htransform( - fromim, H, (toim.shape[0], toim.shape[1] + padding)) + toim_t = hstack((toim, toim_zeros)) else: print 'warp - left' # add translation to compensate for padding to the left H_delta = array([[1,0,-delta],[0,1,0],[0,0,1]]) H = dot(H,H_delta) - # transform fromim - if is_color: - # pad the destination image with zeros to the left - toim_t = hstack((zeros((toim.shape[0], padding, 3)), toim)) - fromim_t = imtools.Htransform( - fromim, H, (toim.shape[0], toim.shape[1] + padding)) - else: - # pad the destination image with zeros to the left - toim_t = hstack((zeros((toim.shape[0],padding)),toim)) - fromim_t = imtools.Htransform( - fromim, H, (toim.shape[0], toim.shape[1] + padding)) + toim_t = hstack((toim_zeros, toim)) + fromim_t = imtools.Htransform(fromim, H, (toim_t.shape[0], toim_t.shape[1])) + # blend and return (put fromim above toim) if is_color: # Three separate checks instead of a * b * c > 0 because of uint8 overflow.