Advertisement
Guest User

Untitled

a guest
Apr 28th, 2017
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.28 KB | None | 0 0
  1. '''
  2.  
  3. USAGE: $python this_script.py ipod_rectangle.jpg background.jpg
  4.  
  5. '''
  6. import random
  7. from PIL import Image
  8. import cv2
  9. import numpy as np
  10.  
  11.  
  12. class PhotoSynthesizer(object):
  13.     '''
  14.    Class for synthesizing "photos" of rectangles. Simulates perspective distortion, scale, rotation and translation.
  15.    Convention for box/cornerpoints ordering:
  16.            [top-left, top-right, bottom-right, bottom-left]
  17.    i.e.    clockwise from top-left.
  18.    '''
  19.     def __init__(self, canvas_size, scale_amount=(0.1, 0.4), rotation_amount=15, warp_amount=0.05):
  20.         self.canvas_size = canvas_size
  21.         self.scale_amount = scale_amount
  22.         self.rotation_amount = rotation_amount
  23.         self.warp_amount = warp_amount
  24.  
  25.     def _to_homogenous(self, nparr):
  26.         homogenous = np.c_[nparr, np.ones(4)]
  27.         return homogenous
  28.  
  29.     def _from_homogenous(self, nparr):
  30.         outarr = np.zeros((4, 2))
  31.         outarr[:, 0] = nparr[:, 0] / nparr[:, 2]
  32.         outarr[:, 1] = nparr[:, 1] / nparr[:, 2]
  33.         return outarr
  34.  
  35.     def _transform_cornerpoints(self, matrix, coordinate_list):
  36.         # turn the coords array into homogeneous coordinates, to do matrix operations on them
  37.         coords_homogeneous = self._to_homogenous(coordinate_list)
  38.         # transpose the cornerpoints arrays so that they can be multiplied by matrices
  39.         coords_homogeneous = np.transpose(coords_homogeneous)
  40.         # perform dot
  41.         coords_homogeneous = np.dot(matrix, coords_homogeneous)
  42.         # un-transpose
  43.         coords_homogeneous = np.transpose(coords_homogeneous)
  44.         # convert from homogeneous to 2D
  45.         return self._from_homogenous(coords_homogeneous)
  46.  
  47.     def _random_homography2(self):
  48.         # assume that the rectangle images have been rescaled to the fit the canvas
  49.         final_transform = np.eye(3, dtype=np.float64)
  50.  
  51.         # translate the cornerpoints such that the centre of the card is at the origin
  52.         tx = self.canvas_size[0] / 2.
  53.         ty = self.canvas_size[1] / 2.
  54.         translation_matrix = np.array([[1, 0, -tx],
  55.                                        [0, 1, -ty],
  56.                                        [0, 0, 1]], dtype=np.float64)
  57.         final_transform = np.dot(translation_matrix, final_transform)
  58.  
  59.         # apply a random rescale (to produce image samples with rectangles of varying sizes)
  60.         # that preserves aspect ratio
  61.         scale_factor = random.uniform(self.scale_amount[0], self.scale_amount[1])
  62.         zoom_matrix = np.array([[scale_factor, 0., 0.],
  63.                                 [0., scale_factor, 0.],
  64.                                 [0., 0., 1.]], dtype=np.float64)
  65.         final_transform = np.dot(zoom_matrix, final_transform)
  66.  
  67.         # perform a random rotation on the card cornerpoints
  68.         theta = np.pi / 180 * np.random.uniform(-self.rotation_amount, self.rotation_amount)
  69.         rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0],
  70.                                     [np.sin(theta), np.cos(theta),  0],
  71.                                     [0,                         0,  1]], dtype=np.float64)
  72.         final_transform = np.dot(rotation_matrix, final_transform)
  73.  
  74.         # generate a small amount of perspective warping
  75.         A = random.uniform(-self.warp_amount, self.warp_amount)
  76.         B = random.uniform(-self.warp_amount, self.warp_amount)
  77.         warp_matrix = np.array([[1, 0., 0.],
  78.                                 [0., 1, 0.],
  79.                                 [A, B, 1.]], dtype=np.float64)
  80.         final_transform = np.dot(warp_matrix, final_transform)
  81.  
  82.         # translate back to centre of canvas
  83.         translation_matrix2 = np.array([[1, 0, tx],
  84.                                        [0, 1, ty],
  85.                                        [0, 0, 1]], dtype=np.float64)
  86.         final_transform = np.dot(translation_matrix2, final_transform)
  87.  
  88.         return final_transform
  89.  
  90.     def snap(self, img_rectangle, img_background):
  91.         '''
  92.        :param img_rectangle: PIL image of rectangle
  93.        :param img_background_new: PIL image of background
  94.        :return: cv2 image - composite of rectangle and background with random perspective
  95.        '''
  96.  
  97.         img_rectangle_new = img_rectangle.convert("RGBA")
  98.         img_rectangle_new = img_rectangle_new.resize(self.canvas_size)
  99.  
  100.         # compute a random projective transform homography
  101.         homography = self._random_homography2()
  102.         # only interested in the 8 degrees of freedom, as a tuple
  103.         h = tuple(homography.flatten()[:8])
  104.  
  105.         # apply the transform
  106.         new_image = img_rectangle_new.transform(self.canvas_size, Image.PERSPECTIVE, h, Image.BICUBIC)
  107.  
  108.         # rescale the background to fit the canvas
  109.         img_background_new = img_background.resize(self.canvas_size)
  110.  
  111.         # paste projective-transformed rectangle onto background
  112.         img_background_new.paste(new_image, (0, 0), new_image)
  113.  
  114.         # convert the PIL image to opencv:
  115.         img_background_new = np.array(img_background_new)
  116.         img_background_new = cv2.cvtColor(img_background_new, cv2.COLOR_RGB2BGR)
  117.  
  118.         cornerpoints_original = np.array([[0, 0],
  119.                                           [self.canvas_size[0], 0],
  120.                                           [self.canvas_size[0], self.canvas_size[1]],
  121.                                           [0, self.canvas_size[1]]], dtype=np.float64)
  122.  
  123.         cols = [(225, 0, 0), (0, 225, 0), (0, 0, 225), (225, 225, 0)]
  124.  
  125.         cornerpoints_warped = self._transform_cornerpoints(np.linalg.inv(homography), cornerpoints_original)
  126.  
  127.         for j in range(4):
  128.             cornerpoints_warped = cornerpoints_warped.astype(int)
  129.             cv2.circle(img_background_new, tuple(cornerpoints_warped[j]), 5, color=cols[j], thickness=-1)
  130.  
  131.         show(img_background_new)
  132.  
  133. def show(im, winname=''):
  134.     cv2.imshow(winname, im)
  135.     cv2.waitKey(0)
  136.     cv2.destroyAllWindows()
  137.  
  138.  
  139. if __name__ == '__main__':
  140.     import sys
  141.  
  142.     IMG_RECTANGLE = Image.open(sys.argv[1])
  143.     IMG_BACKGROUND = Image.open(sys.argv[2])
  144.     CANVAS_SIZE = (640, 410)
  145.     SCALE_AMOUNT = (1, 2)
  146.     WARP_AMOUNT = 0.00005
  147.  
  148.     photographer = PhotoSynthesizer(CANVAS_SIZE, scale_amount=SCALE_AMOUNT, warp_amount=WARP_AMOUNT)
  149.  
  150.  
  151.     while True:
  152.         photographer.snap(IMG_RECTANGLE, IMG_BACKGROUND)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement