美文网首页大数据&云计算python自学云计算
圣诞节:让Serverless送你一顶圣诞帽

圣诞节:让Serverless送你一顶圣诞帽

作者: Dfounderliu | 来源:发表于2020-02-29 13:14 被阅读0次

    圣诞节到了,我偷偷瞄了一眼,身边人的头像很和谐,我觉得这不正常:圣诞老人没给你们发帽子么?

    好吧,既然圣诞老人没给大家发帽子,那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)
            }
    

    使用方法:

    下载我打包好的文件:https://serverless-framework-1256773370.cos.ap-chengdu.myqcloud.com/demo/Add-Christmas-Hat/Add-Christmas-Hat.zip

    解压出来:

    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

    相关文章

      网友评论

        本文标题:圣诞节:让Serverless送你一顶圣诞帽

        本文链接:https://www.haomeiwen.com/subject/vfsphhtx.html