圣诞节:让Serverless送你一顶圣诞帽
圣诞节到了,我偷偷瞄了一眼,身边人的头像很和谐,我觉得这不正常:圣诞老人没给你们发帽子么?
好吧,既然圣诞老人没给大家发帽子,那Serverless架构给大家发一顶帽子吧。
先来预览一下样子,百度随便找了一个图:
image加上圣诞帽:
image看完效果,来测试一下功能(如果就是想玩一玩,可以直接使用我的这个接口):
url:
http://service-8d3fi753-1256773370.bj.apigw.tencentcs.com/release/add_christmas_hat
入参:pic,,string类型,原始图片的base64
出参:picture,string类型,戴帽子的图片base64
基本测试代码(Python3):
import base64
import urllib.request
import json
with open("test.png", 'rb') as f:
image = f.read()
image_base64 = str(base64.b64encode(image), encoding='utf-8')
url = "https://service-ly70xmyz-1256773370.sh.apigw.tencentcs.com/test/addChristmasHat"
data = {
"pic": image_base64
}
picture = json.loads(urllib.request.urlopen(urllib.request.Request(url=url, data=json.dumps(data).encode("utf-8"))).read().decode("utf-8"))["picture"]
imgData = base64.b64decode(picture)
with open('output.png', 'wb') as f:
f.write(imgData)
当然,有一些小伙伴可能想要把这个服务部署到自己的云函数上,那么就可以参考下文:
项目核心代码(Python3的函数,部署在云函数就可以):
import cv2
import dlib
import base64
import json
def addHat(img, hat_img):
print("分离rgba通道,合成rgb三通道帽子图,a通道后面做mask用")
r, g, b, a = cv2.split(hat_img)
rgbHat = cv2.merge((r, g, b))
print("dlib人脸关键点检测器,正脸检测")
predictorPath = "shape_predictor_5_face_landmarks.dat"
predictor = dlib.shape_predictor(predictorPath)
detector = dlib.get_frontal_face_detector()
dets = detector(img, 1)
print("如果检测到人脸")
if len(dets) > 0:
for d in dets:
x, y, w, h = d.left(), d.top(), d.right() - d.left(), d.bottom() - d.top()
print("关键点检测,5个关键点")
shape = predictor(img, d)
print("选取左右眼眼角的点")
point1 = shape.part(0)
point2 = shape.part(2)
print("求两点中心")
eyes_center = ((point1.x + point2.x) // 2, (point1.y + point2.y) // 2)
print("根据人脸大小调整帽子大小")
factor = 1.5
resizedHatH = int(round(rgbHat.shape[0] * w / rgbHat.shape[1] * factor))
resizedHatW = int(round(rgbHat.shape[1] * w / rgbHat.shape[1] * factor))
if resizedHatH > y:
resizedHatH = y - 1
print("根据人脸大小调整帽子大小")
resizedHat = cv2.resize(rgbHat, (resizedHatW, resizedHatH))
print("用alpha通道作为mask")
mask = cv2.resize(a, (resizedHatW, resizedHatH))
maskInv = cv2.bitwise_not(mask)
print("帽子相对与人脸框上线的偏移量")
dh = 0
bgRoi = img[y + dh - resizedHatH:y + dh,
(eyes_center[0] - resizedHatW // 3):(eyes_center[0] + resizedHatW // 3 * 2)]
print("原图ROI中提取放帽子的区域")
bgRoi = bgRoi.astype(float)
maskInv = cv2.merge((maskInv, maskInv, maskInv))
alpha = maskInv.astype(float) / 255
print("相乘之前保证两者大小一致(可能会由于四舍五入原因不一致)")
alpha = cv2.resize(alpha, (bgRoi.shape[1], bgRoi.shape[0]))
bg = cv2.multiply(alpha, bgRoi)
bg = bg.astype('uint8')
print("提取帽子区域")
hat = cv2.bitwise_and(resizedHat, cv2.bitwise_not(maskInv))
print("相加之前保证两者大小一致(可能会由于四舍五入原因不一致)")
hat = cv2.resize(hat, (bgRoi.shape[1], bgRoi.shape[0]))
print("两个ROI区域相加")
addHat = cv2.add(bg, hat)
print("把添加好帽子的区域放回原图")
img[y + dh - resizedHatH:y + dh,
(eyes_center[0] - resizedHatW // 3):(eyes_center[0] + resizedHatW // 3 * 2)] = addHat
return img
def main_handler(event, context):
try:
print("将接收到的base64图像转为pic")
imgData = base64.b64decode(json.loads(event["body"])["pic"])
with open('/tmp/picture.png', 'wb') as f:
f.write(imgData)
print("读取帽子素材以及用户头像")
hatImg = cv2.imread("hat.png", -1)
userImg = cv2.imread("/tmp/picture.png")
output = addHat(userImg, hatImg)
cv2.imwrite("/tmp/output.jpg", output)
print("读取头像进行返回给用户,以Base64返回")
with open("/tmp/output.jpg", "rb") as f:
base64Data = str(base64.b64encode(f.read()), encoding='utf-8')
return {
"picture": base64Data
}
except Exception as e:
return {
"error": str(e)
}
使用方法:
解压出来:
image打开命令行工具,进入到项目目录:
image执行serverless --debug:
image可能会唤起二维码登录,手机扫码登录就好:
image部署成功:
image此时,你的接口地址就是,返回给你的地址+/add_christmas_hat,例如我的返回地址是:http://service-n5ahp2w4-1256773370.gz.apigw.tencentcs.com/release
则接口地址就是:
http://service-n5ahp2w4-1256773370.gz.apigw.tencentcs.com/release//add_christmas_hat
大家在自己的项目中,可以直接使用这个接口就好了。例如小程序中上传一个图片,发送给这个服务,或者web页面上传一个图片,发送到这个服务,就可以得到Serverless送给大家的圣诞帽了。
image