相信對 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了,到這裏應該就能夠結束了,源碼能夠在 這裏 獲得,裏面包含本文全部涉及的圖片,素材和代碼。
若是各位大兄弟,有更好的設計和佈局也歡迎和我交流。