项目简介
HivisionIDPhoto 旨在开发一种实用、系统性的证件照智能制作算法。
它利用一套完善的AI模型工作流程,实现对多种用户拍照场景的识别、抠图与证件照生成。
HivisionIDPhoto 可以做到:
- 轻量级抠图(纯离线,仅需 CPU 即可快速推理)
- 根据不同尺寸规格生成不同的标准证件照、六寸排版照
- 支持 纯离线 或 端云 推理
- 美颜
- 智能换正装(waiting)
Docker 部署
拉取镜像
官方再docker hub是有镜像源的,但是因为某些原因可能pull失败,我备份了一份到阿里云镜像仓库(官方版本为1.2.9),如下拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/zr-dev/hivision_idphotos:v1.0
启动 Gradio Demo 服务
运行下面的命令,在你的本地访问 http://127.0.0.1:7860 即可使用。
docker run -d -p 7860:7860 registry.cn-hangzhou.aliyuncs.com/zr-dev/hivision_idphotos:v1.0
启动 API 后端服务
此处我将容器内部的8080端口映射到本机的8087,读者可以自定义想要映射的端口
docker run -d -p 8087:8080 registry.cn-hangzhou.aliyuncs.com/zr-dev/hivision_idphotos:v1.0 python3 deploy_api.py
服务启动后咱们就可以调用服务的接口了**(为了防止特殊原因,api文档也备份了一份在文章末尾,并附上官方接口文档地址)**
Springboot 进行接口对接
抽取配置文件,将HivisionIDPhoto后端服务的地址抽取为配置类
photo:
id-photo-base-url: http://127.0.0.1:8087
生成证件照(底透明)+添加背景色
- 此处我只需要实现生成证件照的功能,总共需要对接如下两个接口,如果读者还有其他需求可以,参考官方文档
- callIdPhotoApi
- inputPath: 将图片上传到/ai/img/input/2024/10/24/60182299d7d371cbe2b0b7c9f9c8234_20241024111616A001.jpg(即代码中的inputPath)
- 上传代码可以参考我的另一篇文章SpringBoot 上传图片-指定目录按照日期存储
- height: 生成证件照的高
- width: 生成证件照的宽
- human_matting_model和face_detect_model可以根据自己的需求更换
- addBackground
- inputImageBase64: 生成的结果(base64图片)
- color: 背景色HEX值,默认为000000
- fileService.upload() :将生成的证件照上传到阿里云oss,生成url
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.openservices.shade.com.alibaba.fastjson.JSON;
import com.hss.common.utils.uuid.UUID;
import com.hss.system.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* @author zr 2024/10/24
*/
@Service
@Slf4j
public class ImageProcessor {
@Autowired
private FileService fileService;
@Value("${photo.id-photo-base-url}")
private String idPhotoBaseUrl;
public String callIdPhotoApi(String inputPath,Integer height,Integer width) {
String url = idPhotoBaseUrl+"/idphoto";
Map<String, String> headers = new HashMap<>();
// 根据需要添加头部信息,例如:
// headers.put("Content-Type", "multipart/form-data");
Map<String, Object> parameters = new HashMap<>();
parameters.put("input_image", new File(inputPath));
parameters.put("height", height);
parameters.put("width", width);
parameters.put("human_matting_model", "rmbg-1.4"); //人像分割模型,默认为modnet_photographic_portrait_matting。可选值为modnet_photographic_portrait_matting、hivision_modnet、rmbg-1.4、birefnet-v1-lite
parameters.put("face_detect_model", "mtcnn"); //人脸检测模型,默认为mtcnn。可选值为mtcnn、face_plusplus、retinaface-resnet50
parameters.put("hd", true);
parameters.put("dpi", 300);
parameters.put("face_alignment", true);
HttpResponse response = httpPost(url, headers, parameters);
// 处理响应
String body = response.body();
JSONObject jsonObject = com.alibaba.fastjson2.JSON.parseObject(body);
Boolean status = jsonObject.getBoolean("status");
if (status){
String imageData = jsonObject.getString("image_base64_hd");
return imageData;
} else {
log.info("请求失败{}");
return null;
}
}
public String addBackground(String inputImageBase64,String color) {
String url = idPhotoBaseUrl+"/add_background";
Map<String, String> headers = new HashMap<>();
// 根据需要添加头部信息,例如:
// headers.put("Content-Type", "multipart/form-data");
Map<String, Object> parameters = new HashMap<>();
// 添加请求参数
parameters.put("input_image_base64", inputImageBase64);
parameters.put("color", color);
// parameters.put("kb", kb); //输出照片的 KB 值,默认为None,即不对图像进行KB调整。
// parameters.put("render", render); //渲染模式,默认为0。可选值为0、1、2,分别对应纯色、上下渐变、中心渐变。
// parameters.put("dpi", dpi); //图像分辨率,默认为300
HttpResponse response = httpPost(url, headers, parameters);
// 处理响应
String body = response.body();
JSONObject jsonObject = com.alibaba.fastjson2.JSON.parseObject(body);
Boolean status = jsonObject.getBoolean("status");
if (status){
String imageData = jsonObject.getString("image_base64");
// 检查并去掉 Base64 前缀
if (imageData.startsWith("data:image/")) {
imageData = imageData.substring(imageData.indexOf(",") + 1);
}
byte[] imageBytes = Base64.getDecoder().decode(imageData);
String upload = fileService.upload(imageBytes, UUID.fastUUID() + ".jpg");
return upload;
} else {
log.info("请求失败{}");
return null;
}
}
private HttpResponse httpPost(String url,Map<String, String> headers,Map<String, Object> parameter) {
HttpRequest httpRequest = HttpUtil.createPost(url).form(parameter).addHeaders(headers);
HttpResponse response = httpRequest.execute();
log.info("Url: "+httpRequest.getUrl());
log.info("head: "+JSON.toJSONString(httpRequest.headers()));
log.info("parame: "+JSON.toJSONString(httpRequest.form()));
log.info("res: "+response.body());
return response;
}
}
测试
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author zr 2024/10/24
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = HssApplication.class)
@Slf4j
public class IdPhotoTest {
@Autowired
private ImageProcessor imageProcessor;
@Test
public void callIdPhotoApi() {
String s = imageProcessor.callIdPhotoApi("/ai/img/input/2024/10/24/60182299d7d371cbe2b0b7c9f9c8234_20241024111616A001.jpg",413,295);
log.info(s);
}
@Test
public void addBackground() {
String s = imageProcessor.addBackground(imageProcessor.callIdPhotoApi("/ai/img//input/2024/10/24/23-Authentic-Chinese-Hairstyle-Ideas-00-scaled_20241024133448A001.jpg",413,295), "638cce");
log.info(s);
}
}
测试结果
- 原图
- callIdPhotoApi测试结果
- addBackground测试结果
API Docs
目录
开始之前:开启后端服务
在请求 API 之前,请先运行后端服务
python deploy_api.py
接口功能说明
1.生成证件照(底透明)
接口名:idphoto
生成证件照
接口的逻辑是发送一张 RGB 图像,输出一张标准证件照和一张高清证件照:
- 高清证件照:根据
size
的宽高比例制作的证件照,文件名为output_image_dir
增加_hd
后缀 - 标准证件照:尺寸等于
size
,由高清证件照缩放而来,文件名为output_image_dir
需要注意的是,生成的两张照片都是透明的(RGBA 四通道图像),要生成完整的证件照,还需要下面的添加背景色
接口。
问:为什么这么设计?
答:因为在实际产品中,经常用户会频繁切换底色预览效果,直接给透明底图像,由前端 js 代码合成颜色是更好体验的做法。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 和input_image_base64 二选一 | 传入的图像文件,图像文件为需为RGB三通道图像。 |
input_image_base64 | str | 和input_image 二选一 | 传入的图像文件的base64编码,图像文件为需为RGB三通道图像。 |
height | int | 否 | 标准证件照高度,默认为413 |
width | int | 否 | 标准证件照宽度,默认为295 |
human_matting_model | str | 否 | 人像分割模型,默认为modnet_photographic_portrait_matting 。可选值为modnet_photographic_portrait_matting 、hivision_modnet 、rmbg-1.4 、birefnet-v1-lite |
face_detect_model | str | 否 | 人脸检测模型,默认为mtcnn 。可选值为mtcnn 、face_plusplus 、retinaface-resnet50 |
hd | bool | 否 | 是否生成高清证件照,默认为true |
dpi | int | 否 | 图像分辨率,默认为300 |
face_alignment | bool | 否 | 是否进行人脸对齐,默认为true |
head_measure_ratio | float | 否 | 面部面积与照片面积的比例,默认为0.2 |
head_height_ratio | float | 否 | 面部中心与照片顶部的高度比例,默认为0.45 |
top_distance_max | float | 否 | 头部与照片顶部距离的比例最大值,默认为0.12 |
top_distance_min | float | 否 | 头部与照片顶部距离的比例最小值,默认为0.1 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64_standard | str | 标准证件照的base64编码 |
image_base64_hd | str | 高清证件照的base64编码。如hd 参数为false ,则不返回该参数 |
2.添加背景色
接口名:add_background
添加背景色
接口的逻辑是接收一张 RGBA 图像(透明图),根据color
添加背景色,合成一张 JPG 图像。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 和input_image_base64 二选一 | 传入的图像文件,图像文件为需为RGBA四通道图像。 |
input_image_base64 | str | 和input_image 二选一 | 传入的图像文件的base64编码,图像文件为需为RGBA四通道图像。 |
color | str | 否 | 背景色HEX值,默认为000000 |
kb | int | 否 | 输出照片的 KB 值,默认为None ,即不对图像进行KB调整。 |
render | int | 否 | 渲染模式,默认为0 。可选值为0 、1 、2 ,分别对应纯色 、上下渐变 、中心渐变 。 |
dpi | int | 否 | 图像分辨率,默认为300 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64 | str | 添加背景色之后的图像的base64编码 |
3.生成六寸排版照
接口名:generate_layout_photos
生成六寸排版照
接口的逻辑是接收一张 RGB 图像(一般为添加背景色之后的证件照),根据size
进行照片排布,然后生成一张六寸排版照。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 和input_image_base64 二选一 | 传入的图像文件,图像文件为需为RGB三通道图像。 |
input_image_base64 | str | 和input_image 二选一 | 传入的图像文件的base64编码,图像文件为需为RGB三通道图像。 |
height | int | 否 | 输入图像的高度,默认为413 |
width | int | 否 | 输入图像的宽度,默认为295 |
kb | int | 否 | 输出照片的 KB 值,默认为None ,即不对图像进行KB调整。 |
dpi | int | 否 | 图像分辨率,默认为300 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64 | str | 六寸排版照的base64编码 |
4.人像抠图
接口名:human_matting
人像抠图
接口的逻辑是接收一张 RGB 图像,输出一张标准抠图人像照和高清抠图人像照(无任何背景填充)。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 是 | 传入的图像文件,图像文件为需为RGB三通道图像。 |
human_matting_model | str | 否 | 人像分割模型,默认为modnet_photographic_portrait_matting 。可选值为modnet_photographic_portrait_matting 、hivision_modnet 、rmbg-1.4 、birefnet-v1-lite |
dpi | int | 否 | 图像分辨率,默认为300 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64 | str | 抠图人像照的base64编码 |
5.图像加水印
接口名:watermark
图像加水印
接口的功能是接收一个水印文本,然后在原图上添加指定的水印。用户可以指定水印的位置、透明度和大小等属性,以便将水印无缝地融合到原图中。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 和input_image_base64 二选一 | 传入的图像文件,图像文件为需为RGB三通道图像。 |
input_image_base64 | str | 和input_image 二选一 | 传入的图像文件的base64编码,图像文件为需为RGB三通道图像。 |
text | str | 否 | 水印文本,默认为Hello |
size | int | 否 | 水印字体大小,默认为20 |
opacity | float | 否 | 水印透明度,默认为0.5 |
angle | int | 否 | 水印旋转角度,默认为30 |
color | str | 否 | 水印颜色,默认为#000000 |
space | int | 否 | 水印间距,默认为25 |
dpi | int | 否 | 图像分辨率,默认为300 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64 | str | 添加水印之后的图像的base64编码 |
6.设置图像KB大小
接口名:set_kb
设置图像KB大小
接口的功能是接收一张图像和目标文件大小(以KB为单位),如果设置的KB值小于原文件,则调整压缩率;如果设置的KB值大于源文件,则通过给文件头添加信息的方式调大KB值,目标是让图像的最终大小与设置的KB值一致。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 和input_image_base64 二选一 | 传入的图像文件,图像文件为需为RGB三通道图像。 |
input_image_base64 | str | 和input_image 二选一 | 传入的图像文件的base64编码,图像文件为需为RGB三通道图像。 |
kb | int | 否 | 输出照片的 KB 值,默认为None ,即不对图像进行KB调整。 |
dpi | int | 否 | 图像分辨率,默认为300 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64 | str | 设置KB大小之后的图像的base64编码 |
7.证件照裁切
接口名:idphoto_crop
证件照裁切
接口的功能是接收一张 RBGA 图像(透明图),输出一张标准证件照和一张高清证件照。
请求参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
input_image | file | 和input_image_base64 二选一 | 传入的图像文件,图像文件为需为RGBA四通道图像。 |
input_image_base64 | str | 和input_image 二选一 | 传入的图像文件的base64编码,图像文件为需为RGBA四通道图像。 |
height | int | 否 | 标准证件照高度,默认为413 |
width | int | 否 | 标准证件照宽度,默认为295 |
face_detect_model | str | 否 | 人脸检测模型,默认为mtcnn 。可选值为mtcnn 、face_plusplus 、retinaface-resnet50 |
hd | bool | 否 | 是否生成高清证件照,默认为true |
dpi | int | 否 | 图像分辨率,默认为300 |
head_measure_ratio | float | 否 | 面部面积与照片面积的比例,默认为0.2 |
head_height_ratio | float | 否 | 面部中心与照片顶部的高度比例,默认为0.45 |
top_distance_max | float | 否 | 头部与照片顶部距离的比例最大值,默认为0.12 |
top_distance_min | float | 否 | 头部与照片顶部距离的比例最小值,默认为0.1 |
返回参数:
参数名 | 类型 | 说明 |
---|---|---|
status | int | 状态码,true 表示成功 |
image_base64 | str | 证件照裁切之后的图像的base64编码 |
image_base64_hd | str | 高清证件照裁切之后的图像的base64编码,如hd 参数为false ,则不返回该参数 |
cURL 请求示例
cURL 是一个命令行工具,用于使用各种网络协议传输数据。以下是使用 cURL 调用这些 API 的示例。
1. 生成证件照(底透明)
curl -X POST "http://127.0.0.1:8080/idphoto" \
-F "input_image=@demo/images/test0.jpg" \
-F "height=413" \
-F "width=295" \
-F "human_matting_model=modnet_photographic_portrait_matting" \
-F "face_detect_model=mtcnn" \
-F "hd=true" \
-F "dpi=300" \
-F "face_alignment=true"
2. 添加背景色
curl -X POST "http://127.0.0.1:8080/add_background" \
-F "input_image=@test.png" \
-F "color=638cce" \
-F "kb=200" \
-F "render=0" \
-F "dpi=300"
3. 生成六寸排版照
curl -X POST "http://127.0.0.1:8080/generate_layout_photos" \
-F "input_image=@test.jpg" \
-F "height=413" \
-F "width=295" \
-F "kb=200" \
-F "dpi=300"
4. 人像抠图
curl -X POST "http://127.0.0.1:8080/human_matting" \
-F "input_image=@demo/images/test0.jpg" \
-F "human_matting_model=modnet_photographic_portrait_matting" \
-F "dpi=300"
5. 图片加水印
curl -X 'POST' \
'http://127.0.0.1:8080/watermark?size=20&opacity=0.5&angle=30&color=%23000000&space=25' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'input_image=@demo/images/test0.jpg;type=image/jpeg' \
-F 'text=Hello' \
-F 'dpi=300'
6. 设置图像KB大小
curl -X 'POST' \
'http://127.0.0.1:8080/set_kb' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'input_image=@demo/images/test0.jpg;type=image/jpeg' \
-F 'kb=50' \
-F 'dpi=300'
7. 证件照裁切
curl -X 'POST' \
'http://127.0.0.1:8080/idphoto_crop?head_measure_ratio=0.2&head_height_ratio=0.45&top_distance_max=0.12&top_distance_min=0.1' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'input_image=@idphoto_matting.png;type=image/png' \
-F 'height=413' \
-F 'width=295' \
-F 'face_detect_model=mtcnn' \
-F 'hd=true' \
-F 'dpi=300'
Python 请求示例
1.生成证件照(底透明)
import requests
url = "http://127.0.0.1:8080/idphoto"
input_image_path = "demo/images/test0.jpg"
# 设置请求参数
params = {
"head_measure_ratio": 0.2,
"head_height_ratio": 0.45,
"top_distance_max": 0.12,
"top_distance_min": 0.1,
}
files = {"input_image": open(input_image_path, "rb")}
data = {
"height": 413,
"width": 295,
"human_matting_model": "modnet_photographic_portrait_matting",
"face_detect_model": "mtcnn",
"hd": True,
"dpi": 300,
"face_alignment": True,
}
response = requests.post(url, params=params, files=files, data=data).json()
# response为一个json格式字典,包含status、image_base64_standard和image_base64_hd三项
print(response)
2.添加背景色
import requests
url = "http://127.0.0.1:8080/add_background"
input_image_path = "test.png"
files = {"input_image": open(input_image_path, "rb")}
data = {
"color": '638cce',
"kb": None,
"render": 0,
"dpi": 300,
}
response = requests.post(url, files=files, data=data).json()
# response为一个json格式字典,包含status和image_base64
print(response)
3.生成六寸排版照
import requests
url = "http://127.0.0.1:8080/generate_layout_photos"
input_image_path = "test.jpg"
files = {"input_image": open(input_image_path, "rb")}
data = {
"height": 413,
"width": 295,
"kb": 200,
"dpi": 300,
}
response = requests.post(url, files=files, data=data).json()
# response为一个json格式字典,包含status和image_base64
print(response)
4.人像抠图
import requests
url = "http://127.0.0.1:8080/human_matting"
input_image_path = "test.jpg"
files = {"input_image": open(input_image_path, "rb")}
data = {
"human_matting_model": "modnet_photographic_portrait_matting",
"dpi": 300,
}
response = requests.post(url, files=files, data=data).json()
# response为一个json格式字典,包含status和image_base64
print(response)
5.图片加水印
import requests
# 设置请求的 URL 和参数
url = "http://127.0.0.1:8080/watermark"
params = {
"size": 20,
"opacity": 0.5,
"angle": 30,
"color": "#000000",
"space": 25,
}
# 设置文件和其他表单数据
input_image_path = "demo/images/test0.jpg"
files = {"input_image": open(input_image_path, "rb")}
data = {"text": "Hello", "dpi": 300}
# 发送 POST 请求
response = requests.post(url, params=params, files=files, data=data)
# 检查响应
if response.ok:
# 输出响应内容
print(response.json())
else:
# 输出错误信息
print(f"Request failed with status code {response.status_code}: {response.text}")
6. 设置图像KB大小
import requests
# 设置请求的 URL
url = "http://127.0.0.1:8080/set_kb"
# 设置文件和其他表单数据
input_image_path = "demo/images/test0.jpg"
files = {"input_image": open(input_image_path, "rb")}
data = {"kb": 50, "dpi": 300}
# 发送 POST 请求
response = requests.post(url, files=files, data=data)
# 检查响应
if response.ok:
# 输出响应内容
print(response.json())
else:
# 输出错误信息
print(f"Request failed with status code {response.status_code}: {response.text}")
7. 证件照裁切
import requests
# 设置请求的 URL
url = "http://127.0.0.1:8080/idphoto_crop"
# 设置请求参数
params = {
"head_measure_ratio": 0.2,
"head_height_ratio": 0.45,
"top_distance_max": 0.12,
"top_distance_min": 0.1,
}
# 设置文件和其他表单数据
input_image_path = "idphoto_matting.png"
files = {"input_image": ("idphoto_matting.png", open(input_image_path, "rb"), "image/png")}
data = {
"height": 413,
"width": 295,
"face_detect_model": "mtcnn",
"hd": "true",
"dpi": 300,
}
# 发送 POST 请求
response = requests.post(url, params=params, files=files, data=data)
# 检查响应
if response.ok:
# 输出响应内容
print(response.json())
else:
# 输出错误信息
print(f"Request failed with status code {response.status_code}: {response.text}")