前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【人像分割】照片底色说换就换【微信小程序】

【人像分割】照片底色说换就换【微信小程序】

作者头像
小帅丶
发布2021-12-28 13:10:04
1.6K1
发布2021-12-28 13:10:04
举报
文章被收录于专栏:XAIXAI

一般去拍证件照时底色是蓝色或者红色,但有的证件需要其他颜色。要办的证件很多,如果每办一次就要去拍很麻烦,

那么通过百度的人像分割。再稍加一点代码即可实现照片换底色功能,很省事很便捷。

这里直接从接口开始。没有百度账号,第一次使用百度AI建议看接入指南https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjgn3

本文讲解使用Java语言

-------------后端代码-------------

1.创建一个springboot项目,推荐使用maven构建

代码语言:javascript
复制
lombok https://mvnrepository.com/artifact/org.projectlombok/lombok
aip-sdk  https://mvnrepository.com/artifact/com.baidu.aip/java-sdk
commons-fileupload https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload
fastjson https://mvnrepository.com/artifact/com.alibaba/fastjson
hutool-all https://mvnrepository.com/artifact/cn.hutool/hutool-all

2.创建类,单例加载百度AISDK

代码语言:javascript
复制
import com.baidu.aip.bodyanalysis.AipBodyAnalysis;
/**
 * 加载模块对象
 * @author 小帅丶
 */
public class BDFactory {
	private static AipBodyAnalysis aipBodyAnalysis;

	private static String appid_body = "";
	private static String apikey_body = "";
	private static String secretkey_body = "";

	public static AipBodyAnalysis getAipBodyAnalysis(){
		if(aipBodyAnalysis==null){
			synchronized (AipBodyAnalysis.class) {
				if(aipBodyAnalysis==null){
					aipBodyAnalysis = new AipBodyAnalysis(appid_body, apikey_body, secretkey_body);
				}
			}
		}
		return aipBodyAnalysis;
	}
}

3.创建Controller,编写上传图片接口

此功能会实现人像分割、图片底色更换

代码语言:javascript
复制
import cn.hutool.core.codec.Base64;
import cn.ydxiaoshuai.tools.factory.BDFactory;
import cn.ydxiaoshuai.tools.util.PngColoringUtil;
import cn.ydxiaoshuai.tools.vo.AcnespotmoleBean;
import cn.ydxiaoshuai.tools.vo.BodySegBean;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.bodyanalysis.AipBodyAnalysis;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.util.HashMap;

/**
 * @author 小帅丶
 * @className IdPhotoRestController
 * @Description 证件照处理
 * @Date 2020/5/21-10:20
 **/
@Controller
@RequestMapping(value = "/idphoto")
@Scope("prototype")
@Slf4j
public class IdPhotoRestController extends ApiRestController{

    AipBodyAnalysis aipBodyAnalysis = BDFactory.getAipBodyAnalysis();
    /**
     * @Description 照片底色替换
     * @param file 图片文件
     * @return void
     * @Author 小帅丶
     * @Date 2020年6月5日
     **/
    @RequestMapping(value = "/replace", method = {RequestMethod.POST}, produces="application/json;charset=UTF-8")
    public ResponseEntity idphotoReplace(@RequestParam(value = "file") MultipartFile file,
                                                     HttpServletRequest request,
                                                     HttpServletResponse response) {
        log.info("方法路径{}", request.getRequestURI());
        AcnespotmoleBean bean = new AcnespotmoleBean();
        //颜色
        String colorStr = ServletRequestUtils.getStringParameter(request, "color","red");
        Color backgroudColor = getColor(colorStr);
        HashMap options = new HashMap<>();
        try {
            startTime = System.currentTimeMillis();
            options.put("type", "foreground");
            JSONObject object = aipBodyAnalysis.bodySeg(file.getBytes(), options);
            BodySegBean bodySegBean = JSON.parseObject(object.toString(),BodySegBean.class);
            if(bodySegBean.getPerson_num()>=1){
                //返回处理后的图片
                String imagebase64 = PngColoringUtil.changePNGBackgroudColorByBase64(Base64.decode(bodySegBean.getForeground()), backgroudColor);
                AcnespotmoleBean.Data data = new AcnespotmoleBean.Data();
                data.setImage_base64(imagebase64);
                bean.success("success", "成功", data);
            }else{
                bean.fail("fail", "处理失败 未检测到人脸", 20200522);
            }
        } catch (Exception e) {
            errorMsg = e.getMessage();
            log.info("背景图变化接口出错了" + errorMsg);
            bean.error("system error", "系统错误");
        }
        //耗时
        timeConsuming = String.valueOf(System.currentTimeMillis() - startTime);
        log.info("耗时{},接口返回内容",timeConsuming);
        //响应的内容
        return new ResponseEntity(JSON.toJSONString(bean), httpHeaders, HttpStatus.OK);
    }

