def get(self, userId, photoId): # Get Access Token and Photo URL from header access_token = self.request.headers["access-token"] photo_url = self.request.headers["photo-url"] # Load PIL image from facebook url im = ImageLoader().load_url_image(photo_url) # Crop image to a square cols, rows = im.size # Landscape Layout (or Square) if cols >= rows: target_cols = rows left = (cols-target_cols)/2 right = left+target_cols im = im.crop( (left, 0, right, rows) ) # Portrait Layout else: target_rows = cols upper = (rows-target_rows)/2 lower = upper+target_rows im = im.crop( (0, upper, cols, lower) ) # Analyze image imgAnalyzer = ImageAnalyzer() cols, rows = im.size labVec = imgAnalyzer.getLABVector(im, 0, 0, cols, rows) # Store the Lab Vector into the Google Datastore ImageDatastore().set_Lab_vector(userId, photoId, labVec) # Prepare JSON response json_response = json.dumps( {"success": True, "photoId": photoId}, indent=4) # Write JSON response self.response.headers['Content-Type'] = 'application/json' self.response.write(json_response)
class Photomosaic: # Variables total_rows = 0 total_cols = 0 progress = 0 photoLog = [] cellLog = [] photos = {} subimage = {} # Convenience objects ImgAnalyzer = None ImgFinder = None ImgLoader = None # The input image to analyze input = None input_grid_width = 0 input_grid_height = 0 input_cell_width = 0 input_cell_height = 0 # The output photomosiac based on the input image output = None output_mag = 1 output_grid_width = 0 output_grid_height = 0 output_cell_width = 0 output_cell_height = 0 # Constructor def __init__(self, input_PIL_img, lib_Lab_vectors, photoLog, cellLog, subimage, progress=0): # Set instance variables self.input = input_PIL_img self.photoLog = photoLog # The photoLog, cellLog, and progress should probably be in it's own information expert self.cellLog = cellLog self.progress = int(progress) self.ImgAnalyzer = ImageAnalyzer() self.ImgFinder = ImageFinder(lib_Lab_vectors) self.ImgLoader = ImageLoader() self.subimage = subimage # Calculate all of the closests photos in the photomosaic def calculate_photomosaic(self, rows, cols): # Initialize input image self._input_dims(int(rows), int(cols)) # Find the initial coordinates row = int(len(self.cellLog) / self.total_cols) col = int(len(self.cellLog) % self.total_cols) x0 = col*self.input_cell_width y0 = row*self.input_cell_height # Traverse the cells, and call "_process_cell" for each one of them self._traverse_cells(self._process_cell, x0, y0) # Create the photomosiac - currently only works with a square (rows=cols) def create_photomosaic(self, rows, cols, mag): # Initialize input and output images self._input_dims(int(rows), int(cols)) self._output_dims(float(mag)) # Find the initial coordinates to start pasting cells row = int(self.progress / self.total_cols) col = int(self.progress % self.total_cols) x0 = col*self.input_cell_width y0 = row*self.input_cell_height # Traverse the cells, and call "_paste_cell" for each one of them self._traverse_cells(self._paste_cell, x0, y0) # Return the ouput image as a base64 encoded string return self.base64() # Return the output image as a base64 encoded string def base64(self): file = StringIO() self.output.save(file, "png") return b64encode(file.getvalue()) # Traverse the cells def _traverse_cells(self, fnc_process_cell, x0=0, y0=0): for y in range(y0, self.input_grid_height, self.input_cell_height): if y != y0: x0 = 0 # Only start in the middle of the grid on the first iteration for x in range(x0, self.input_grid_width, self.input_cell_width): fnc_process_cell(x, y) self.progress += 1 # Analyze the input cell, find the best match, and add it to the cell log def _process_cell(self, x0, y0): labVec = self.ImgAnalyzer.getLABVector(self.input, x0, y0, self.input_cell_width, self.input_cell_height) closest_photoId = self.ImgFinder.closest_match(labVec) self.cellLog.append(closest_photoId) # Download the image and paste it into the output image def _paste_cell(self, x0, y0): # Translate the x and y coordinates into a cellLog index and find the photoId row = int(y0/self.input_cell_height) col = int(x0/self.input_cell_width) cellLogIndex = row*self.total_cols + col photoId = self.cellLog[cellLogIndex] # Get the image associated with the photo if photoId in self.photos: # We already have the image, so grab it from the dictionary closest_img = self.photos[photoId] else: # We haven't previously downloaded the image, so get it from Facebook closest_img = self.ImgLoader.load_url_image(self._get_url(photoId)) # Crop the image and resize it into a square closest_img = self._crop_resize_square(closest_img) # Add the image to the photos dictionary self.photos[photoId] = closest_img # Now that the image has been found, paste it into the corresponding output cell self.output.paste( closest_img, (col*self.output_cell_width, row*self.output_cell_height) ) # Returns the URL associated with the photoId def _get_url(self, photoId): for log in self.photoLog: if log["photoId"] == photoId: return log["url"] else: return None # Crop the image into a square and resize it to the output cell size def _crop_resize_square(self, im): cols, rows = im.size # Landscape Layout (or Square) if cols >= rows: target_cols = rows left = (cols-target_cols)/2 right = left+target_cols return im.transform( (self.output_cell_width, self.output_cell_height), Image.EXTENT, (left, 0, right, rows) ) # Portrait Layout else: target_rows = cols upper = (rows-target_rows)/2 lower = upper+target_rows return im.transform( (self.output_cell_width, self.output_cell_height), Image.EXTENT, (0, upper, cols, lower) ) # Defines input dimensions def _input_dims(self, rows, cols): # Since number of columns is the width and number of rows is height self.input_grid_width = self.subimage["w"] self.input_grid_height = self.subimage["h"] self.total_rows = int(rows) self.total_cols = int(cols) self.input_grid_width -= self.input_grid_width % self.total_cols self.input_grid_height -= self.input_grid_height % self.total_rows self.input_cell_width = self.input_grid_width / self.total_cols self.input_cell_height = self.input_grid_height / self.total_rows # Crop Image self.input = self.input.crop( (self.subimage["x"], self.subimage["y"], self.subimage["x"]+self.input_cell_width*self.total_cols, self.subimage["y"]+self.input_cell_height*self.total_rows) ) # Defines output dimensions and creates output image def _output_dims(self, mag): # Set dimensions self.output_mag = float(mag) self.output_grid_width = int(self.input_grid_width * self.output_mag) self.output_grid_height = int(self.input_grid_height * self.output_mag) self.output_grid_width -= self.output_grid_width % self.total_cols self.output_grid_height -= self.output_grid_height % self.total_rows self.output_cell_width = self.output_grid_width / self.total_cols self.output_cell_height = self.output_grid_height / self.total_rows # Create output image self.output = Image.new("RGB", (self.output_grid_width, self.output_grid_height), "red")