调用阿里云API实现证件照生成

1. 作者介绍

王逸腾,男,西安工程大学电子信息学院,2022级硕士研究生
研究方向:三维手部姿态和网格估计
电子邮件:[email protected]

路治东,男,西安工程大学电子信息学院,2022级研究生,张宏伟人工智能课题组
研究方向:机器视觉与人工智能
电子邮件:[email protected]

2. 算法介绍

2.1 阿里云介绍


阿里云创立于2009年,是全球领先的云计算及人工智能科技公司,致力于以在线公共服务的方式,提供安全、可靠的计算和数据处理能力,让计算和人工智能成为普惠科技。阿里云服务着制造、金融、政务、交通、医疗、电信、能源等众多领域的领军企业,包括中国联通、12306、中石化、中石油、飞利浦、华大基因等大型企业客户,以及微博、知乎、锤子科技等明星互联网公司。在天猫双11全球狂欢节、12306春运购票等极富挑战的应用场景中,阿里云保持着良好的运行纪录
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本
猿辅导、中泰证券、小米、媛福达、Soul和当贝,这些我们耳熟能详的APP或企业中,阿里云给他们提供了性能强大、安全、稳定的云产品与服务。
计算,容器,存储,网络与CDN,安全、中间件、数据库、大数据计算、人工智能与机器学习、媒体服务、企业服务与云通信、物联网、开发工具、迁移与运维管理和专有云等方面,阿里云都做的很不错。

2.2 证件照生成背景

传统做法:通常是人工进行P图,不仅费时费力,而且效果也很难保障,容易有瑕疵。
机器学习做法:通常利用边缘检测算法进行人物轮廓提取。
深度学习做法:通常使用分割算法进行人物分割。例如U-Net网络。
在这里插入图片描述

2.3 图像分割算法

《BiHand: Recovering Hand Mesh with Multi-stage Bisected Hourglass Networks》里的SeedNet网络是很经典的网络,它把分割任务转变成多个任务。作者的思想是:尽可能的通过多任务学习收拢语义,这样或许会分割的更好或姿态估计的更好。其实这个模型就是多阶段学习网络的一部分,作者想通过中间监督来提高网络的性能。
我提取bihand网络中的SeedNet与训练权重,进行分割结果展示如下
在这里插入图片描述
我是用的模型不是全程的,是第一阶段的。为了可视化出最好的效果,我把第一阶段也就是SeedNet网络的输出分别采用不同的方式可视化。
从左边数第一张图为原图,第二张图为sigmoid后利用plt.imshow(colored_mask, cmap=‘jet’)进行彩色映射。第三张图为网络输出的张量经过sigmoid后,二色分割图,阀闸值0.5。第四张为网络的直接输出,利用直接产生的张量图进行颜色映射。第五张为使用sigmoid处理张量后进行的颜色映射。第六张为使用sigmoid处理张量后进行0,1分割掩码映射。使用原模型和网络需要添加很多代码。下面为修改后的的代码:

下面为修改后的net_seedd代码:# Copyright (c) Lixin YANG. All Rights Reserved.
r"""
Networks for heatmap estimation from RGB images using Hourglass Network
"Stacked Hourglass Networks for Human Pose Estimation", Alejandro Newell, Kaiyu Yang, Jia Deng, ECCV 2016
"""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from skimage import io,transform,util
from termcolor import colored, cprint

from bihand.models.bases.bottleneck import BottleneckBlock
from bihand.models.bases.hourglass import HourglassBisected
import bihand.utils.func as func
import matplotlib.pyplot as plt

from bihand.utils import misc
import matplotlib.cm as cm
def color_mask(output_ok):
    # 颜色映射
    cmap = plt.cm.get_cmap('jet')

    # 将张量转换为numpy数组
    mask_array = output_ok.detach().numpy()

    # 创建彩色图像
    cmap = cm.get_cmap('jet')
    colored_mask = cmap(mask_array)
    return colored_mask
    # 可视化
    # plt.imshow(colored_mask, cmap='jet')
    # plt.axis('off')
    # plt.show()
def two_color(mask_tensor):
    # 将张量转换为numpy数组
    mask_array = mask_tensor.detach().numpy()

    # 将0到1之间的值转换为二值化掩码
    threshold = 0.5 # 阈值,大于阈值的为白色,小于等于阈值的为黑色
    binary_mask = np.where(mask_array > threshold, 1, 0)
    return binary_mask
    # 可视化
    # plt.imshow(binary_mask, cmap='gray')
    # plt.axis('off')
    # plt.show()
