Esempio n. 1
0
class HDR(Filter):

    """High-dynamic-range_imaging with python PIL - works with files"""

    def __init__(self):
        Filter.__init__(self)
        self.case = 'test'
        self.resize = False

        self.strength = Param("strength", 0.0, min_v=0.0, max_v=3.0)
        self.naturalness = Param("naturalness", 10, min_v=0, max_v=10)
        # self.sub_lum = Param("sub_lum", 100, min_v=0, max_v=255)
        # self.shift_x = Param("shift_x", 0, min_v=-800, max_v=800)
        # self.shift_y = Param("shift_y", 0, min_v=-600, max_v=600)

        self.show_image = Param("show_images", 1, min_v=1, max_v=10)
        self.limit_image = Param("limit_image", 4, min_v=1, max_v=10)
        self.debug_show = Param(
            "show_debug",
            "show_normal",
            lst_value=[
                "show_normal",
                "show_sat",
                "show_con"])
        self.show_hdr = Param("show_hdr", False)
        self.index = 0
        self.images = []
        self.imgs = []
        self.first_time = True

    def execute(self, image):
        show_hdr = self.show_hdr.get()
        limit_image = self.limit_image.get()
        len_image = len(self.images)
        if len_image == limit_image:
            self.images[self.index - 1] = image
            self.index += 1
            if self.index > limit_image:
                self.index = 1
        elif len_image < limit_image:
            self.images.append(image)
            self.index += 1
        else:
            self.images.pop()
            if self.index > limit_image:
                self.index = limit_image

        len_image = len(self.images)

        show_no = self.show_image.get()
        show_no = len_image if show_no > len_image else show_no

        if not show_hdr:
            return self.images[show_no - 1]
        nature = self.naturalness.get()
        if nature:
            nature /= 10.0
        return self.get_hdr(self.images, strength=self.strength.get(),
                            naturalness=nature)

    """
    SOURCE: https://sites.google.com/site/bpowah/hdrandpythonpil
    a collection of images to merge into HDR

    blend an arbitrary number of photos into a single HDR image
    or several images with various combinations of HDR parameters

    it is assumed that project folders contain all the images you want to merge
    case = folder name
    cur_dir = folder where the project folders are located
    images are auto-sorted by degree of exposure (image brightness)
    """

    def get_masks(self, imgs, cur_str):
        """
        create a set of masks from a list of images
        (one mask for every adjacent pair of images
        """
        masks = []
        mask_ct = len(imgs) - 1
        imgs = [self.bal(img.convert(mode='L'), cur_str) for img in imgs]
        for i in range(mask_ct):
            blend_fraction = .5  # 1. - (float(i)+.5)/float(mask_ct)
            m = Image.blend(imgs[i], imgs[i + 1], blend_fraction)
            masks.append(m)
        return masks

    def bal(self, im, cur_str):
        """
        adjust the balance of the mask
        (re-distribute the histogram so that there are more
        extreme blacks and whites)
        like increasing the contrast, but without clipping
        and maintains overall average image brightness
        """
        h = im.histogram()
        ln = range(len(h))
        up = [sum(h[0: i]) for i in ln]
        lo = [sum(h[i:-1]) for i in ln]
        ct = sum(h)
        st = int(cur_str * 255.)

        lut = [i + st * up[i] * lo[i] * (up[i] - lo[i]) / ct ** 3 for i in ln]
        for i in ln:
            if lut[i] < 1:
                lut[i] = 1
            if lut[i] > 255:
                lut[i] = 255
        return im.point(lut)

    def merge(self, imgs, cur_str):
        """
        combine a set images into a smaller set by combinding all
        adjacent images
        """
        masks = self.get_masks(imgs, cur_str)
        imx = lambda i: Image.composite(imgs[i], imgs[i + 1], masks[i])
        return [imx(i) for i in range(len(masks))]

    def merge_all(self, imgs, cur_str):
        """
        iteratively merge a set of images until only one remains
        """
        while len(imgs) > 1:
            imgs = self.merge(imgs, cur_str)
        return imgs[0]

    def get_hdr(self, images, strength=0.0, naturalness=1.0):
        """
        process the hdr image(s)
        strength - a float that defines how strong the hdr
                   effect should be
                 - a value of zero will combine images by using a
                   greyscale image average
                 - a value greater than zero will use higher contrast
                   versions of those greyscale images
                 - suggest you a value between 0.0 and 2.0
        naturalness - values between zero and one
                 - zero will be a very high-contrast image
                 - 1.0 will be a very flat image
                 - 0.7 to 0.9 tend to give the best results
        """
        imgs = copy([Image.fromarray(img) for img in images])

        sat_img = self.merge_all(imgs, strength)
        if self.debug_show.get_pos_list() == 1:
            return np.array(sat_img)
        imgs.reverse()

        con_img = self.merge_all(imgs, strength)
        if self.debug_show.get_pos_list() == 2:
            return np.array(con_img)

        """
        combines a saturated image with a contrast image
        and puts them in a dictionary of completed images
        """
        images = Image.blend(con_img, sat_img, naturalness)
        images = np.array(images)
        return images