示例#1
0
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")))
示例#2
0
 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)
示例#3
0
 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)
示例#4
0
    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
示例#5
0
 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)
示例#6
0
    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)
示例#7
0
    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)
示例#8
0
    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