高清仿妆

描述

将参考图中的妆容应用到用户图,支持调整整体仿妆强度、美白程度,以及腮红、眼影、眉毛、美瞳、唇彩和高光修容的强度。接口还支持参考图检测和预处理,并可返回单张结果图、拼接对比图或不同妆容强度的结果图。

版本

1.0

图片要求

  • 支持图片 URL 或 Base64 编码的图片数据。
  • 普通仿妆时,依次传入两张图片:第一张为用户图,第二张为提供妆容的参考图。
  • ref_judgment=1 时仅传入参考图。
  • input_ref_type=1 时,参考图应为已预处理的 640 × 640 图片。

调用 URL

    正式环境:https://openapi.meitu.com
    任务提交接口:https://openapi.meitu.com/api/v1/sdk/sync/push
    任务名称(task):/v1/AIMakeup/494490
    任务类型(task_type):formula

调用方法

POST

Content-Type: application/json

权限

使用前需申请 AccessKey 和 SecretKey,并按照开放平台接口签名完成请求签名。

请求参数

是否必选参数名类型参数说明
必选paramsstring仿妆推理参数,以 JSON 字符串传入
必选init_imagesobject[]输入图片列表。普通仿妆时,第一张为用户图,第二张为参考图;ref_judgment 为 1 时仅传入参考图
必选taskstring固定为 /v1/AIMakeup/494490
必选task_typestring固定为 formula
可选sync_timeoutint默认 30,单位为秒;-1 表示不等待。同步等待超时后返回状态 9,使用查询接口获取结果

init_images 图片参数,结构说明如下

是否必选参数名类型参数说明
必选urlstring图片 URL 或 Base64 编码的图片数据
必选profileobject图片属性信息

profile 属性信息描述

是否必选参数名类型参数说明
必选media_profilesobject媒体属性信息
可选media_extraobject图片附加信息,例如人脸关键点、五官属性
必选versionstring固定为 v1

media_profiles 媒体属性信息

是否必选参数名类型参数说明
必选media_data_typestringurl 表示图片 URL;jpg 表示 JPG 图片的 Base64 编码

params 推理参数是 JSON 字符串,其结构说明如下

是否必选字段类型说明
可选rsp_media_typestring默认 url;url 表示结果图片以 URL 返回,jpg 表示结果图片以 Base64 编码返回
必选parameterobject仿妆算法参数对象

parameter 算法参数详情

是否必选参数名类型参数说明
可选ref_judgmentint处理模式:0 普通仿妆,传入用户图和参考图;1 检测参考图是否符合仿妆要求,并返回预处理后的 640 × 640 参考图;2 实时仿妆参考图处理;3 实时仿妆方案 2 处理
可选blend_valueint整体融合系数,范围 0–100;默认 100
可选makeup_res_typeint结果形式:0 仅返回仿妆结果图;1 返回由处理后的用户图、参考图和仿妆结果图组成的一张拼接图;3 返回低、中、高三种强度的仿妆结果图;默认 1
可选input_ref_typeint参考图类型:0 未预处理;1 已预处理为 640 × 640 的参考图;默认 0
必选beauty_flagint用户图预处理美颜模式,固定传入 0
可选face_color_alphaint美白程度,范围 0–100;默认 40
可选blusher_alphaint腮红透明度,范围 0–100;默认 30
可选eyeshadow_alphaint眼影透明度,范围 0–100;默认 85
可选eyebrow_alphaint眉毛透明度,范围 0–100;默认 45
可选pupil_alphaint美瞳透明度,范围 0–100;默认 55
可选lip_alphaint唇彩透明度,范围 0–100;默认 100
可选hl_alphaint高光修容透明度,范围 0–100;默认 45
可选hightpass_radiusint清晰度程度,范围 0–100;默认 0
可选error_code_modeint错误码模式:0 不区分用户图与参考图;1 区分用户图与参考图;默认 0

输入值示例

以下示例传入用户图和参考图,执行普通仿妆并返回结果图 URL。params 必须为 JSON 字符串。

{
  "task": "/v1/AIMakeup/494490",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/user.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url"
        },
        "version": "v1"
      }
    },
    {
      "url": "https://example.com/reference.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url"
        },
        "version": "v1"
      }
    }
  ],
  "params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"ref_judgment\":0,\"makeup_res_type\":0,\"input_ref_type\":0,\"beauty_flag\":0,\"blend_value\":100,\"face_color_alpha\":40,\"blusher_alpha\":70,\"eyeshadow_alpha\":80,\"eyebrow_alpha\":55,\"pupil_alpha\":70,\"lip_alpha\":90,\"hl_alpha\":60,\"hightpass_radius\":0,\"error_code_mode\":0}}",
  "sync_timeout": 30
}

