python拼图小工具------之送给女朋友的小礼物
背景:
一年N度的节日叕到了,这是一个纠结给女朋友/老婆送什么的季节。。。本着独特、心意、经济的原则,想着送老婆一个定制拼图,但普通定制拼图,无非是拿个好看的照片,发给卖家,制成拼图。确实符合上述“经济”特性,但“独特和心意”却无法凸显。于是有了本文思路–用两张图片(一般是你和她,如果是他和她,则不在本文讨论范围之内),然后通过处理生成一张由你的图拼接成她的图的样子的图,最后拿去定制,寓意是你中有我,我中有你。有点绕,具体如下,暂称最终图为拼接图。
先上效果:
该工具使用python实现,为了方便大家使用,转换成了exe文件,这样大家下载即可用。(实用主义者到此即可,需要了解实现原理或想进一步交流的小伙伴请继续!)
链接:https://pan.baidu.com/s/19HMVXpdMzKVTj8s4MJ_CGQ
提取码:miao
工具说明:
功能
用小图拼接成大图;无色彩;可放大原大图
输入
大图–会提取轮廓
放大倍数–将大图放大
小图–经过处理,按匹配大小替换大图
小图缩小倍数–小图太大会影响生成质量,建议缩小
输出
由小图组成的大图轮廓图
思路
普通的定制拼图只需一张图片;而拼接图需要两张图片A和B。
目标:
将A拼接成B的模样。
实现
实现逻辑
1.参数校验和初始化
使用tkinter完成界面展示和参数读取
2.显示进度
3.生成大图(B)和小图(A)( 目标:将A拼接成B的模样)
3.1 按比例放大图B
3.2 按比例缩小图A
4.生成样本图
将缩小后的A生成100份样本,按明暗度划分
5.计算样本图均值
6.合成
将放大后的B按照样本尺寸分块,然后逐块用合适的样本图替换
7.保存
8.清理现场
# 参数校验和初始化
checkFileAndInit(IN_FILE)
# 显示进度
showProgress()
# 生成大图和小图
generateBigAndSmallPic(IN_FILE, RATIO)
# 生成样本图
generateSamples(SMALL_FILE, 100)
# 计算样本图均值
getSmallPicAvgList()
# 合成
bigPic=doHandlePic()
# 保存
saveAndShowPic(bigPic)
# 清理
clean()
环境准备
主要是python3以及依赖库:tkinter、PIL、numpy
通过pip install 命令安装即可。
完整代码
import time
from PIL import Image
from numpy import *
import os
from tkinter import Tk, Label, StringVar, Entry, Button, mainloop, W,filedialog,ttk,LEFT
import tkinter as tk
import threading
# config value
IN_FILE = 'test.jpg'
FILE_NAME = 'test.jpg'
FILE_BASE_DIR = ''
FILE_NAME_PREX = 'test'
INPUT_SMALL_FILE = None
SHRINK_TIMES = 20
SMALL_FILE_SUFFIX = "_small"
BIG_FILE_SUFFIX = "_big"
RESULT_PIC_FORMAT = '.png'
RATIO = 1
BIG_FILE = ''
SMALL_FILE = ''
SMALL_PIC_AVG_LIST = []
SMALL_PIC_RANGE = 100
PROGRESS_VALUE = 5
root = Tk()
#get small file pixels average value
def getSmallPicAvgList():
global SMALL_PIC_RANGE
for i in range(SMALL_PIC_RANGE):
smallFile = getAbsPath(FILE_BASE_DIR, FILE_NAME_PREX + SMALL_FILE_SUFFIX + str(i) + RESULT_PIC_FORMAT)
avgSmall = average(array(Image.open(smallFile)))
SMALL_PIC_AVG_LIST.append(avgSmall)
# exchange region by small pic
def exchangeRegion(pic, picFile, box):
region = pic.crop(box)
avg = average(array(region))
dict = []
for i in range(SMALL_PIC_RANGE):
dict.append((abs(avg - SMALL_PIC_AVG_LIST[i]), i))
dict.sort()
diff_value, smallPicIndex = dict.pop(0)
matchPicFile = getAbsPath(FILE_BASE_DIR, FILE_NAME_PREX + SMALL_FILE_SUFFIX + str(smallPicIndex) + RESULT_PIC_FORMAT)
matchPic = Image.open(matchPicFile)
pic.paste(matchPic, box)
return pic
# cut picture
def generateBigAndSmallPic(inFile, ratio, isBlackWhite=True):
pil_im = Image.open(inFile)
if isBlackWhite:
pil_im = pil_im.convert('L')
w = pil_im.size[0]
h = pil_im.size[1