diff --git a/mosiac.py b/mosiac.py index f14aea4..edbff24 100755 --- a/mosiac.py +++ b/mosiac.py @@ -29,7 +29,7 @@ class Mosiac(): self.matrixSize = None - def openBigImage(self, imagePath, mat=(20,40)): + def openBigImage(self, imagePath, mat=(40,20)): """ Opens and initializes the big image. """ @@ -77,7 +77,7 @@ class Mosiac(): if image.mode == "P": image = image.convert(image.palette.mode) if image.mode == "RGBA": - image = alpha_composite_with_color(image).convert("RGB") + image = alpha_composite(image).convert("RGB") if image.mode == "L": image = image.convert("RGB") # image = image.convert("RGBA") @@ -117,6 +117,8 @@ class Mosiac(): cluster = {pixel: self.imageBank[pixel] for pixel in \ sort[n*num:n*num+num]} self.clusters.append(cluster) + + # shove the left overs into the last cluster self.clusters[-1].update({pixel: self.imageBank[pixel] for pixel in \ sort[-(len(sort) % num):]}) @@ -143,7 +145,7 @@ class Mosiac(): tol = int(len(dist) * self.tolerance) tol += int(tol == 0) indexs = dist.argsort()[:tol] - # choice = dist.argmin() # closet value + # choice = indexs.argmin() # closet value choice = np.random.choice(indexs) return cluster[tuple(nodes[choice])] @@ -156,6 +158,9 @@ class Mosiac(): pixels = list(self.smallImage.getdata()) for pixel in pixels: image = self.nearestImage(pixel) + image = image.convert("RGBA") + comp = Image.new("RGBA", image.size, pixel + (30,)) + image = Image.alpha_composite(image, comp).convert("RGB") self.imageMatrix.append(image) print(f"buildMatrix took: {time.time()-then} seconds.") @@ -166,12 +171,16 @@ class Mosiac(): """ then = time.time() image = Image.new("RGB", self.bigImageSize, (255,255,255)) - # self.bigImage = self.bigImage.crop((0,0,self.bigImageSize[0],self.bigImageSize[1])) + self.bigImage = self.bigImage.crop( + (0, 0, self.bigImageSize[0], self.bigImageSize[1])) n = 0 for y in range(0, self.bigImageSize[1], self.tileSize[1]): for x in range(0, self.bigImageSize[0], self.tileSize[0]): image.paste(self.imageMatrix[n], box=(x,y)) n += 1 + image = image.convert("RGBA") + self.bigImage.putalpha(50) + image = Image.alpha_composite(image, self.bigImage).convert("RGB") # self.bigImage.save(os.path.join(root, "mosiac.png"), "PNG") image.save(os.path.join(root, "mosiac.jpg"), "JPEG", optimize=True, quality=90) print(f"buildMosiac took: {time.time()-then} seconds.") @@ -189,46 +198,15 @@ def step (r,g,b, repetitions=1): return (h2, lum, v2) -def alpha_composite(front, back): - """Alpha composite two RGBA images. - +def alpha_composite(image, color=(255, 255, 255)): + """ + Alpha composite an RGBA Image with a specified color. Source: http://stackoverflow.com/a/9166671/284318 - - Keyword Arguments: - front -- PIL RGBA Image object - back -- PIL RGBA Image object - """ - front = np.asarray(front) - back = np.asarray(back) - result = np.empty(front.shape, dtype='float') - alpha = np.index_exp[:, :, 3:] - rgb = np.index_exp[:, :, :3] - falpha = front[alpha] / 255.0 - balpha = back[alpha] / 255.0 - result[alpha] = falpha + balpha * (1 - falpha) - old_setting = np.seterr(invalid='ignore') - result[rgb] = (front[rgb] * falpha + back[rgb] * balpha * (1 - falpha)) / result[alpha] - np.seterr(**old_setting) - result[alpha] *= 255 - np.clip(result, 0, 255) - # astype('uint8') maps np.nan and np.inf to 0 - result = result.astype('uint8') - result = Image.fromarray(result, 'RGBA') - return result - - -def alpha_composite_with_color(image, color=(255, 255, 255)): - """Alpha composite an RGBA image with a single color image of the - specified color and the same size as the original image. - - Keyword Arguments: - image -- PIL RGBA Image object - color -- Tuple r, g, b (default 255, 255, 255) - - """ - back = Image.new('RGBA', size=image.size, color=color + (255,)) - return alpha_composite(image, back) + image.load() # needed for split() + background = Image.new('RGB', image.size, color) + background.paste(image, mask=image.split()[3]) # 3 is the alpha channel + return background if __name__ == "__main__":