返回值说明

注意,生成的结果图会定期清理,请及时下载保存
字段类型说明
request_idstring请求标识
trace_idstring链路追踪标识
codeint业务状态码,0 表示请求受理成功
error_codeint错误码,成功时为 0
messagestring业务信息
tipsany补充提示,可为 null
dataobject任务状态和算法结果

data 字段说明

字段类型说明
statusint状态码:-1 未找到任务;0 创建成功;1 执行中;2 失败;9 超时,使用查询接口查询;10 成功
resultobject算法结果
progressnumber任务进度,例如 0.10.851
predict_elapsedint预计耗时,毫秒
create_timeint64创建时间戳,毫秒
task_idstring任务 ID
custom_task_idstring客户自定义任务 ID
trace_idstring链路追踪标识
client_infostring客户端信息
init_imagesobject[]/null输入媒体回显

result 字段说明

字段类型说明
idstring任务 ID
urlsstring[]结果图片地址列表

data.status=10 表示任务完成,结果图片从 data.result.urls 获取;data.status=9 时使用返回的 task_id 查询。

返回值示例

请求成功返回示例

{
  "request_id": "req_1234567890",
  "trace_id": "trace_1234567890",
  "code": 0,
  "error_code": 0,
  "message": "success",
  "tips": null,
  "data": {
    "status": 10,
    "result": {
      "id": "task_1234567890",
      "urls": [
        "https://example.com/makeup_result.jpg"
      ]
    },
    "progress": 1,
    "predict_elapsed": 0,
    "create_time": 1789002000000,
    "task_id": "task_1234567890",
    "custom_task_id": "",
    "trace_id": "trace_1234567890",
    "client_info": "",
    "init_images": null
  }
}

需要查询返回示例

当返回状态为 9 时,使用返回的 task_id 调用查询接口获取结果。

{
  "request_id": "req_1234567890",
  "trace_id": "trace_1234567890",
  "code": 0,
  "error_code": 0,
  "message": "success",
  "tips": null,
  "data": {
    "status": 9,
    "result": {
      "id": "task_1234567890"
    },
    "progress": 0,
    "predict_elapsed": 10000,
    "create_time": 1789002000000,
    "task_id": "task_1234567890",
    "custom_task_id": "",
    "trace_id": "trace_1234567890",
    "client_info": "",
    "init_images": null
  }
}

请求失败返回示例

{
  "request_id": "req_1234567890",
  "trace_id": "trace_1234567890",
  "code": 20001,
  "error_code": 20001,
  "message": "PROCESS_ERROR",
  "tips": null,
  "data": {
    "status": 2,
    "result": {
      "id": "task_1234567890"
    },
    "progress": 0,
    "predict_elapsed": 0,
    "create_time": 1789002000000,
    "task_id": "task_1234567890",
    "custom_task_id": "",
    "trace_id": "trace_1234567890",
    "client_info": "",
    "init_images": null
  }
}

当前 API 特有的错误代码与信息

error_code_mode = 0

ErrorCode 状态代码错误信息说明
20001PROCESS_ERROR处理失败
22001MTAIMKTF_ERRO_TYPE_INPUT输入图片异常
22003MTAIMKTF_ERRO_TYPE_FACE_SIDE人脸过小或侧脸角度过大
22004MTAIMKTF_ERRO_TYPE_FACE_BLACK人脸过暗
22005MTAIMKTF_ERRO_TYPE_FACE_YINGYANG人脸两侧明暗差异过大
22006MTAIMKTF_ERRO_TYPE_FACE_BRIGHT人脸过亮
22007MTAIMKTF_ERRO_TYPE_FACE_COLOR_SHIFT人脸存在色偏
22008MTAIMKTF_ERRO_TYPE_FACE_EYE_CLOSE用户图与参考图的睁闭眼状态不匹配

error_code_mode = 1

