相信对 NBA 感兴趣的大兄弟必定不会对球星卡陌生吧,虽然不知道我们这个圈子对 NBA 感兴趣的大兄弟多很少。可是,不感兴趣也问题不大,本文阐述的方法实际上是通用的图片合成方法。javascript
让咱们来看一张球星卡:java
这种球星卡能够划分为5个部分python
今天咱们要干的事情就是找到这5个素材而后用 Python 把他们组合起来,那么这个时候确定有大兄弟会有疑问了,直接用 PS 套起来不就行了吗,讲道理这样作确实方便快捷,可是前提是你只作这一张卡,当你要为联盟大概450名球员制做球星卡的时候,你就须要一个脚原本帮助你完成了(对 PS 不太熟,若是 PS 也能够,能够告诉我哈)。git
这篇文章须要一点 Python 基础,彻底不了解 Python 的大兄弟最好去学习一点基础知识再看。github
OK 让咱们开始吧!数据库
就像开头提到的,咱们须要5种素材。这5种素材我都会提供若干个给你们练手。服务器
上面的图片实际上只有4个素材,还有一个就是球员的名字了,球员的名字咱们能够在组合过程当中使用 ImageDraw 和 ImageFont 加载球员姓名。app
为了不字体路径和中文乱码的问题,我还提供了一个微软雅黑的字体。函数
素材能够在 这里 clone 或者下载,声明:本文全部涉及的素材和图片仅供交流学习使用。布局
咱们的场景是为联盟中的全部球员制做球星卡,那么全部的球员天然是从数据库里面查出来的了,这里为了练习,咱们能够 mock 一些数据(虽然,讲道理,波什并不能放在 SUPER 里面,可是这里只有一张装饰边框图,因此就勉为其难的和吾皇放在一个等级了)。
mock_data = [
{
'id': 1966,
'cn_name': '勒布朗-詹姆斯',
'team_id': 5,
'category': 'SUPER'
},
{
'id': 1977,
'cn_name': '克里斯-波什',
'team_id': 14,
'category': 'SUPER'
}
]复制代码
有数据以后,咱们就来遍历这些球员,找到咱们须要的属性,再传入到一个组合函数中。
def compose_all(all):
for player in all:
id = player['id']
# if id == 1966:
if True:
category = player['category']
player_img = str(id) + '.png'
team_id = player['team_id']
team_img = str(team_id) + '.png'
name = player['cn_name']
category = player_category.index(category) + 1
category_img = 'card_bg_' + str(category) + '.png'
output_name = str(id) + '.png'
print('start compose ' + str(id))
compose(player_img, name, team_img, category_img, output_name)复制代码
这里有个我的习惯,由于常常在服务器上写一些脚本,全部if True:
那个地方就是调试用的,当一个球员调试没问题以后,注释掉,跑代码,这样能够不用再调整缩进了,不知道其余的大兄弟这个地方喜欢怎么写。
在这里我默认会对球员分档(根据一些数据信息)
player_category = ["SUPER", "CORE", "BLUE", "SIX", "BENCH"]复制代码
对应档位的装饰边框分别为card_bg_1.png
,card_bg_2.png
等。
检查5个素材是否都拿到了:
还差一个底板背景图,由于每一个球员底板背景图都同样,因此在组合函数中直接使用就行了。
在咱们去组合球星卡以前,还有一个问题须要解决,那就是咱们不能保证全部素材都在同一个目录下,那么咱们就须要给每一个素材指定一个目录,这样咱们在组合球星卡的时候就能够一马平川了。
team_path = './logo/'
player_path = './player_img/'
output_path = './trading_cards/'
font_file = './assets/msyh.ttf'
card_decorate_path = './assets/'复制代码
设置好路径以后写上咱们的组合函数,为了保证这个函数的正常运行,咱们须要导入三个模块。
import os
import numpy as np
from PIL import Image, ImageFont, ImageDraw复制代码
若是提示没有找到模块,请使用下面的命令进行安装
pip install Pillow
pip install numpy复制代码
Pillow 关于图片处理的详细文档请参考 Pillow
下面是咱们的组合函数
def compose(player_img, name, team_logo, category_img, output_name):
card_bg = card_decorate_path + 'bg.png'
player_img_offset_height = 15
if not os.path.isfile(player_path + player_img):
need_manual_compose.append(player_img)
print(player_path + player_img + ' is not exist')
return
player_img = Image.open(player_path + player_img).convert('RGBA')
bg_img = Image.open(card_decorate_path + category_img).convert('RGBA')
card_bg_img = Image.open(card_bg).convert('RGBA')
logo = Image.open(team_path + team_logo).convert('RGBA')
logo = logo.resize((100,100), Image.ANTIALIAS)
card_bg_img.paste(player_img, (35,player_img_offset_height), player_img)
card_bg_img.paste(bg_img, (0,0), bg_img)
card_bg_img.paste(logo, (95,315), logo)
font = ImageFont.truetype(font_file, 20)
d = ImageDraw.Draw(card_bg_img)
try:
name = unicode(name, 'utf-8')
except NameError:
name = name
d.text((12, 12), name, font=font, fill=(255,255,255))
card_bg_img.save(output_path + output_name, quality=100)复制代码
有几个问题须要说明一下:
OK,让咱们来看一看结果怎么样吧
恩,彷佛还不错,可是你们会发现波什的手没了,因此说一马平川什么的都是骗人的。
通过我我的的观察,会发现大部分的球星动做图都是和詹姆斯相似的(即球员的动做在图片中的位置是靠下的),若是下移粘贴坐标会致使球星卡的主要局域出现大面积的空白。一计不成,再生一计,咱们能够对相似波什的动做图作特殊处理,下移他们的粘贴坐标就能够了。
ok,问题来了,人眼一看就会知道哪一个动做图高哪一个动做图低,那么 Python 怎么才能知道呢?
能够看到,每张动做图的大小是同样的,可是具体的动做在图片中的分布是不同的。
这个时候咱们就须要numpy
这个库来帮助咱们把图片转换成像素矩阵,而后咱们对矩阵进行逐行扫描并记录有效像素出现的位置,这样就能够判断哪些动做图是偏高的。
def calculateUsefulHeight(img):
img = Image.open(player_path + img).convert('RGBA')
w, h = img.size
mat = np.array(img)
for i in range(mat.shape[0]):
if not allEqual(mat[i]):
return h - i
def allEqual(line):
w = len(line)
if not w:
return True
init_value = line[0][3]
step = 10
for i in range(int(round(w/step))):
if line[i * step][3] == init_value:
continue
else:
return False
return True复制代码
而后再在组合函数中加入对动做图高的特殊处理的代码就能够了。
def compose(player_img, name, team_logo, category_img, output_name):
...
# deal with high player image
h = calculateUsefulHeight(player_img)
# 这个地方的310是球星卡展现球员动做的最大高度
if h > 310:
offset = h - 310
player_img_offset_height += offset复制代码
再来跑一遍,看看效果如何。
不错,这样就能够了,尤为是一瞬间跑出来 450 张看起来效果还不错的球星卡仍是很是的爽的。
OK了,到这里应该就能够结束了,源码能够在 这里 获得,里面包含本文全部涉及的图片,素材和代码。
若是各位大兄弟,有更好的设计和布局也欢迎和我交流。