    private Color getColor(String colorStr) {
        Color backgroudColor = null;
        if(colorStr.equals("red")){
            backgroudColor = Color.RED;
        }
        if(colorStr.equals("blue")){
            backgroudColor = Color.BLUE;
        }
        if(colorStr.equals("black")){
            backgroudColor = Color.BLACK;
        }
        if(colorStr.equals("white")){
            backgroudColor = Color.WHITE;
        }
        return backgroudColor;
    }
}

4.页面返回的对象

代码语言:javascript
复制
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author 小帅丶
 * @className AcnespotmoleBean
 * @Description 接口返回页面的对象
 * @Date 2020/4/10-15:11
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AcnespotmoleBean extends BaseBean{
    //具体返回的内容
    private Data data;
    @lombok.Data
    public static class Data{
        private String image_base64;
        private Integer acne_count=0;
        private Integer speckle_count=0;
        private Integer mole_count=0;
    }
    public AcnespotmoleBean success(String msg,String msg_zh, Data data) {
        this.msg = msg;
        this.msg_zh = msg_zh;
        this.code = 200;
        this.data = data;
        return this;
    }
    public AcnespotmoleBean fail(String msg,String msg_zh, Integer code) {
        this.msg = msg;
        this.msg_zh = msg_zh;
        this.code = code;
        return this;
    }
    public AcnespotmoleBean error(String msg,String msg_zh) {
        this.msg = msg;
        this.msg_zh = msg_zh;
        this.code = 500;
        return this;
    }
}

5.基础Bean

代码语言:javascript
复制
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author 小帅丶
 * @className BaseBean
 * @Description 基类
 * @Date 2019/7/18-14:48
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BaseBean {
    public Integer code;
    public String msg;
    public String msg_zh;
    public String author;
}

6.人像分割返回的JSON字符串转的Java对象

代码语言:javascript
复制
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * @author 小帅丶
 * @className BodySegBean
 * @Description 人像分割
 * @Date 2020/5/22-15:18
 **/
@NoArgsConstructor
@Data
public class BodySegBean {
    private int person_num;
    private String foreground;
    private long log_id;
    private List person_info;
    @NoArgsConstructor
    @Data
    public static class PersonInfoBean {
        private double height;
        private double width;
        private double top;
        private double score;
        private double left;
    }
}

7.所需工具类。即对图片进行底色替换的方法

代码语言:javascript
复制
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
/**
 * @Description 透明背景上色
 * @author 小帅丶
 * @className PngColoringUtil
 * @Date 2019/10/11-17:03
 **/