ErrorCode 状态代码错误信息说明
20001PROCESS_ERROR处理失败
22001MTAIMKTF_ERRO_TYPE_INPUT输入图片异常
23003MTAIMKTF_ERRO_TYPE_FACE_SIDE_SRC用户图人脸过小或侧脸角度过大
23004MTAIMKTF_ERRO_TYPE_FACE_BLACK_SRC用户图人脸过暗
23005MTAIMKTF_ERRO_TYPE_FACE_YINGYANG_SRC用户图人脸两侧明暗差异过大
23006MTAIMKTF_ERRO_TYPE_FACE_BRIGHT_SRC用户图人脸过亮
23007MTAIMKTF_ERRO_TYPE_FACE_COLOR_SHIFT_SRC用户图人脸存在色偏
23008MTAIMKTF_ERRO_TYPE_FACE_EYE_CLOSE_SRC用户图与参考图的睁闭眼状态不匹配
22003MTAIMKTF_ERRO_TYPE_FACE_SIDE_REF参考图人脸过小或侧脸角度过大
22004MTAIMKTF_ERRO_TYPE_FACE_BLACK_REF参考图人脸过暗
22005MTAIMKTF_ERRO_TYPE_FACE_YINGYANG_REF参考图人脸两侧明暗差异过大
22006MTAIMKTF_ERRO_TYPE_FACE_BRIGHT_REF参考图人脸过亮
22007MTAIMKTF_ERRO_TYPE_FACE_COLOR_SHIFT_REF参考图人脸存在色偏
22008MTAIMKTF_ERRO_TYPE_FACE_EYE_CLOSE_SRC用户图与参考图的睁闭眼状态不匹配

通用的错误代码与信息

详见 API 错误码

SDK 调用示例

以下示例先构造完整请求体,再使用对应语言的签名 SDK 签名并发送。将示例中的 AK、SK 和图片地址替换为实际值。

Python

使用 Python 签名 SDK,并安装 requests。

import json

import requests
from sign_sdk import sign

def api_call_example():
    key = "your_access_key"
    secret = "your_secret_key"
    url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
    method = "POST"
    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }

    inner_params = {
        "rsp_media_type": "url",
        "parameter": {
            "ref_judgment": 0,
            "makeup_res_type": 0,
            "input_ref_type": 0,
            "beauty_flag": 0,
            "blend_value": 100,
            "face_color_alpha": 40,
            "blusher_alpha": 70,
            "eyeshadow_alpha": 80,
            "eyebrow_alpha": 55,
            "pupil_alpha": 70,
            "lip_alpha": 90,
            "hl_alpha": 60,
            "hightpass_radius": 0,
            "error_code_mode": 0
        }
    }
    payload = {
        "task": "/v1/AIMakeup/494490",
        "task_type": "formula",
        "init_images": [
            {
                "url": "https://example.com/user.jpg",
                "profile": {
                    "media_profiles": {
                        "media_data_type": "url"
                    },
                    "version": "v1"
                }
            },
            {
                "url": "https://example.com/reference.jpg",
                "profile": {
                    "media_profiles": {
                        "media_data_type": "url"
                    },
                    "version": "v1"
                }
            }
        ],
        "params": json.dumps(inner_params, ensure_ascii=False),
        "sync_timeout": 30
    }
    body = json.dumps(payload, ensure_ascii=False)

    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, method, headers, body)
    with requests.Session() as session:
        response = session.send(signed_request, timeout=60)
        print("Status:", response.status_code)
        print("Response:", response.text)

if __name__ == "__main__":
    api_call_example()

Go

使用 Go 签名 SDK

package main

import (
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/mtlab/api/signer"
)

func main() {
	key := "your_access_key"
	secret := "your_secret_key"
	signObj := signer.NewSigner(key, secret)
	url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
	headers := make(http.Header)
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	headers.Set("Content-Type", "application/json")

	body := `{
  "task": "/v1/AIMakeup/494490",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/user.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url"
        },
        "version": "v1"
      }
    },
    {
      "url": "https://example.com/reference.jpg",
      "profile": {
        "media_profiles": {
          "media_data_type": "url"
        },
        "version": "v1"
      }
    }
  ],
  "params": "{\"rsp_media_type\":\"url\",\"parameter\":{\"ref_judgment\":0,\"makeup_res_type\":0,\"input_ref_type\":0,\"beauty_flag\":0,\"blend_value\":100,\"face_color_alpha\":40,\"blusher_alpha\":70,\"eyeshadow_alpha\":80,\"eyebrow_alpha\":55,\"pupil_alpha\":70,\"lip_alpha\":90,\"hl_alpha\":60,\"hightpass_radius\":0,\"error_code_mode\":0}}",
  "sync_timeout": 30
}`

	req, err := signObj.Sign(url, http.MethodPost, headers, body)
	if err != nil {
		fmt.Println("Failed to sign request:", err)
		return
	}
	client := &http.Client{Timeout: 60 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Failed to send request:", err)
		return
	}
	defer resp.Body.Close()

	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Failed to read response:", err)
		return
	}
	fmt.Println("Status:", resp.StatusCode)
	fmt.Println("Response:", string(responseBody))
}

