千圖成像!祝可愛的小伙伴們圣誕快樂🎅
- 前言
- 一、🎄圣誕樹🎄
- 二、代碼分析
- 1.頭像爬取
- 2.千圖成像
- 寫在最后
前言
當走上街頭時能隱約察覺到多了些許“紅白綠”的色彩,那是:圣誕老人🎅、雪花??、圣誕樹🎄,彌紅燈閃爍,各類促銷活動海報令郎滿目,沒有錯,圣誕節快來了~
從寫博客開始,一路上得到了不少小伙伴的支持和鼓勵,而這周的總排名不偏不倚,恰好100名整,我想,這大概是某種巧合,更確切來說應該是一種激勵,近些日,嚴酷寒冬似乎柔情了許多,有了那么幾日的柔柔暖陽,而我希望可以把這份溫暖也帶給大家,
我將用粉絲的頭像拼接出一幅圣誕樹,正所謂,“千圖成像,集萬千之美”,
一、🎄圣誕樹🎄

該圖的像素為6200x10250,將其區域放大后的效果為:

今天所用到的代碼是比較通用的,只需要替換背景圖和圖片庫即可打造屬于你自己的專屬圖片,詳情分析,客觀您往下瞅瞅~
帥小伙!圣誕來襲,還不趕快用來表白一波,還在猶豫啥呢?
二、代碼分析
1.頭像爬取
通過爬蟲將粉絲的頭像下載到本地,具體分析大家可以參考我之前的博客【前方高能!看小伙是怎么表白粉絲的】,完整代碼如下:
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 17 12:27:33 2020
@author: kimol_love
"""
import requests
def get_fansInfo():
'''
獲取粉絲相關資訊
'''
url = 'https://me.csdn.net/api/relation/index?pageno=%d&pagesize=%d&relation_type=fans' # 介面地址
cookies = {} # CSDN登陸后的cookies
headers = { # 請求頭
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Referer': 'https://i.csdn.net/',
'Origin': 'https://i.csdn.net',
'Connection': 'keep-alive',
'TE': 'Trailers',
}
# 獲取粉絲總數
res = requests.get(url%(1,10),headers=headers,cookies=cookies)
res_json = res.json()
N_fans = res_json['data']['data_all']
print('一共有%d個粉絲'%N_fans)
# 獲取全部粉絲資料
res = requests.get(url%(1,N_fans),headers=headers,cookies=cookies)
res_json = res.json()
return res_json
def download_avatar(username,url):
'''
下載用戶頭像
'''
savePath = './avatars' # 頭像存盤目錄
res = requests.get(url)
with open('%s/%s.jpg'%(savePath,username),'wb') as f:
f.write(res.content)
if __name__ == '__main__':
fans = get_fansInfo()
for f in fans['data']['list']:
username = f['fans'] # 用戶名
url = f['avatar'] # 頭像地址
download_avatar(username,url)
print('用戶"%s"頭像下載完成!'%username)
將頭像下載完畢并去重,結果如下:

一共有2796張非重復圖片,有了它們,我們便可以開始——搞事情!
2.千圖成像
所謂千圖成像就是用很多張圖片拼接成一張完整的圖片,它需要兩個部分:一張背景圖,一個圖片庫,根據背景圖的結構用圖片庫中的圖片來進行拼接,最終形成新的圖片,
一種最簡單直觀的思路便是:遍歷背景圖中的每個像素點,并用圖庫中與之顏色最相近的圖片粘貼在這個位置,
因此,我們首先需要計算每個圖片的“平均顏色”,即圖片像素點(R,G,B)的平均值,代碼如下:
def compute_mean(imgPath):
'''
計算平均(R,G,B)
'''
img = Image.open(imgPath)
img = img.convert('RGB')
imgArray = np.array(img)
R = np.mean(imgArray[:,:,0])
G = np.mean(imgArray[:,:,1])
B = np.mean(imgArray[:,:,2])
return (R,G,B)
遍歷圖片庫中的每張圖片,并得到它們的平均距離,生成一個圖片串列,以便后續的使用:
def get_imgList(imgDir):
'''
獲取圖片串列(圖片目錄及平均顏色)
'''
imgList = []
for imgName in os.listdir(imgDir):
path = imgDir+imgName
color = compute_mean(path)
imgList.append({'path':path,'RGB':color})
return imgList
該串列的每個元素是一個字典,包括了path和RGB,分別表示圖片的路徑以及圖片的平均顏色,如下:

在得到了圖片的“平均顏色”后,便是比較背景圖的像素點與它的相似性,這里采用了歐式距離:
def compute_distance(color1, color2):
'''
計算兩張圖的顏色差
'''
dis = 0
for i in range(len(color1)):
dis += (color1[i]-color2[i])**2
dis = dis**0.5
return dis
剩下的便是遍歷背景圖,并進行比較填充,代碼如下:
def create_image(bgImg,imgDir,N=10,M=50):
'''
根據背景圖,用頭像填充出新圖
bgImg:背景圖地址
imgDir:頭像目錄
N:背景圖縮放的倍率
M:頭像的大小(MxM)
'''
# 獲取圖片串列
imgList = get_imgList(imgDir)
# 讀取背景圖
bg = Image.open(bgImg)
bg = bg.resize((bg.size[0]//N,bg.size[1]//N)) # 縮放
bgArray = np.array(bg)
width = bg.size[0]*M # 新生成圖片的寬度
height = bg.size[1]*M # 新生成圖片的高度
# 創建空白的新圖
newImg = Image.new('RGB',(width,height))
# 回圈填充圖
for x in range(bgArray.shape[0]):
for y in range(bgArray.shape[1]):
## 找到距離最小的圖片
minDis = 10000
index = 0
for img in imgList:
dis = compute_distance(img['RGB'],bgArray[x][y])
if dis < minDis:
index = img['path']
minDis = dis
## 填充
tempImg = Image.open(index)
tempImg = tempImg.resize((M,M))
newImg.paste(tempImg,(y*M,x*M))
print('(%d, %d)'%(x,y))
# 保存圖片
newImg.save('千圖成像.jpg')
呼叫它:
create_image('bg.jpg','./avatars(dr)/',5,50)
函式的輸入有bgImg、imgDir、N、M,它們分別表示:
| 引數 | 含義 |
|---|---|
| bgImg | 背景圖的地址 |
| imgDir | 圖片庫的目錄 |
| N | 背景圖的壓縮比率 |
| M | 填充的圖片大小 |
注:imgDir最后需要有目錄連接符/,否則會報錯;N是為了將背景圖的尺寸進行調整壓縮,否則容易因為像素點太多而執行緩慢,
最后,代碼一Run,小圖在手,簡單的快樂,美滋滋~
寫在最后
由于kimol君太想趕在圣誕前將這份禮物送出,所以代碼以及文字略顯倉促,還望大家見諒,
客觀來說,該代碼的執行效率并不高,特別是當N設定得較小(即背景圖片像素點很多)或者圖片庫中的圖片很多時,針對這個問題,也有很多優化方法,例如采用圖片向量的方式對圖片進行編碼,進而比較等等,感興趣的小伙伴可以參考這篇文章,
最后,提前祝最可愛的小伙伴們圣誕快樂🎅,愿我們聚于一圖,煥盡萬丈芒!另祝即將奔赴考研戰場的小伙伴考的都會,會的都考!
我是kimol君,咋們下次再會~

創作不易,大俠請留步… 動起可愛的雙手,來個贊再走唄 (???←?)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/240060.html
標籤:python
