超簡(jiǎn)單 Python 頭像戴圣誕帽教程

還記得疫情之初,我們用Python給頭像戴口罩的文章嗎?
當(dāng)時(shí)只是簡(jiǎn)單的調(diào)用了第三方模塊將口罩圖片替換入原圖,內(nèi)容非常簡(jiǎn)短。
今天,將為大家提供一個(gè)能夠通過以下三種方式給頭像戴上圣誕帽的Python教程:
1.實(shí)時(shí)打開攝像頭讀取頭像圖佩戴圣誕帽
2.從本地讀取一幅頭像圖佩戴圣誕帽
3.從文件夾中批量讀取頭像圖佩戴圣誕帽
1.準(zhǔn)備
開始之前,你要確保Python和pip已經(jīng)成功安裝在電腦上,如果沒有,請(qǐng)?jiān)L問這篇文章:超詳細(xì)Python安裝指南?進(jìn)行安裝。
如果你用Python的目的是數(shù)據(jù)分析,可以直接安裝Anaconda:Python數(shù)據(jù)分析與挖掘好幫手—Anaconda,它內(nèi)置了Python和pip.
此外,推薦大家用VSCode編輯器,因?yàn)樗梢栽诰庉嬈飨路降慕K端運(yùn)行命令安裝依賴模塊:Python 編程的最好搭檔—VSCode 詳細(xì)指南。
Windows環(huán)境下打開 Cmd (開始-運(yùn)行-CMD),蘋果系統(tǒng)環(huán)境下請(qǐng)打開 Terminal (command+空格輸入Terminal),輸入命令安裝依賴:
pip install https://pypi.python.org/packages/da/06/bd3e241c4eb0a662914b3b4875fc52dd176a9db0d4a2c915ac2ad8800e9e/dlib-19.7.0-cp36-cp36m-win_amd64.whl#md5=b7330a5b2d46420343fbed5df69e6a3f
pip install opencv-python有兩個(gè)依賴,一個(gè)是 dlib模塊,需要通過whl文件安裝。一個(gè)是常用的opencv模塊,直接pip安裝即可。
文章源代碼fork自:amusi/Merry_Christmas_Hat
本文全部源代碼及圖片可在此下載:
https://github.com/Ckend/Merry_Christmas_Hat
如果你訪問不了Github,可在Python實(shí)用寶典公眾號(hào)后臺(tái)回復(fù):圣誕帽?下載。
2.給頭像戴上圣誕帽
為防大家沒耐心看下去,我把佩戴圣誕帽的教程提前了。
下載源代碼后,進(jìn)入源代碼的文件夾,一共有三種方式給你的頭像佩戴圣誕帽。
1.打開攝像頭讀取頭像圖:
當(dāng)攝像頭打開后,會(huì)實(shí)時(shí)出現(xiàn)佩戴著圣誕帽的你。按q保存你最喜歡的圖片即可,源代碼如下:
def?method_one(hat_img):
????"""
????方式1: 打開攝像頭讀取頭像圖
????"""
????cap = cv2.VideoCapture(0)
????if?not?cap.isOpened():
????????print('攝像頭打開失敗!')
????else:
????????print('攝像頭打開成功!')
????????print("請(qǐng)按下鍵盤上的'q',保存當(dāng)前滿意圖像!")
????????while?cap.isOpened():
????????????_, img = cap.read()
????????????cv2.imshow("img", img)
????????????k = cv2.waitKey(33) & 0xFF
????????????if(k == ord('q')):
????????????????cv2.imwrite("sefile.jpg", img)
????????????????face_flag, output = add_hat(img, hat_img)
????????????????if(-1?== face_flag):
????????????????????break
????????????????cv2.imshow("output", output)
????????????????print("請(qǐng)按下鍵盤上的任意按鍵,退出當(dāng)前程序!")
????????????????cv2.waitKey(0)
????????????????cv2.imwrite("output.jpg", output)
????????????????break
# 讀取帽子圖,第二個(gè)參數(shù)-1表示讀取為rgba通道,否則為rgb通道
hat_img = cv2.imread("hat.png", -1)
# 選擇你需要的方式
method_one(hat_img)
cv2.destroyAllWindows()這樣,通過運(yùn)行Merry_Chirstmas_Hat.py文件就能打開攝像頭并實(shí)時(shí)顯示佩戴圣誕帽的你:
python Merry_Chirstmas_Hat.py2.讀取一個(gè)圖像佩戴圣誕帽
這是最常見的使用場(chǎng)景,你只需要的源代碼文件夾下,放置你所需要佩戴圣誕帽的圖像,命名為test.jpg(或其他,只需要改函數(shù)調(diào)用里你的指定文件名稱)。
放置完成后運(yùn)行Merry_Chirstmas_Hat.py文件即可佩戴圣誕帽。
def?method_two(hat_img, filename):
????"""
????方式2: 從本地讀取一幅頭像圖
????"""
????img = cv2.imread(filename)
????success, output = add_hat(img, hat_img)
????if?not?success:
????????print("戴失敗了!")
????????return
????# 展示效果
????cv2.imshow("output", output)
????cv2.waitKey(0)
????cv2.imwrite("output.jpg", output)
# 讀取帽子圖,第二個(gè)參數(shù)-1表示讀取為rgba通道,否則為rgb通道
hat_img = cv2.imread("hat.png", -1)
# 選擇你需要的方式
method_two(hat_img, "test.jpg")
cv2.destroyAllWindows()3.?從文件夾中讀取多張頭像圖(批量處理)
在源代碼的文件夾下,創(chuàng)建一個(gè)名為images的文件夾,在里面放置所有以.jpg結(jié)尾的圖像,運(yùn)行Merry_Chirstmas_Hat.py文件后你能看到所有這些圖像佩戴圣誕帽的效果。
def?method_three(hat_img):
????"""
????方式3: 從文件夾中讀取多張頭像圖(批量處理)
????"""
????import?glob as?gb
????img_path = gb.glob("./images/*.jpg")
????for?path in?img_path:
????????img = cv2.imread(path)
????????# 添加帽子
????????success, output = add_hat(img, hat_img)
????????if?not?success:
????????????print("戴失敗了!")
????????????continue
????????# 展示效果
????????cv2.imshow("output", output)
????????cv2.waitKey(0)
????????
# 讀取帽子圖,第二個(gè)參數(shù)-1表示讀取為rgba通道,否則為rgb通道
hat_img = cv2.imread("hat.png", -1)
# 選擇你需要的方式
method_three(hat_img)
cv2.destroyAllWindows()我們的代碼默認(rèn)使用了第二種方式佩戴圣誕帽,你可以修改代碼178行的method選擇你所需要的方式。佩戴效果如下:
原圖:

