• 【零基础微信小程序】证件照换底色小程序实战开发


    在这里插入图片描述

    系列文章目录

    【零基础微信小程序入门开发】小程序介绍及环境搭建
    【零基础微信小程序入门开发】配置小程序
    【零基础微信小程序入门开发】小程序框架一
    【零基础微信小程序入门开发】小程序框架二
    【零基础微信小程序入门开发】基础能力(一)
    【零基础微信小程序入门开发】基础能力(二)
    👉照片换底小程序实战开发
    在这里插入图片描述

    成品演示

    小程序照片换底色演示

    项目背景说明

    通过小程序配合百度的人体分割接口进行简单的照片渲染,本期做一个小工具,对学生党、工作人员、打印店铺以及涉及到求职简历办公等需求的人员都很有用,这个项目由于一些原因不再做维护了,于是打算出个教程将证件照小程序分享给大家,这里采用百度AI接口是因为现在网上开源的py脚本对边缘计算不是很优秀,会有很多模糊点没办法处理,识别人体的轮廓范围,与背景进行分离,适用于拍照背景替换、照片合成、身体特效等场景。输入正常人像图片,返回分割后的二值结果图、灰度图、透明背景的人像图(png格式);并输出画面中的人数、人体坐标信息,可基于此对图片进行过滤、筛选。百度在这方便做得很好,细致化到发丝,并且免费!!
    在这里插入图片描述

    我们来看下人像分割是啥意思?
    举个例子:

    1)原图
    在这里插入图片描述

    2)二值图

    在这里插入图片描述

    3)灰度图
    在这里插入图片描述

    3)目标图
    在这里插入图片描述
    目标的图片是一张透明图,通过透明图,加上小程序的canvas渲染就可以得到一张换了背景的图片,这个程序原理就是这样,实现的算法都在百度,我们只需要调用拼接就可以

    基础配置

    注册好小程序后,将后端合法域名设置添加

    https://aip.baidubce.com

    *复制备用好的appid

    申请百度接口

    地址在这里,注册找到 【人体分析】,创建应用后添加【人像分割】
    这里呢每天有免费的额度够大家用了
    在这里插入图片描述

    API状态请求地址调用量限制QPS限制
    人像分割付费使用https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg5万次/天赠送 + 超出按量计费10

    创建应用如图:
    在这里插入图片描述
    保存好百度给的appid 和key等这些参数

    我们已经获取到了人像分割识别接口:

    https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg

    那怎么使用呢?

    使用人像分割接口方法

    我们先看下官方给的请求示例:

    HTTP 方法:POST

    请求URL: https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg

    URL参数:

    参数
    access_token通过API Key和Secret Key获取的access_token,参考“Access Token获取”

    Header如下:

    (这里一定要按照文档的要求来 不然会出错)

    参数
    Content-Typeapplication/x-www-form-urlencoded

    请求参数

    参数是否必选类型可选值范围说明
    imagestring-图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M。图片的base64编码是不包含图片头的,如(data:image/jpg;base64,),支持图片格式:jpg、bmp、png,最短边至少50px,最长边最大4096px
    typestringlabelmap,scoremap,foreground可以通过设置type参数,自主设置返回哪些结果图,避免造成带宽的浪费1)可选值说明:labelmap - 二值图像,需二次处理方能查看分割效果scoremap - 人像前景灰度图foreground - 人像前景抠图,透明背景2)type 参数值可以是可选值的组合,用逗号分隔;如果无此参数默认输出全部3类结果图

    access_token获得方法

    请求URL数据格式,向授权服务地址

    https://aip.baidubce.com/oauth/2.0/token

    发送请求(推荐使用POST),并在URL中带上以下参数:

    grant_type: 必须参数,固定为client_credentials;
    client_id: 必须参数,应用的API Key;
    client_secret: 必须参数,应用的Secret Key;

    注: API Key、Secret Key 均可在百度智能云控制台 应用列表 处获取,若无应用请先进行创建; API Key、Secret
    Key用于接口调用鉴权,请务必注意保密,不可在公开文档或代码中以明文展示,否则可能导致账号被盗用。

    与自己的密钥拼接后(例如):

    https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=Va5yQRHlA4Fq5eR3LT0vuXV4&client_secret=0rDSjzQ20XUj5itV6WRtznPQSzr5pVw2&

    这里呢,access_token有效期是30天,大家可以用定时任务每几天触发一次,然后存取到redis即可,这样就避免了每次使用都需要去调用的情况

    创建小程序

    这里大家新建一个新的项目即可,我这里直接导入了
    在这里插入图片描述

    功能设计

    通过wxml渲染一个基本功能
    基本功能包含的控件,图片控件、按钮,完整的样式图如下:
    在这里插入图片描述

    设计上传功能

    构建一个view用于放默认图片“+”

    <view style="width: 300rpx;height: 600rpx;display: flex;align-items: center;justify-content: center;flex-direction: row;"bindtap="add_img" class="saveimg">
    <view style="width: 420rpx;height: 500rpx;border: 1px solid black;display: flex;flex-direction:column;justify-content: center;align-items: center;">
    
    <view style="width: 460rpx;height: 500rpx;display: flex;flex-direction:column;align-items: center;justify-content: center;" wx:if="{{is_tp}}">
    <view style="width:80rpx;height:80rpx;font-size: 80px;margin: 0 auto;color: #EEE5E1;">+</view>
    </view>
    <view style="width: 460rpx;height: 500rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;" wx:else>
      <canvas canvas-id="firstCanva" class="firstCanvas" style="width: 160px;height: 230px;"></canvas>
      <!-- //预览 -->
      <view style='width:0px;height:0px;overflow:hidden;position:fixed;padding-left:9000px;'>
        <canvas canvas-id="firstCanvas" class="firstCanvas" style="width: {{imgwidth}}px;height: {{imgheight}}px;"></canvas>
        <!-- //实际输出 -->
    </view>
    <!-- Canvas 2D组件 -->
    
    <!-- 保存按钮 -->
    
    </view>
    
    
    </view>
    
    </view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    预览图:
    在这里插入图片描述

    现在开始设计js事件,通过上方的bindtap事件

    bindtap=“add_img”

    我们在js中构造方法:

      add_img:function(){},
    
    • 1

    当用户点击上传后,需要一个选择图片的操作 所以:

    wx.chooseImage({
    count: 1,
    sizeType: ['original', 'compressed'],
    sourceType: ['album', 'camera'],
    success (res) {
    // tempFilePath可以作为img标签的src属性显示图片
    const tempFilePaths = res.tempFilePaths
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    通过这一步即可获取到图片的临时路径res.tempFilePaths
    在这里插入图片描述
    临时路径如下
    在这里插入图片描述

    转换

    获取到上传图片信息后,因为百度的接口中已经说明了,只能用base64编码且大小不能超过4M

    图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M。图片的base64编码是不包含图片头的,如(data:image/jpg;base64,),支持图片格式:jpg、bmp、png,最短边至少50px,最长边最大4096px

    所以我们现在需要将临时图片转换为base64编码,通过调用第三方js进行处理

    that.urlTobase64(tempFilePaths);
    
    • 1

    转换后如下:
    在这里插入图片描述
    获取到了后通过baidu_方法进行数据传输
    *我这里通过将封装好的方法放到PHP上去了,这样就可以在调用的时候访问access_token了,因为我可以直接从服务器读取redis里面的access_token
    在这里插入图片描述
    这里因为项目代码可以diy所以仅提供一个思路
    转换成功后返回base64数据,通过setStorageSync将数据进行缓存(缓存数据最大只能10M)

     wx.setStorageSync('new_base64', res.data)
    
    • 1

    在这里插入图片描述

    处理后图片渲染

    获取到新的数据后 我们复制一下百度返回的base64码

    打开浏览器通过这个工具:base64图片转换

    将返回的数据最前面加上

    data:image/jpeg;base64,

    通过网站将base64转换为图片
    在这里插入图片描述

    发现图片是一张处理后的透明图,这里就说明我们上面的流程已经完整运行了,接下来只需要将base64转换为图片即可,通过小程序将base64逆向转换为图片存在本地生成一个临时路径通过canvas完成对颜色的渲染绘画最后保存下来即可

    转换图片到本地:

    //将base64图片转本地图片
    let that=this;
    var tt=wx.getStorageSync('new_base64')
    var fsm = wx.getFileSystemManager();
    var filePath = wx.env.USER_DATA_PATH + '/share_img'  + '.png';
    var buffer = wx.base64ToArrayBuffer(tt);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    临时路径:
    在这里插入图片描述

    转换后保存到缓存通过canvas渲染到前端

        let that=this;
        var ww_tmp=wx.getStorageSync('tmp_img_data');
        var tmp_url=wx.getStorageSync('tmp_url');
        // 使用 wx.createContext 获取绘图上下文 context
        var context = wx.createCanvasContext('firstCanva')
        // 设置边框颜色
        context.setStrokeStyle("#fff")
        // 设置边框粗细
        context.setLineWidth(0)
        // 设置背景颜色
        context.setFillStyle(color)
        context.fillRect(0,0,160,230)
        // 将人像绘制上去
        context.drawImage(tmp_url,0,0,160,230)
        // 创建一个矩形
        context.rect(0, 0, 160,230)
        context.stroke()
        context.draw()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    效果
    在这里插入图片描述

    颜色绘制

    设计颜色选择器

    在这里插入图片描述
    wxml代码

    <view style="width: auto;height: 200rpx;">
    <view style="width: auto;height: 200rpx;display: flex;flex-direction: row;align-items: center;justify-content: center;">
    <view style="width: 170rpx;height: 180rpx;display: flex;flex-direction: row;display: flex;flex-direction: column;align-items: center;justify-content: center;" bindtap="color_c" data-id="#FFFFFF">
    <view style="width: 170rpx;height: 170rpx;background-color:#FFFFFF;border-radius: 50%;"></view>
    </view>
    <view style="width: 170rpx;height: 180rpx;display: flex;flex-direction: row;margin-left: 10rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;"bindtap="color_c" data-id="#428EDA">
    <view style="width: 170rpx;height: 170rpx;background-color:RGB(52,151,232);border-radius: 50%;"></view>
    </view>
    <view style="width: 170rpx;height: 180rpx;display: flex;flex-direction: row;margin-left: 10rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;"bindtap="color_c" data-id="#98CBEC">
    <view style="width: 170rpx;height: 170rpx;background-color:RGB(152,203,236);border-radius: 50%;"></view>
    </view>
    <view style="width: 170rpx;height: 180rpx;display: flex;flex-direction: row;margin-left: 10rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;"bindtap="color_c" data-id="#FE0000">
    <view style="width: 170rpx;height: 170rpx;background-color:RGB(205,26,53);border-radius: 50%;"></view>
    </view>
    </view>
    </view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    颜色选中事件

    在js构造方法(这里有两个是因为一个是输出的图像,一个是给用户看的展示到前端的)

      color_c:function(color){
    let that=this;
    that.huanse(color);
    that.huans(color);
    
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    渲染选中的颜色

    通过颜色的选择结合百度分割后的图片绘制

    huanse: function (color) {
        // console.log(color.currentTarget.dataset.id);
        if(color==undefined){
      color='#fff'
        }else{
          color=color.currentTarget.dataset.id
        }
        let that=this;
        var ww_tmp=wx.getStorageSync('tmp_img_data');
        var tmp_url=wx.getStorageSync('tmp_url');
        // 使用 wx.createContext 获取绘图上下文 context
        var context = wx.createCanvasContext('firstCanvas')
        // 设置边框颜色
        context.setStrokeStyle("#fff")
        // 设置边框粗细
        context.setLineWidth(0)
        // 设置背景颜色
        context.setFillStyle(color)
        context.fillRect(0,0,ww_tmp.width,ww_tmp.height)
        // 将人像绘制上去
        context.drawImage(tmp_url,0,0,ww_tmp.width,ww_tmp.height)
        // 创建一个矩形
        context.rect(0, 0, ww_tmp.width,ww_tmp.height)
        context.stroke()
        context.draw()
        that.setData({
          is_tp:false
        })
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    保存

    因为小程序有激励广告费可以赚取,所以我们在这里可以加一个广告激励时间,通过判断观看完整来执行代码
    wxml代码

    <button bindtap="watch_ad" type="primary" style="margin-top: 10rpx;">保存到相册</button>
    
    • 1

    js代码:

    加一个模态窗口,用于询问

     wx.showModal({
          title: '提示',
          content: '保存需要观看完整视频',
          success: function(res) {
            if (res.confirm) {
              if (videoAd) {
                videoAd.show().catch(err => {
                 // 失败重试
                 videoAd.load()
                 .then(() => videoAd.show())
                })
                }
              console.log('用户点击确定')
            } else if (res.cancel) {
              console.log('用户点击取消')
            }
          }
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    canvas渲染绘制放在onload事件即可
    在这里插入图片描述

    总结

    以上就是我们本次的开发项目实战,也是第一次项目实战,对照片换底小程序进行详细的叙述,代码的实现很简单,只需要会调用,学会处理接口的数据就行,最后业务的需求根据自身的能力和想法进行优化即可,以上!

  • 相关阅读:
    互联网摸鱼日报(2023-10-23)
    设计模式-模板模式在Java中的使用示例
    RAC+ADG switch over 演练时TNS配置
    AQS介绍
    python中的logging模块——将日志保存到文件中
    1秒奇迹!你的桌面文件夹也可以瞬间整洁
    c# 图书管理系统
    C51之智能感应垃圾桶
    Jenkins 安装以及初始化
    听GPT 讲Rust源代码--library/core/src(7)
  • 原文地址:https://blog.csdn.net/qq_35230125/article/details/125403077