def _launch_quilt(debug, final_path, src, **kwargs): """ Launches quilt process with the parsed arguments. """ multi_proc = kwargs.pop('multiprocess') # ------------- quilt -------------- qs = time.time() log.info('Quilt started at {0}'.format(time.strftime("%H:%M:%S"))) try: # compute quilting Quilt.debug = debug q = Quilt(src, **kwargs) if multi_proc: q.optimized_compute() else: q.compute() # get the result result = q.get_result() if debug: show(result) save(result, final_path) except ValueError as err: log.error(err.message) return t = (time.time() - qs) / 60 log.debug('Quilt took {0:0.6f} minutes'.format(t)) log.info('End {0}'.format(time.strftime("%H:%M:%S")))
def test_show_single_uint(self, mk_show): """ Test show calls _show method in Image just once. Test with a single uint8 image as input. """ a = np.array([[0, 0.5, 0.8], [1, 0.3, 0.7]]) show(np.uint8(gray2rgb(a))) mk_show.assert_called_once_with(mock.ANY, command=None, title=None)
def test_show_single_float(self, mk_show): """ Test show calls _show method in Image just once with the right args. Test with a single float64 image as input. """ a = np.array([[0, 0.5, 0.8], [1, 0.3, 0.7]]) a = matrix2img(gray2rgb(a)) show(a) mk_show.assert_called_once_with(a, command=None, title=None)
def create_flip(cls, img, amount=(0, 0)): """ Generates the required flips of the input image and builds an image containing the input image and its flips. The final image is so composed: _______ If amount = [0, 1]: | img | |_______| | flipV | |_______| _______ _______ If amount = [1, 0]: | img | flipH | |_______|_______| _______ _______ If amount = [1, 1]: | img | flipH | |_______|_______| | flipV |flipHV | |_______|_______| Args: img: image to be rotated amount: Returns: image composed of the input one and it rotations """ # check the amount if not amount or amount == (0, 0): return img # turn the input image into a 3-channel image third_dim = len(img.shape) == 3 img = gray2rgb(img) # vertical if amount[0]: flip = zeros((img.shape[0] * 2 + 1, img.shape[1], 3)) flip[:img.shape[0], :, :] = img flip[img.shape[0] + 1:, :, :] = flipud(img) img = flip # horizontal if amount[1]: flip = zeros((img.shape[0], img.shape[1] * 2 + 1, 3)) flip[:, :img.shape[1], :] = img flip[:, img.shape[1] + 1:, :] = fliplr(img) img = flip # if the input image had 1 channel only, also the result will do if not third_dim: img = img[:, :, 0] show(img) if cls.debug else None return img
def test_show_list(self, mk_show): """ Test show calls _show method in Image just once with the right args. Test with a list of images as input. """ a = matrix2img(gray2rgb(np.array([[0, 0.5, 0.8], [1, 0.3, 0.7]]))) b = matrix2img(np.array([[0, 0.5, 0.8], [1, 0.3, 0.7], [1, 0.3, 0.7]])) c = matrix2img(gray2rgb(np.array([[0.5, 0.8], [0.3, 0.7], [0.3, 0.7]]))) show([a, b, c]) expected = [ mock.call(a, command=None, title=None), mock.call(b, command=None, title=None), mock.call(c, command=None, title=None) ] mk_show.assert_has_calls(expected)
def compute(self): """ Single, traditional, single process computation. """ self.log.info('\nCOMPUTING ...') for n in xrange(self.niter): for i in xrange(self.num_tiles[0]): startI = i * self.tilesize - i * self.overlap endI = min(self.Y[0].shape[0], startI + self.tilesize) sizeI = endI - startI if sizeI <= self.overlap: continue for j in xrange(self.num_tiles[1]): startJ = j * self.tilesize - j * self.overlap endJ = min(self.Y[0].shape[1], startJ + self.tilesize) sizeJ = endJ - startJ if sizeJ <= self.overlap: continue # skip if this patch is not meant to be filled if self.Ymask and not np.any(self.Ymask[startI:endI, startJ:endJ]): continue # Dist from each tile to the overlap region y_patches = [ y[startI:endI, startJ:endJ, :] for y in self.Y ] res_patches = self._compute_patch( y_patches, [sizeI, sizeJ], (i, j), mask=self.Xmask, constraint_start=self.constraint_start) for idx, res in enumerate(res_patches): self.Y[idx][startI:endI, startJ:endJ, :] = res self.log.debug('iter {0} / {1}'.format(n, self.niter)) show(self.Y[0]) if self.debug else None if self.result_path: save(self.Y[0], self.result_path)
def optimized_compute(self): """ First process: it computes the quilt algorithm with big tiles, manages child processes and them combines the results. 1) creates the child processes (number defined according to the available cores and the number of big tiles in the image) 2) computes quilting with big tiles 3) every time a tile is computed (and sewed with the image), it is put in a queue process 1: big tiles for each of the tile: process n """ self.log.info('\nMULTIPROCESSING COMPUTING ...') big_num_tiles = self.calc_num_tiles(tile_size=self.big_tilesize, overlap=self.big_overlap) # prepare the pool n_proc = min(big_num_tiles[0] * big_num_tiles[1], self.cores) out_queue = Queue() in_queue = JoinableQueue() pool = Pool(n_proc, unwrap_self, ( self, in_queue, out_queue, )) self.log.info('preparing {0} processes - {1}'.format( n_proc, time.strftime("%H:%M:%S"))) if self.Ymask is not None: # zero values will become inf Ymask_rgb = gray2rgb(self.Ymask) # use the mask as a draft of the dst img so that boundaries are # respected self.Y[0] = deepcopy(Ymask_rgb) for i in xrange(big_num_tiles[0]): startI = i * self.big_tilesize - i * self.big_overlap endI = min(self.Y[0].shape[0], startI + self.big_tilesize) sizeI = endI - startI if sizeI <= self.overlap: continue for j in xrange(big_num_tiles[1]): startJ = j * self.big_tilesize - j * self.big_overlap endJ = min(self.Y[0].shape[1], startJ + self.big_tilesize) sizeJ = endJ - startJ if sizeJ <= self.overlap: continue dst_patches = [y[startI:endI, startJ:endJ, :] for y in self.Y] # for the big tiles don't consider the mask, since it would # remove most of the image because the tiles are so big res_patches = self._compute_patch( dst_patches, [sizeI, sizeJ], (i, j), mask=self.Xmask_big, constraint_start=self.constraint_start, err=0.8) # add the mask on top if self.Ymask is not None: res_patches = [ r * Ymask_rgb[startI:endI, startJ:endJ] for r in res_patches ] for idx, res in enumerate(res_patches): self.Y[idx][startI:endI, startJ:endJ, :] = res # make a process start in this big tile _img = [y[startI:endI, startJ:endJ, :] for y in self.Y] _mask = self.Ymask[startI:endI, startJ:endJ] \ if self.Ymask is not None else None _id = (startI, startJ) in_queue.put({'dst': _img, 'mask': _mask, 'id': _id}) # wait for all the children self.log.debug('master finished {0}'.format(time.strftime("%H:%M:%S"))) show(self.Y[0]) if self.debug else None pool.close() self.log.debug('closed, in queue: {0} out: {1}'.format( in_queue.qsize(), out_queue.qsize())) in_queue.join() self.log.debug('all children finished {0}'.format( time.strftime("%H:%M:%S"))) # get the results results = sorted([ out_queue.get() for _ in xrange(big_num_tiles[0] * big_num_tiles[1]) ]) # sew them together for idx, res in results: # calculate the mask base_patch = self.Y[0][idx[0]:idx[0] + self.big_tilesize, idx[1]:idx[1] + self.big_tilesize] new_patch = res[0] mask_patch = self.calc_patch_mask(base_patch, new_patch, coord=idx, overlap=self.big_overlap) # apply the mask to each layer for i, y in enumerate(self.Y): base_patch = y[idx[0]:idx[0] + self.big_tilesize, idx[1]:idx[1] + self.big_tilesize] new_patch = res[i] self.Y[i][idx[0]:idx[0]+self.big_tilesize, idx[1]:idx[1]+self.big_tilesize, :] = \ filter_img(new_patch, base_patch, mask_patch) # apply the mask again if self.Ymask is not None: self.Y = [r * Ymask_rgb for r in self.Y] show(self.Y[0]) if self.debug else None if self.result_path: save(self.Y[0], self.result_path) self.log.info('saving' + self.result_path)
def create_rotations(cls, img, amount): """ Generates the required rotations of the input image and builds an image containing the input image and its rotations (the remaining space is left zero). The final image is so composed: _______ If amount == 2: | rot0 | |_______| |rot180 | |_______| _______ _____ _____ If amount == 4: | rot0 | | | |_______| rot | rot | |rot180 | 90 | -90 | |_______|_____|_____| Args: img: image to be rotated amount: amount of rotation of 90 degrees. E.g.: amount = 2 --> rotation = 90*2 = 180 Accepted values: {0, 2, 4} Returns: image composed of the input one and it rotations """ # check the amount if not amount: return img if amount not in [2, 4]: raise ValueError( 'Rotation must be None, 2 or 4. Got {0}'.format(amount)) # turn the input image into a 3-channel image third_dim = len(img.shape) == 3 img = gray2rgb(img) rot = None if amount == 2: rot = zeros((img.shape[0] * 2 + 1, img.shape[1], 3)) rot[:img.shape[0], :, :] = img rot[img.shape[0] + 1:, :, :] = rot90(img, 2) if amount == 4: # set so that height > width if img.shape[0] > img.shape[1]: img = rot90(img, 1) rot = zeros((max(img.shape[1], img.shape[0] * 2 + 1), img.shape[1] + img.shape[0] * 2 + 2, 3)) rot[:img.shape[0], :img.shape[1], :] = img rot[img.shape[0] + 1: img.shape[0] * 2 + 1, :img.shape[1], :] = \ rot90(img, 2) rot[:img.shape[1], img.shape[1] + 1:img.shape[1] + 1 + img.shape[0], :] = rot90( img, 1) rot[:img.shape[1], img.shape[0] + img.shape[1] + 2:, :] = \ rot90(img, 3) # if the input image had 1 channel only, also the result will do if not third_dim: rot = rot[:, :, 0] show(rot) if cls.debug else None return rot