前言
當走上街頭時能隱約察覺到多了些許“紅白綠”的色彩,那是:聖誕老人、雪花❄️、聖誕樹。彌紅燈閃爍,各類促銷活動海報令郎滿目。沒有錯,聖誕節快來了~
從寫部落格開始,一路上得到了不少小夥伴的支援和鼓勵,而這周的總排名不偏不倚,恰好100名整。我想,這大概是某種巧合,更確切來說應該是一種激勵。近些日,嚴酷寒冬似乎柔情了許多,有了那麼幾日的柔柔暖陽,而我希望可以把這份溫暖也帶給大家。
我將用粉絲的頭像拼接出一幅聖誕樹,正所謂,“千圖成像,集萬千之美”。
原文地址:千圖成像!祝可愛的小夥伴們聖誕快樂_kimol君的部落格-CSDN部落格
一、聖誕樹圖片上傳失敗
重試
該圖的畫素為6200x10250,將其區域性放大後的效果為:
今天所用到的程式碼是比較通用的,只需要替換背景圖和圖片庫即可打造屬於你自己的專屬圖片。詳情分析,客觀您往下瞅瞅~
帥小夥!聖誕來襲,還不趕快用來表白一波,還在猶豫啥呢?
二、程式碼分析1.頭像爬取透過爬蟲將粉絲的頭像下載到本地,具體分析大家可以參考我之前的部落格【前方高能!看小夥是怎麼表白粉絲的】,完整程式碼如下:
# -*- coding: utf-8 -*-"""Created on Sat Oct 17 12:27:33 2020@author: kimol_love"""import requestsdef 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_jsondef 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,它們分別表示:
引數
含義
注:imgDir最後需要有目錄連線符/,否則會報錯;N是為了將背景圖的尺寸進行調整壓縮,否則容易因為畫素點太多而執行緩慢。
最後,程式碼一Run,小圖在手,簡單的快樂,美滋滋~
寫在最後由於kimol君太想趕在聖誕前將這份禮物送出,所以程式碼以及文字略顯倉促,還望大家見諒。
客觀來說,該程式碼的執行效率並不高,特別是當N設定得較小(即背景圖片畫素點很多)或者圖片庫中的圖片很多時。針對這個問題,也有很多最佳化方法,例如採用圖片向量的方式對圖片進行編碼,進而比較等等。感興趣的小夥伴可以參考這篇文章。
最後,提前祝最可愛的小夥伴們聖誕快樂,願我們聚於一圖,煥盡萬丈芒!另祝即將奔赴考研戰場的小夥伴考的都會,會的都考!
我是kimol君,咋們下次再會~