class SeedNet(nn.Module):
    def __init__(
        self,
        nstacks=2,
        nblocks=1,
        njoints=21,
        block=BottleneckBlock,
    ):
        super(SeedNet, self).__init__()
        self.njoints  = njoints
        self.nstacks  = nstacks
        self.in_planes = 64

        self.conv1 = nn.Conv2d(3, self.in_planes, kernel_size=7, stride=2, padding=3, bias=True)
        self.bn1 = nn.BatchNorm2d(self.in_planes)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(2, stride=2)
        self.layer1 = self._make_residual(block, nblocks, self.in_planes, 2*self.in_planes)
        # current self.in_planes is 64 * 2 = 128
        self.layer2 = self._make_residual(block, nblocks, self.in_planes, 2*self.in_planes)
        # current self.in_planes is 128 * 2 = 256
        self.layer3 = self._make_residual(block, nblocks, self.in_planes, self.in_planes)

        ch = self.in_planes # 256

        hg2b, res1, res2, fc1, _fc1, fc2, _fc2= [],[],[],[],[],[],[]
        hm, _hm, mask, _mask = [], [], [], []
        for i in range(nstacks): # 2
            hg2b.append(HourglassBisected(block, nblocks, ch, depth=4))
            res1.append(self._make_residual(block, nblocks, ch, ch))
            res2.append(self._make_residual(block, nblocks, ch, ch))
            fc1.append(self._make_fc(ch, ch))
            fc2.append(self._make_fc(ch, ch))
            hm.append(nn.Conv2d(ch, njoints, kernel_size=1, bias=True))
            mask.append(nn.Conv2d(ch, 1, kernel_size=1, bias=True))

            if i < nstacks-1:
                _fc1.append(nn.Conv2d(ch, ch, kernel_size=1, bias=False))
                _fc2.append(nn.Conv2d(ch, ch, kernel_size=1, bias=False))
                _hm.append(nn.Conv2d(njoints, ch, kernel_size=1, bias=False))
                _mask.append(nn.Conv2d(1, ch, kernel_size=1, bias=False))

        self.hg2b  = nn.ModuleList(hg2b) # hgs: hourglass stack
        self.res1  = nn.ModuleList(res1)
        self.fc1   = nn.ModuleList(fc1)
        self._fc1  = nn.ModuleList(_fc1)
        self.res2  = nn.ModuleList(res2)
        self.fc2   = nn.ModuleList(fc2)
        self._fc2  = nn.ModuleList(_fc2)
        self.hm   = nn.ModuleList(hm)
        self._hm  = nn.ModuleList(_hm)
        self.mask  = nn.ModuleList(mask)
        self._mask = nn.ModuleList(_mask)


    def _make_fc(self, in_planes, out_planes):
        bn = nn.BatchNorm2d(in_planes)
        conv = nn.Conv2d(in_planes, out_planes, kernel_size=1, bias=False)
        return nn.Sequential(conv, bn, self.relu)


    def _make_residual(self, block, nblocks, in_planes, out_planes):
        layers = []
        layers.append( block( in_planes, out_planes) )
        self.in_planes = out_planes
        for i in range(1, nblocks):
            layers.append(block( self.in_planes, out_planes))
        return nn.Sequential(*layers)

    def forward(self, x):

        l_hm, l_mask, l_enc = [], [], []
        x = self.conv1(x) # x: (N,64,128,128)
        x = self.bn1(x)
        x = self.relu(x)

        x = self.layer1(x)
        x = self.maxpool(x) # x: (N,128,64,64)
        x = self.layer2(x)
        x = self.layer3(x)

        for i in range(self.nstacks): #2
            y_1, y_2, _ = self.hg2b[i](x)

            y_1 = self.res1[i](y_1)
            y_1 = self.fc1[i](y_1)
            est_hm = self.hm[i](y_1)
            l_hm.append(est_hm)

            y_2 = self.res2[i](y_2)
            y_2 = self.fc2[i](y_2)
            est_mask = self.mask[i](y_2)
            l_mask.append(est_mask)

            if i < self.nstacks-1:
                _fc1 = self._fc1[i](y_1)
                _hm = self._hm[i](est_hm)
                _fc2 = self._fc2[i](y_2)
                _mask = self._mask[i](est_mask)
                x = x + _fc1 + _fc2 + _hm + _mask
                l_enc.append(x)
            else:
                l_enc.append(x + y_1 + y_2)
        assert len(l_hm) == self.nstacks
        return l_hm, l_mask, l_enc