PHP

使用 PHP 签名 SDK,将 signer.php 放在示例文件所在目录。

<?php
require_once __DIR__ . '/signer.php';

$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$headers = [
    'Content-Type' => 'application/json',
    'Host' => 'openapi.meitu.com',
];

$innerParams = json_encode([
    'rsp_media_type' => 'url',
    'parameter' => [
        'ref_judgment' => 0,
        'makeup_res_type' => 0,
        'input_ref_type' => 0,
        'beauty_flag' => 0,
        'blend_value' => 100,
        'face_color_alpha' => 40,
        'blusher_alpha' => 70,
        'eyeshadow_alpha' => 80,
        'eyebrow_alpha' => 55,
        'pupil_alpha' => 70,
        'lip_alpha' => 90,
        'hl_alpha' => 60,
        'hightpass_radius' => 0,
        'error_code_mode' => 0,
    ],
], JSON_UNESCAPED_SLASHES);
$body = json_encode([
    'task' => '/v1/AIMakeup/494490',
    'task_type' => 'formula',
    'init_images' => [
        [
            'url' => 'https://example.com/user.jpg',
            'profile' => [
                'media_profiles' => [
                    'media_data_type' => 'url',
                ],
                'version' => 'v1',
            ],
        ],
        [
            'url' => 'https://example.com/reference.jpg',
            'profile' => [
                'media_profiles' => [
                    'media_data_type' => 'url',
                ],
                'version' => 'v1',
            ],
        ],
    ],
    'params' => $innerParams,
    'sync_timeout' => 30,
], JSON_UNESCAPED_SLASHES);

$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);

$response = curl_exec($curl);
if ($response === false) {
    echo 'Error: ' . curl_error($curl);
} else {
    echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
    echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);

Java

使用 Java 签名 SDK,将示例保存为 Main.java。

import com.meitu.openai.common.Signer;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws Exception {
        Signer signer = new Signer("your_access_key", "your_secret_key");
        String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
        String method = "POST";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");

        String body = "{\n" +
                "  \"task\": \"/v1/AIMakeup/494490\",\n" +
                "  \"task_type\": \"formula\",\n" +
                "  \"init_images\": [\n" +
                "    {\n" +
                "      \"url\": \"https://example.com/user.jpg\",\n" +
                "      \"profile\": {\n" +
                "        \"media_profiles\": {\n" +
                "          \"media_data_type\": \"url\"\n" +
                "        },\n" +
                "        \"version\": \"v1\"\n" +
                "      }\n" +
                "    },\n" +
                "    {\n" +
                "      \"url\": \"https://example.com/reference.jpg\",\n" +
                "      \"profile\": {\n" +
                "        \"media_profiles\": {\n" +
                "          \"media_data_type\": \"url\"\n" +
                "        },\n" +
                "        \"version\": \"v1\"\n" +
                "      }\n" +
                "    }\n" +
                "  ],\n" +
                "  \"params\": \"{\\\"rsp_media_type\\\":\\\"url\\\",\\\"parameter\\\":{\\\"ref_judgment\\\":0,\\\"makeup_res_type\\\":0,\\\"input_ref_type\\\":0,\\\"beauty_flag\\\":0,\\\"blend_value\\\":100,\\\"face_color_alpha\\\":40,\\\"blusher_alpha\\\":70,\\\"eyeshadow_alpha\\\":80,\\\"eyebrow_alpha\\\":55,\\\"pupil_alpha\\\":70,\\\"lip_alpha\\\":90,\\\"hl_alpha\\\":60,\\\"hightpass_radius\\\":0,\\\"error_code_mode\\\":0}}\",\n" +
                "  \"sync_timeout\": 30\n" +
                "}";

        Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        try {
            connection.setRequestMethod(method);
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(60000);
            connection.setInstanceFollowRedirects(false);
            for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
                connection.setRequestProperty(header.getKey(), header.getValue());
            }
            connection.setDoOutput(true);
            try (OutputStream output = connection.getOutputStream()) {
                output.write(body.getBytes(StandardCharsets.UTF_8));
            }

            int status = connection.getResponseCode();
            InputStream stream = status >= 400
                    ? connection.getErrorStream()
                    : connection.getInputStream();
            System.out.println("Status: " + status);
            if (stream != null) {
                try (InputStream input = stream;
                     ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = input.read(buffer)) != -1) {
                        output.write(buffer, 0, length);
                    }
                    System.out.println("Response: " + output.toString("UTF-8"));
                }
            }
        } finally {
            connection.disconnect();
        }
    }
}