佩戴效果圖:

3.原理分析
在上面的三種佩戴圣誕帽方法中,都調(diào)用了一個(gè)叫?add_hat?的函數(shù)。
顧名思義,這個(gè)函數(shù)里對(duì)原圖像做了佩戴圣誕帽的邏輯,其步驟如下:
1. 正臉識(shí)別(才好佩戴帽子到頭部)。
2. 遍歷所有人臉,取5個(gè)關(guān)鍵點(diǎn),并根據(jù)人臉大小調(diào)整帽子大小。
3. 利用alpha通道的圖像提取放帽子的區(qū)域(提取空心區(qū)域)。
4. 將原帽子覆蓋至第3步提取出來(lái)的空心區(qū)域上并放回原圖。
下面分步驟闡述:
1.正臉識(shí)別
利用了dlib中已經(jīng)訓(xùn)練好的人臉關(guān)鍵點(diǎn)檢測(cè)模型對(duì)圖像進(jìn)行提取人臉的操作:
# dlib人臉關(guān)鍵點(diǎn)檢測(cè)器(需要確保.py文件同級(jí)目錄下有shape_predictor_5_face_landmarks.dat這個(gè)文件)
predictor_path = "shape_predictor_5_face_landmarks.dat"
predictor = dlib.shape_predictor(predictor_path)
# dlib正臉檢測(cè)器
detector = dlib.get_frontal_face_detector()
# 正臉檢測(cè)
dets = detector(img, 1)
檢測(cè)到的人臉數(shù)據(jù)將會(huì)保存到dets變量中,因此dets的長(zhǎng)度將大于0.
2.遍歷人臉,取關(guān)鍵點(diǎn)并調(diào)整帽子大小
獲取保存的人臉數(shù)據(jù)的各種參數(shù),并根據(jù)這些參數(shù)對(duì)帽子進(jìn)行比例轉(zhuǎn)化:
# 如果檢測(cè)到人臉
if?len(dets) > 0:
????# 遍歷所有人臉
????for?d in?dets:
????????x, y, w, h = d.left(), d.top(), d.right()-d.left(), d.bottom()-d.top()
????????
????????# 關(guān)鍵點(diǎn)檢測(cè),5個(gè)關(guān)鍵點(diǎn)
????????shape = predictor(img, d)
????????
????????# 選取左(0)右(2)眼眼角的點(diǎn)
????????point1 = shape.part(0)
????????point2 = shape.part(2)
????????
????????# 求兩點(diǎn)中心
????????eyes_center = ((point1.x+point2.x)//2, (point1.y+point2.y)//2)
????????
????????# 根據(jù)人臉大小調(diào)整帽子大小
????????factor = 1.5????# 比例因子
????????resized_hat_h = int(
????????????round(rgb_hat.shape[0]*w/rgb_hat.shape[1]*factor))
????????resized_hat_w = int(
????????????round(rgb_hat.shape[1]*w/rgb_hat.shape[1]*factor))
????????
????????# 避免帽子高度超出圖像畫面
????????if?resized_hat_h > y:
????????????resized_hat_h = y-1
????????????
????????# 根據(jù)人臉大小調(diào)整帽子大小
????????resized_hat = cv2.resize(rgb_hat, (resized_hat_w, resized_hat_h))3. 利用alpha通道的圖像提取放帽子的區(qū)域(提取空心區(qū)域)。
通過alpha通道生成的黑白圖像作為mask,將其填充到原圖中。生成了bg.jpg.
# 用alpha通道作為mask(bitwise_not)
mask = cv2.resize(a, (resized_hat_w, resized_hat_h))
mask_inv = cv2.bitwise_not(mask)
# 帽子相對(duì)與人臉框上線的偏移量
dh = 0
dw = 0
# 原圖ROI
bg_roi = img[y+dh-resized_hat_h:y+dh,
?????????????(eyes_center[0]-resized_hat_w//3):(eyes_center[0]+resized_hat_w//3*2)]
# 原圖ROI中提取放帽子的區(qū)域
bg_roi = bg_roi.astype(float)
mask_inv = cv2.merge((mask_inv, mask_inv, mask_inv))
alpha = mask_inv.astype(float)/255
# 相乘之前保證兩者大小一致(可能會(huì)由于四舍五入原因不一致)
alpha = cv2.resize(alpha, (bg_roi.shape[1], bg_roi.shape[0]))
bg = cv2.multiply(alpha, bg_roi)
bg = bg.astype('uint8')
cv2.imwrite("bg.jpg", bg)如果你打開bg.jpg,你就會(huì)發(fā)現(xiàn)這是一個(gè)佩帶黑色模板的原圖帽子區(qū)域:

4.將原帽子覆蓋至第3步提取出來(lái)的空心區(qū)域上并放回原圖。
接下來(lái)要做的,就是將帽子替換到第3部生成的空心區(qū)域上并放回原圖:
# 提取帽子區(qū)域
hat = cv2.bitwise_and(resized_hat, resized_hat, mask=mask)
cv2.imwrite("hat.jpg", hat)
# 相加之前保證兩者大小一致(可能會(huì)由于四舍五入原因不一致)
hat = cv2.resize(hat, (bg_roi.shape[1], bg_roi.shape[0]))
# 兩個(gè)ROI區(qū)域相加
add_hat = cv2.add(bg, hat)
# 把添加好帽子的區(qū)域放回原圖
img[y+dh-resized_hat_h:y+dh, (eyes_center[0]-resized_hat_w//3):(
????eyes_center[0]+resized_hat_w//3*2)] = add_hat
return?1, img這樣,便完成了整個(gè)佩戴圣誕帽的流程。文章完整源代碼可在Python實(shí)用寶典公眾號(hào)后臺(tái)回復(fù):圣誕帽?下載。
我們的文章到此就結(jié)束啦,如果你喜歡今天的Python 實(shí)戰(zhàn)教程,請(qǐng)持續(xù)關(guān)注Python實(shí)用寶典。
有任何問題,可以在公眾號(hào)后臺(tái)回復(fù):加群,回答相應(yīng)紅字驗(yàn)證信息,進(jìn)入互助群詢問。
原創(chuàng)不易,希望你能在下面點(diǎn)個(gè)贊和在看支持我繼續(xù)創(chuàng)作,謝謝!
點(diǎn)擊下方閱讀原文可獲得更好的閱讀體驗(yàn)
Python實(shí)用寶典?(pythondict.com)
不只是一個(gè)寶典
歡迎關(guān)注公眾號(hào):Python實(shí)用寶典
