生成Chaos风格的PhotoMosaic效果,chaosphotomosaic,platform: li
生成Chaos风格的PhotoMosaic效果,chaosphotomosaic,platform: li
platform: linux python2.7
Dependency: PIL
Waring: EXPERIMENTAL, may damage your photo files, so try it in a new experimental directory!
Demo: https://1a1rrq.sn2.livefilestore.com/y1p7DQkSgKd5dLtkOiUXpx6ACTajjZYAMtiwrPn3jkW3AzQrvwl9Ao76dCvM6bLWoa8nBKIxqQzGlXC1_ARqTVU2XJgVTkOjaCG/xxx.png?psid=1
More refer to http://reverland.org/python/2013/02/19/yet-another-photomosaic-generator/ or https://github.com/reverland/scripts/blob/master/python/yapmg.py
#! /bin/env python# -*- coding: utf-8 -*-'''YAPMG -- Yet Another PhotoMosaic Generator written in Python'''import Imageimport ImageOpsimport osimport randomimport ImageStatimport cPickle as p__author__ = "Reverland (lhtlyy@gmail.com)"def add_frame(image): '''Add frame for image.''' im = ImageOps.expand(image, border=int(0.01 * max(image.size)), fill=0xffffff) return imdef rotate_image(image, degree): '''Rotate images for specific degree. Expand to show all''' if image.mode != 'RGBA': image = image.convert('RGBA') im = image.rotate(degree, expand=1) return imdef drop_shadow(image, offset, border=0, shadow_color=0x444444): """Add shadows for image""" # Caclulate size fullWidth = image.size[0] + abs(offset[0]) + 2 * border fullHeight = image.size[1] + abs(offset[1]) + 2 * border # Create shadow, hardcode color shadow = Image.new('RGBA', (fullWidth, fullHeight), (0, 0, 0)) # Place the shadow, with required offset shadowLeft = border + max(offset[0], 0) # if <0, push the rest of the image right shadowTop = border + max(offset[1], 0) # if <0, push the rest of the image down shadow.paste(shadow_color, [shadowLeft, shadowTop, shadowLeft + image.size[0], shadowTop + image.size[1]]) shadow_mask = shadow.convert("L") # Paste the original image on top of the shadow imgLeft = border - min(offset[0], 0) # if the shadow offset was <0, push right imgTop = border - min(offset[1], 0) # if the shadow offset was <0, push down shadow.putalpha(shadow_mask) shadow.paste(image, (imgLeft, imgTop)) return shadowdef process_image(filename, newname): '''convert image to png to support transparency''' if filename.split('.')[-1] != 'png': im = Image.open(filename) im.save(newname + '.png') print "processing image file %s" % filename return 1def process_directory(path): os.chdir(path) count = 1 for filename in os.listdir(path): ext = filename.split('.')[-1] if ext == 'jpeg' or ext == 'jpg': process_image(filename, str(count)) os.remove(filename) count += 1 return 1def thumbnail(im, size): """thumnail the image""" im.thumbnail(size, Image.ANTIALIAS) return im# Just for fundef chao_image(path, size=(800, 800), thumbnail_size=(50, 50), shadow_offset=(10, 10), backgroud_color=0xffffff): image_all = Image.new('RGB', size, backgroud_color) for image in os.listdir(path): if image.split('.')[-1] == 'png': im = Image.open(image) degree = random.randint(-30, 30) im = thumbnail(rotate_image(drop_shadow(add_frame(im), shadow_offset), degree), thumbnail_size) image_all.paste(im, (random.randint(-thumbnail_size[0], size[0]), random.randint(-thumbnail_size[1], size[1])), im) return image_all## May not usefuldef rgb2xyz(im): """rgb to xyz""" rgb2xyz = (0.412453, 0.357580, 0.180423, 0, 0.212671, 0.715160, 0.072169, 0, 0.019334, 0.119193, 0.950227, 0) out = im.convert("RGB", rgb2xyz) return outdef average_image(im): """return average (r,g,b) for image""" color_vector = [int(x) for x in ImageStat.Stat(im).mean] return color_vectordef compare_vectors(v1, v2): """compare image1 and image2, return relations""" if len(v1) == len(v2): distance = 0 for i in xrange(len(v1)): distance += (v1[i] - v2[i]) ** 2 return distance else: print "vector not match in dimensions"#for r, g, b in list(im.getdata())def tile_dict(path): """Return list of average (R,G,B) for image in this path as dict.""" dic = {} for image in os.listdir(path): if image.split('.')[-1] == 'png': try: im = Image.open(image) except: print "image file %s cannot open" % image continue if im.mode != 'RGB': im = im.convert('RGB') dic[image] = average_image(im) return dicdef thumbnail_background(im, scale): """thumbnail backgroud image""" newsize = im.size[0] / scale, im.size[1] / scale im.thumbnail(newsize) print 'thumbnail size and the number of tiles %d X %d' % im.size return im.sizedef find_similar(lst, dic): """for lst([R, G, B], Calculate which key-value in dic has the most similarity.Return first 10)""" similar = {} for k, v in dic.items(): similar[k] = compare_vectors(v, lst) # if len(v) != len(lst): # print v, len(v), lst, len(lst) similar = [(v, k) for k, v in similar.items()] # Not good, lost the same Score similar.sort() return similar[:10]def get_image_list(im, dic): """receive a thumbnail image and a dict of image to be mosaic, return tiles(filename) in order(as a list)""" lst = list(im.getdata()) tiles = [] for i in range(len(lst)): #print find_similar(lst[i], dic)[random.randrange(10)][1] tiles.append(find_similar(lst[i], dic)[random.randrange(10)][1]) return tilesdef paste_chaos(image, tiles, size, shadow_off_set=(30, 30)): """size is thumbnail of backgroud size that is how many tiles per line and row""" # image_all = Image.new('RGB', image.size, 0xffffff) image_all = image lst = range(len(tiles)) random.shuffle(lst) fragment_size = (image.size[0] / size[0], image.size[1] / size[1]) print 'tiles size %d X %d' % fragment_size print 'number of tiles one iteration: %d' % len(lst) for i in lst: im = Image.open(tiles[i]) degree = random.randint(-20, 20) im = thumbnail(rotate_image(drop_shadow(add_frame(im), shadow_off_set), degree), (fragment_size[0] * 3 / 2, fragment_size[1] * 3 / 2)) x = i % size[0] * fragment_size[0] + random.randrange(-fragment_size[0] / 2, fragment_size[0] / 2) y = i / size[0] * fragment_size[1] + random.randrange(-fragment_size[1] / 2, fragment_size[1] / 2) # print x, y image_all.paste(im, (x, y), im) return image_alldef main(filename, n, scale, iteration, path='./'): # 0. select an big image for mosaic print "open %s" % filename im = Image.open(filename) # 1. process image as png to support transparency print "process directory %s" % path process_directory(path) # 2. get a dict for path print "get tile dict for path `%s`" % path try: with open('dic.txt', 'r') as f: dic = p.load(f) except: dic = tile_dict(path) with open('dic.txt', 'wb') as f: p.dump(dic, f) # 3. thumbnail the big image for compare print "thumbnail background for compare" # n = 30 # 原始图片缩为多少分之一 # scale = 3 # 原始图片放大倍数 big_size = im.size[0] * scale, im.size[1] * scale im_chao = Image.new('RGB', big_size, 0xffffff) imb_t_size = thumbnail_background(im, n) print "how may tiles: %d X %d" % imb_t_size print 'number of iterations: %d' % iteration for i in range(iteration): print 'iteration: %d' % (i + 1) # 4. get a list of smail image for mosaic print "get pic list" im_tiles = get_image_list(im, dic) # 5. paste in chaos style print "generate final image" im_chao = paste_chaos(im_chao, im_tiles, imb_t_size) return im_chaoif __name__ == '__main__': im = main('../mm.jpg', 15, 5, 2) im.save('../final3.png') im.show()#该片段来自于http://byrx.net
相关内容
- 绘制人人好友关系图,绘制人人好友,依赖:networkx
- mysql数据导入到sqlite3中,数据导入sqlite3,家里的路由器
- 获取电影最新下载列表,获取电影最新下载,# coding=gb
- 打开文件对话框,,from tkinter
- Session for Tornado(Redis),tornadoredis,session id的生
- 使用python登录人人网并发表状态,python登录人人发表
- 使用Python解决FizzBuzz问题,python解决fizzbuzz,FizzBuzz问题描
- 文件夹对比,,买了个移动硬盘备份 但是
- 简单模拟编译前端过程,简单模拟编译过程,学了几天
- 文本文件常用工具,,common_lib/u
评论关闭