public class PngColoringUtil {
    /**
     * @Description 给PNG图片增加背景色
     * @Author 小帅丶
     * @param sourceImage 原始图片 最好是PNG透明的
     * @param targetImage 修改后的图片
     * @param backgroudColor 背景色
     **/
    public static void changePNGBackgroudColor(String sourceImage, String targetImage, Color backgroudColor) {
        try {
            BufferedImage result = changePNGBackgroudColor(sourceImage, backgroudColor);
            File output = new File(targetImage);
            ImageIO.write(result, "jpg", output);
        } catch (IOException e) {
            System.out.println("有问题了" + e.getMessage());
        }
    }
    /**
     * @Description 给PNG图片增加背景色 返回base64
     * @Author 小帅丶
     * @param sourceImage 原始图片 最好是PNG透明的
     * @param backgroudColor 背景色
     * @return java.lang.String
     **/
    public static String changePNGBackgroudColorByBase64(byte[] sourceImage, Color backgroudColor){
        try {
            String base64 = "";
            BufferedImage result = changePNGBackgroudColor(sourceImage, backgroudColor);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(result, "jpg", baos );
            baos.flush();
            byte[] imageInByte = baos.toByteArray();
            baos.close();
            final Base64.Encoder encoder = Base64.getEncoder();
            base64 = encoder.encodeToString(imageInByte);
            return base64;
        }catch (Exception e){
            System.out.println("有问题了" + e.getMessage());
            return null;
        }
    }
    /**
     * @Description 给PNG图片增加背景色 返回base64
     * @Author 小帅丶
     * @param sourceImage 原始图片 最好是PNG透明的
     * @param backgroudColor 背景色
     * @return java.lang.String
     **/
    public static String changePNGBackgroudColorByBase64(String sourceImage, Color backgroudColor){
        try {
            String base64 = "";
            BufferedImage result = changePNGBackgroudColor(sourceImage, backgroudColor);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(result, "jpg", baos );
            baos.flush();
            byte[] imageInByte = baos.toByteArray();
            baos.close();
            final Base64.Encoder encoder = Base64.getEncoder();
            base64 = encoder.encodeToString(imageInByte);
            return base64;
        }catch (Exception e){
            System.out.println("有问题了" + e.getMessage());
            return null;
        }
    }
    /**
     * @Description 给PNG图片增加背景色 返回BufferedImage
     * @Author 小帅丶
     * @param sourceImage 原始图片 最好是PNG透明的
     * @param backgroudColor 背景色
     * @return BufferedImage
     **/
    public static BufferedImage changePNGBackgroudColor(byte[] sourceImage, Color backgroudColor) {
        try {
            ByteArrayInputStream in = new ByteArrayInputStream(sourceImage);
            BufferedImage image = ImageIO.read(in);
            BufferedImage result = new BufferedImage(
                    image.getWidth(),
                    image.getHeight(),
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D graphic = result.createGraphics();
            graphic.drawImage(image, 0, 0, backgroudColor, null);
            graphic.dispose();
            return result;
        } catch (IOException e) {
            System.out.println("有问题了" + e.getMessage());
            return null;
        }
    }
    /**
     * @Description 给PNG图片增加背景色 返回BufferedImage
     * @Author 小帅丶
     * @param sourceImage 原始图片 最好是PNG透明的
     * @param backgroudColor 背景色
     * @return BufferedImage
     **/
    public static BufferedImage changePNGBackgroudColor(String sourceImage, Color backgroudColor) {
        try {
            File input = new File(sourceImage);
            BufferedImage image = ImageIO.read(input);

            BufferedImage result = new BufferedImage(
                    image.getWidth(),
                    image.getHeight(),
                    BufferedImage.TYPE_INT_RGB);

            Graphics2D graphic = result.createGraphics();
            graphic.drawImage(image, 0, 0, backgroudColor, null);
            graphic.dispose();
            return result;
        } catch (IOException e) {
            System.out.println("有问题了" + e.getMessage());
            return null;
        }
    }
}

-------------前端代码-------------

需要使用ColorUI 请自行下载

1.index.js代码

代码语言:javascript
复制
var app = getApp();
var api = require('../../utils/baiduai.js');
Page({
  data: {
    motto: '照片底色修改',
    result: [],
    images: {},
    img: '',
    color:'red',
    windowWidth: 0,
    base64img: '',
    access_token: '',
    action_type: 'TO_OLD',
    tempFilePath: null
  },
  //单选修改
  radiochange: function (e) {
    console.log('radio发生change事件,携带的value值为:', e.detail.value)
    var that = this;
    that.data.color = e.detail.value;
    if (that.data.img == '') {
      wx.showModal({
        content: '未选择图片哦',
        showCancel: false,
        confirmText: '明白了'
      })
    } else {
      wx.showLoading({
        title: "修改中...",
        mask: true
      }),
        that.bgColor();
    }
  },
  onShareAppMessage: function () {
    return {
      title: '背景色修改',
      path: '/pages/idphoto/idphoto',
      imageUrl: '../../images/sharefaceeditattr.png',
      success: function (res) {
        if (res.errMsg == 'shareAppMessage:ok') {
          wx.showToast({
            title: '分享成功',
            icon: 'success',
            duration: 500
          });
        }
      },
      fail: function (res) {
        if (res.errMsg == 'shareAppMessage:fail cancel') {
          wx.showToast({
            title: '分享取消',
            icon: 'loading',
            duration: 500
          })
        }
      }
    }
  },
  clear: function (event) {
    console.info(event);
    wx.clearStorage();
  },
  //事件处理函数
  bindViewTap: function () {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  uploads: function () {
    var that = this
    var takephonewidth
    var takephoneheight
    wx.chooseImage({
      count: 1, // 默认9
      sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
      sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
      success: function (res) {
        that.setData({
          tempFilePath: res.tempFilePaths[0]
        })
        wx.getImageInfo({
          src: res.tempFilePaths[0],
          success(res) {
            takephonewidth = res.width,
              takephoneheight = res.height
          }
        })
        // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
        if (res.tempFiles[0].size > (4096 * 1024)) {
          wx.showToast({
            title: '图片文件过大哦',
            icon: 'none',
            mask: true,
            duration: 1500
          })
        } else {
          wx.showLoading({
            title: "修改中...",
            mask: true
          }),
            that.setData({
              img: res.tempFilePaths[0]
            })
        }
        that.bgColor();//修改图片背景色的方法
      },
    })
  },
  //照片背景色变化
  bgColor: function () {
    var that = this;
    wx.uploadFile({
      url: api.bgColorUrl,
      filePath: that.data.tempFilePath,
      header: {
        'content-type': 'multipart/form-data'
      },
      formData: {
        color: that.data.color
      },
      name: 'file',
      success: function (res) {
        wx.hideLoading();
        var data = res.data;
        var str = JSON.parse(data);
        if (str.code == 200) {
          that.setData({
            img: 'data:image/jpg;base64,' + str.data.image_base64
          })
        } else {
          wx.showModal({
            title: '温馨提示',
            content: str.msg_zh,
            showCancel: false,
            confirmText: '知道了'
          })
        }
      },
      fail: function (res) {
        wx.hideLoading();
        wx.showToast({
          title: '服务错误,稍后再试',
          duration: 2000
        })
      }
    })
  },
  onLoad: function () {
  
  },
  /**
   * 点击查看图片,可以进行保存
   */
  preview(e) {
    var that = this;
    if (null == that.data.img || that.data.img == '') {
      wx.showModal({
        title: '温馨提示',
        content: '未选择任何图片',
        showCancel: false,
        confirmText: '知道了'
      })
    } else {
      wx.previewImage({
        urls: [that.data.img],
        current: that.data.img
      })
    }
  }
});

2.baiduai.js代码

代码语言:javascript
复制
// 自己的服务器域名 线上必须HTTPS 且备案的域名 本地测试可以局域网IP
const host = 'https://domain/';
//背景色修改
const bgColorUrl = host+'apiName';
//暴露出去的接口
module.exports = {
  bgColorUrl: bgColorUrl
}

3.index.wxss代码

代码语言:javascript
复制
@import "../../ui/main.wxss";
@import "../../ui/icon.wxss";
.up {
  color: rgb(255, 255, 255);
  font-size: 20px;
  font-family: 微软雅黑;
  width: 200px;
  height: 50px;
  vertical-align: middle;
  text-align: center;
  line-height: 45px;
  border-radius: 25px;
  background-color: rgb(26, 160, 225);
}
.page-body-wrapper image{
    background: #ececec;
}
image {
    width: 100%;
    height: 100%;
    max-height: 1
}
.msg {
    margin: 10px 0;
    text-align: center;
}
.table {
  margin-top: 10rpx;
  border: 0px solid darkgray;
  width: 100%;
}
.tr {
  display: flex;
  width: 100%;
  justify-content: center;
  height: 80rpx;
  
}
.td {
  font-family: 微软雅黑;
    font-size: 28rpx;
    width:100%;
    display: flex;
    justify-content: center;
    text-align: center;
    align-items: center;
}
.bg-g{
  background: white;
}
.baikeform{
  font-size: 20rpx;
  color: #c0c0c0;
  border-top: 1rpx solid #eeeeee;
  margin:30rpx 40rpx 0rpx 40rpx;
  padding: 20rpx;
}
.th {
  font-size: 28rpx;
  width: 48%;
  justify-content: center;
  background: #3366FF;
  color: #fff;
  display: flex;
  height: 80rpx;
  align-items: center;
}
.preview-tips {
  margin: 50rpx 0  30rpx;  
}

.video {
  margin: 20rpx auto;
  width: 100%;
  height: 300px;
}
switch{
    zoom: 0.8;
}
page {
  background-color: #F8F8F8;
  height: 100%;
  font-size: 32rpx;
  line-height: 1.6;
}
.weui-cell_ft{
  font-size: 32rpx;
}

.page-body-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.btn-area {
  margin-top: 40rpx;
  box-sizing: border-box;
  width: 100%;
  padding: 0 30rpx;
}
.footer{
  font-size: 30rpx;
  text-align: center; 
  color: #7367F0;
}
.reason_txt{
  font-size: 32rpx;
  color: #1AA0E1;
  display: table;
  width: auto;
  white-space: nowrap;
  border-spacing: 0.5rem 0;
  margin-left: 28rpx;
  margin-right: 28rpx;
  margin-top: 28rpx;
}
.reason_txt::before,.reason_txt::after{
  display: table-cell;
  content: "";
  width: 50%;
  background: linear-gradient(#1AA0E1, #1AA0E1) repeat-x center;
  background-size: 0.1rem 0.1rem;
}
.reminder-content{
  width: 89%;
  margin: 0 auto;
  font-size: 24rpx;
  color:#bfbfbf;
}

4.index.wxml代码

代码语言:javascript
复制
由于社区显示html代码会被解析,因此页面代码放在gitee

https://gitee.com/xshuai/codes/c5kn1yeudfw7aqrt4903m14

5.index.json代码

代码语言:javascript
复制
{
  "navigationBarTitleText": "图片背景色修改"
}

查看演示效果

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
人体分析
腾讯云神图·人体分析(Body Analysis)基于腾讯优图领先的人体分析算法,提供人体检测、行人重识别(ReID)等服务。支持识别图片或视频中的半身人体轮廓;支持通过人体检测,识别行人的穿着、体态等属性信息。可应用于人像抠图、背景特效、人群密度检测等场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档