摘要:本文利用ssim演算法,幫你快速打造一個“刷臉測試夫妻相”Demo出來。
本文分享自華為雲社群《情人節季,快來上傳你的女神照片,測試下你們的夫妻相》,作者: HWCloudAI 。
“夫妻相”是指兩人之間的相貌讓人感覺是一對夫妻,還有一種說法是指夫妻之間面容相似。
有研究認為:兩個人在一起生活得久了,表情動作彼此模仿,會越來越像。其實是因為大多數人都珍愛自己,看到跟自己相像的人格外順眼,從一開頭就是拿自己當範本選擇另一半。“夫妻相”的大抵意思是因為常常接觸,心靈相傾,習慣趨同,相同的作息、腸道菌落交換等相互影響,以致到了面容相像。夫妻相是面容相像,心靈相傾,習慣趨同,相互影響。
世界各地都有類似的說法:人們容易被面容與自己有共同之處的人吸引。一些進化生物學家認為,這是因為我們潛意識裡覺得,與自己長相相似的人更值得信任。然而也有研究表明,當動物處於壓力下,它們更傾向與同伴中遺傳距離較遠的個體交配。
儘管上述描述在當今心理學、生物學方面有爭議,但是大多數人還是比較認同“夫妻相”這一說法的。(以上“夫妻相”解釋來自百度百科)
基於此,本文利用ssim演算法,幫你快速打造一個“刷臉測試夫妻相”Demo出來。
夫妻相似度 ssim演算法原理
SSIM(structural similarity)是一種用來衡量圖片相似度的指標,也可用來判斷圖片壓縮後的質量。
基本原理:
其中有幾個需要注意的點:
C1、C2、C3為常數,避免分母接近於0時造成的不穩定性。
SSIM函式S具有對稱性、有界性(不超過1)和最大值唯一性(當且僅當x=y時,S=1,表示兩幅圖一樣)。
上述S函式為C3=C2/2的簡化形式。
(更多SSIM介紹可自行搜尋論文《Image Quality Assessment: From Error Visibility to Structural Similarity》)
注意事項:
- 本案例使用框架:PyTorch-1.8
- 本案例使用硬體規格:CPU: 2核 4GB
- 本案例的AI Gallery連結 上傳你的女神照片,測試下你們的夫妻相
步驟一:下載需要的海報檔案和字型
import os import os.path as osp import moxing as mox parent = osp.join(os.getcwd(),'Valentine') if not os.path.exists(parent): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/Valentine',parent) if os.path.exists(parent): print('Download success') else: raise Exception('Download Failed') else: print("Model Package already exists!")
INFO:root:Using MoXing-v2.1.0.5d9c87c8-5d9c87c8 INFO:root:Using OBS-Python-SDK-3.20.9.1 Download success
步驟二:使用ssim演算法計算夫妻相
import numpy as np import cv2 import random import matplotlib.pyplot as plt from matplotlib import font_manager import warnings from scipy.signal import convolve2d from PIL import Image,ImageDraw,ImageFont warnings.filterwarnings('ignore')
def matlab_style_gauss2D(shape=(3,3),sigma=0.5): """ 2D gaussian mask - should give the same result as MATLAB's fspecial('gaussian',[shape],[sigma]) """ m,n = [(ss-1.)/2. for ss in shape] y,x = np.ogrid[-m:m+1,-n:n+1] h = np.exp( -(x*x + y*y) / (2.*sigma*sigma) ) h[ h < np.finfo(h.dtype).eps*h.max() ] = 0 sumh = h.sum() if sumh != 0: h /= sumh return h def filter2(x, kernel, mode='same'): return convolve2d(x, np.rot90(kernel, 2), mode=mode) def compute_ssim(im1, im2, k1=0.01, k2=0.04, win_size=11, L=255): if not im1.shape == im2.shape: raise ValueError("Input Imagees must have the same dimensions") if len(im1.shape) > 2: raise ValueError("Please input the images with 1 channel") M, N = im1.shape C1 = (k1*L)**2 C2 = (k2*L)**2 window = matlab_style_gauss2D(shape=(win_size,win_size), sigma=0.5) window = window/np.sum(np.sum(window)) if im1.dtype == np.uint8: im1 = np.double(im1) if im2.dtype == np.uint8: im2 = np.double(im2) mu1 = filter2(im1, window, 'valid') mu2 = filter2(im2, window, 'valid') mu1_sq = mu1 * mu1 mu2_sq = mu2 * mu2 mu1_mu2 = mu1 * mu2 sigma1_sq = filter2(im1*im1, window, 'valid') - mu1_sq sigma2_sq = filter2(im2*im2, window, 'valid') - mu2_sq sigmal2 = filter2(im1*im2, window, 'valid') - mu1_mu2 ssim_map = ((2*mu1_mu2+C1) * (2*sigmal2+C2)) / ((mu1_sq+mu2_sq+C1) * (sigma1_sq+sigma2_sq+C2)) return np.mean(np.mean(ssim_map)) def img_show(similarity, img1, img2, name1, name2): # similarity = random.uniform(60,100) zt = "./Valentine/方正蘭亭準黑_GBK.ttf" my_font = font_manager.FontProperties(fname = zt,size =20 ) img1 = cv2.resize(img1, (520, 520)) img2 = cv2.resize(img2, (520, 520)) imgs = np.hstack([img1, img2]) imgs2 = imgs[:,:, ::-1] plt.axis('off') plt.title('{0} VS {1} \n CP指數: {2}%'.format(name1, name2, round(similarity, 2)), fontproperties=my_font) plt.imshow(imgs2) path = "a.jpg" cv2.imwrite(path, imgs)
加入人臉檢測
def getFaces(gray): cascPath = "/home/ma-user/anaconda3/envs/PyTorch-1.8/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_default.xml" faceCascade = cv2.CascadeClassifier(cascPath) im1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # Detect faces faces = faceCascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, flags=cv2.CASCADE_SCALE_IMAGE ) return faces
步驟三:修改預置的影片和圖片
在Valentine資料夾下中,有一個預置的1.png和2.png圖片,大家可以將裡面的圖片替換成自己的, 圖片的名稱不建議修改,如果修改成其他的名稱,後面的路徑也要相應的修改,上傳的圖片不要太大,儘量使用正臉的圖片。
if __name__ == '__main__': name1 = input('請輸入圖1照片姓名: \n') name2 = input('請輸入圖2照片姓名: \n') img1_path = 'Valentine/1.png' img2_path = 'Valentine/2.png' img1 = cv2.imread(img1_path) img2 = cv2.imread(img2_path) im1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) im2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) im1_faces = getFaces(im1) im2_faces = getFaces(im2) if len(im1_faces) !=1 or len(im2_faces)!= 1: raise ValueError("輸入圖片需要包含一個人臉") im1 = cv2.resize(im1, (520,520)) im2 = cv2.resize(im2, (520,520)) similarity = compute_ssim(im1, im2)*100 if similarity == 100: raise ValueError("圖片重複! 請重新上傳圖片") img_show(similarity, img1, img2, name1, name2)
請輸入圖1照片姓名:
王強
請輸入圖2照片姓名:
李欣
image = Image.open("a.jpg") image = image.resize((498,278))
步驟四:列印輸出海報
import os from PIL import Image,ImageDraw,ImageFont,ImageFilter from PIL import ImageFile ImageFile.LOAD_TRUNCATED_IMAGES = True
#@title 請在下面填寫創作者 : def gen_poster(img,txt1,txt2,path): font1 = ImageFont.truetype(zt,42) font2 = ImageFont.truetype(zt,24) img_draw = ImageDraw.Draw(img) img_draw.text((197,629), txt1, font=font1,fill='#961900') img_draw.text((152,689), txt2, font=font2, fill='#252b3a') img.filter(ImageFilter.BLUR) img.save(path) template_img = "./Valentine/ValentinPoster.png" zt = "./Valentine/方正蘭亭準黑_GBK.ttf" temp_image = Image.open(template_img) temp_image.paste(image ,(40,266)) title_char = str(round(similarity,1)) + "%" author_char = "王強" #@param {type:"string"} savepath = 'ValentinPoster.png' # 海報圖片路徑 gen_poster(temp_image,title_char,author_char,savepath) Image.open(savepath) # 顯示圖片