if __name__ == '__main__':
    #a = torch.randn(10, 3, 256, 256)
    # SeedNetmodel = SeedNet()
    # output1,output2,output3 = SeedNetmodel(a)
    # print(output1,output2,output3)

    #total_params = sum(p.numel() for p in SeedNetmodel.parameters())/1000000
    #print("Total parameters: ", total_params)
    pretrained_weights_path = 'E:/bihand/released_checkpoints/ckp_seednet_all.pth.tar'
    img_rgb_path=r"E:\FreiHAND\training\rgb\00000153.jpg"
    img=io.imread(img_rgb_path)
    resized_img = transform.resize(img, (256, 256), anti_aliasing=True)
    img256=util.img_as_ubyte(resized_img)


    #plt.imshow(resized_img)
    #plt.axis('off')  # 关闭坐标轴
    #plt.show()


    ''' implicit HWC -> CHW, 255 -> 1 '''
    img1 = func.to_tensor(img256).float() #转换为张量并且进行标准化处理
    ''' 0-mean, 1 std,  [0,1] -> [-0.5, 0.5] '''
    img2 = func.normalize(img1, [0.5, 0.5, 0.5], [1, 1, 1])
    img3 = torch.unsqueeze(img2, 0)
    ok=img3
    print(img.shape)
    SeedNetmodel = SeedNet()

    misc.load_checkpoint(SeedNetmodel, pretrained_weights_path)#加载权重

    output1, output2, output3 = SeedNetmodel(img3)
    #mask_tensor = torch.rand(1, 64, 64)
    output=output2[1] # 1,1,64,64
    output_1=output[0]# 1,64,64
    output_ok=torch.sigmoid(output_1[0])
    output_real=output_1[0].detach().numpy()#直接产生的张量图
    color_mask=color_mask(output_ok) #显示彩色分割图
    two_color=two_color(output_ok)#显示黑白分割图


    see=output_ok.detach().numpy() 


    # 使用Matplotlib库显示分割掩码
    # plt.imshow(see, cmap='gray')
    # plt.axis('off')
    # plt.show()
   # print(output1, output2, output3)


    images = [resized_img, color_mask, two_color,output_real,see,see]
    rows = 1
    cols = 4

    # 创建子图并展示图像
    fig, axes = plt.subplots(1, 6, figsize=(30, 5))

    # 遍历图像列表,并在每个子图中显示图像
    for i, image in enumerate(images):
        ax = axes[i] if cols > 1 else axes  # 如果只有一列,则直接使用axes
        if i ==5:
            ax.imshow(image, cmap='gray')
        else:
         ax.imshow(image)

        ax.imshow
        ax.axis('off')

    # 调整子图之间的间距
    plt.subplots_adjust(wspace=0.1, hspace=0.1)

    # 展示图像
    plt.show()

上述的代码文件是在bihand/models/net_seed.py中,全部代码链接在https://github.com/lixiny/bihand。
把bihand/models/net_seed.p中的代码修改为我提供的代码即可使用作者训练好的模型和进行各种可视化。(预训练模型根据作者代码提示下载)

3.调用阿里云API进行证件照生成实例

3.1 准备工作

1.找到接口
在这里插入图片描述
进入下面链接即可快速访问
link
2.购买试用包
在这里插入图片描述
3.查看APPcode
在这里插入图片描述
4.下载代码
在这里插入图片描述
5.参数说明
在这里插入图片描述

3.2 实验代码

# !/usr/bin/python
# encoding: utf-8
"""
===========================证件照制作接口===========================
"""

import requests
import json
import base64
import hashlib


class Idphoto:
    def __init__(self, appcode, timeout=7):
        self.appcode = appcode
        self.timeout = timeout

        self.make_idphoto_url = 'https://idp2.market.alicloudapi.com/idphoto/make'

        self.headers = {
            'Authorization': 'APPCODE ' + appcode,
        }

    def get_md5_data(self, body):
        """
        md5加密
        :param body_json:
        :return:
        """

        md5lib = hashlib.md5()
        md5lib.update(body.encode("utf-8"))
        body_md5 = md5lib.digest()
        body_md5 = base64.b64encode(body_md5)
        return body_md5

    def get_photo_base64(self, file_path):
        with open(file_path, 'rb') as fp:
            photo_base64 = base64.b64encode(fp.read())

        photo_base64 = photo_base64.decode('utf8')
        return photo_base64

    def aiseg_request(self, url, data, headers):
        resp = requests.post(url=url, data=data, headers=headers, timeout=self.timeout)
        res = {"status_code": resp.status_code}
        try:
            res["data"] = json.loads(resp.text)
            return res
        except Exception as e:
            print(e)

    def make_idphoto(self, file_path, bk, spec="2"):
        """
        证件照制作接口
        :param file_path:
        :param bk:
        :param spec:
        :return:
        """
        photo_base64 = self.get_photo_base64(file_path)

        body_json = {
            "photo": photo_base64,
            "bk": bk,
            "with_photo_key": 1,
            "spec": spec,
            "type": "jpg"
        }

        body = json.dumps(body_json)
        body_md5 = self.get_md5_data(body=body)
        self.headers.update({'Content-MD5': body_md5})

        data = self.aiseg_request(url=self.make_idphoto_url, data=body, headers=self.headers)
        return data


if __name__ == "__main__":
    file_path = "图片地址"

    idphoto = Idphoto(appcode="你的appcode")

    d = idphoto.make_idphoto(file_path, "red", "2")
    print(d)

3.3 实验结果与分析

在这里插入图片描述
原图片
在这里插入图片描述
背景为红色生成的证件照
在这里插入图片描述
背景为蓝色生成的证件照
在这里插入图片描述
另外尝试了使用柴犬照片做实验,也生成了证件照
原图
在这里插入图片描述
背景为红色生成的证件照
在这里插入图片描述

参考(可供参考的链接和引用文献)

1.参考:BiHand: Recovering Hand Mesh with Multi-stage Bisected Hourglass Networks(BMVC2020)
论文链接:https://arxiv.org/pdf/2008.05079.pdf

猜你喜欢

转载自blog.csdn.net/m0_37758063/article/details/131128967
今日推荐