衣服分割
描述
识别图片中的服装、配饰及人体相关区域,输出总分割 mask 和分类 mask。分类结果通过 mask_label 标识,可用于提取指定类别的区域。
版本
1.0
图片要求
- 图片格式:JPG、PNG。
- 使用图片 URL 时,将
media_data_type显式设置为url,URL 不进行 Base64 编码。
分割类别
| 类别编号 | 类别 |
|---|---|
| 0 | 背景 |
| 1 | 头饰 |
| 2 | 头发 |
| 3 | 手套 |
| 4 | 眼镜 |
| 5 | 上衣 |
| 6 | 连衣裙 |
| 7 | 外套 |
| 8 | 袜子 |
| 9 | 裤子 |
| 10 | 皮肤 |
| 11 | 围巾等 |
| 12 | 短裙 |
| 13 | 脸 |
| 14 | 鞋 |
| 15 | 包 |
| 16 | 饰品 |
| 17 | 连体衣 |
| 18 | 假人柱子 |
分类 mask 的 mask_label 为字符串,例如 "0" 表示背景,"6" 表示连衣裙。总 mask 不包含 mask_label 字段。
调用 URL
任务提交接口:
https://openapi.meitu.com/api/v1/sdk/sync/push
任务名称(`task`):`/v1/clothing_segmentation/488136`
任务类型(`task_type`):`formula`调用方法
POST
Content-Type: application/json权限
使用已开通该能力的 AK/SK,通过签名 SDK 生成请求签名。详见开放平台接口签名。
请求参数
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 是 | task | string | 固定为 /v1/clothing_segmentation/488136。 |
| 是 | task_type | string | 固定为 formula。 |
| 是 | init_images | array | 输入图片列表,本文示例传入一张待分割图片。 |
| 是 | params | string | 算法参数对象序列化后的 JSON 字符串,结构见下文。 |
| 否 | sync_timeout | integer | 同步等待时长,单位为秒,默认值为 30。 |
init_images 元素
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 是 | url | string | 图片 URL 或 Base64 编码数据,与 profile.media_profiles.media_data_type 对应。 |
| 是 | profile | object | 图片属性。 |
profile
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 是 | version | string | 固定为 v1。 |
| 是 | media_profiles | object | 图片数据类型。 |
| 否 | media_extra | object | 图片附加信息,无需传入时可省略。 |
media_profiles
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 否 | media_data_type | string | png:Base64 编码的图片数据,原文参数表默认值为 png;url:图片 URL。使用 URL 时请显式传入 url。 |
params
params 必须为字符串。将下列对象序列化后赋给 params,再序列化整个请求体:
{
"parameter": {
"rsp_media_type": "base64"
}
}| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 是 | parameter | object | 衣服分割参数。 |
| 否 | extra | object | 算法协议中的额外处理信息,无需传入时可省略。 |
parameter
| 是否必选 | 参数名 | 类型 | 参数说明 |
|---|---|---|---|
| 否 | rsp_media_type | string | base64:结果图片以 Base64 编码返回。原文参数表未说明默认值。 |
原文请求示例中的 media_data_type 和 rsp_media_type 均为 jpg,与参数表不一致。本文请求采用参数表定义的 URL 输入和 base64 输出;jpg 不作为已确认的请求取值列入参数表。
输入值示例
将图片地址替换为实际待分割图片的可访问 URL。
{
"task": "/v1/clothing_segmentation/488136",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/input.png",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"parameter\":{\"rsp_media_type\":\"base64\"}}",
"sync_timeout": 30
}返回值说明
统一网关的任务状态与查询方式见任务查询接口。网关通用字段如下;本 task 的实际结果封装层级尚未通过响应样本核验。
| 字段 | 类型 | 说明 |
|---|---|---|
| code | integer | 网关业务状态码。0 不代表算法任务已经完成,还需检查任务状态。 |
| message | string | 网关响应信息。 |
| data | object | 任务信息。 |
| data.task_id | string | 网关任务 ID,用于查询任务结果。 |
| data.status | integer | 任务状态,见下表。 |
| data.result | object | 任务结果;本 task 的内部字段层级待确认。 |
| data.status | 说明 |
|---|---|
| -1 | 未找到任务。 |
| 0 | 任务创建成功。 |
| 1 | 执行中。 |
| 2 | 失败。 |
| 9 | 同步等待超时,继续查询,不代表任务失败。 |
| 10 | 成功。 |
算法结果字段
以下字段来自原文算法直连接口,不表示它们位于统一网关响应根级。
| 字段 | 类型 | 说明 |
|---|---|---|
| parameter | object | 结果类型信息。 |
| parameter.rsp_media_type | string | 输出数据类型。原文返回字段说明和示例均为 jpg。 |
| media_info_list | array | 第一个元素为总 mask,后续元素为分类 mask。 |
| media_info_list[].media_data | string | mask 图片数据。原文字段说明为 Base64 数据,成功示例中的类型标识为 url。 |
| media_info_list[].media_profiles | object | mask 图片属性。 |
| media_info_list[].media_profiles.media_data_type | string | 图片数据类型。原文字段说明为 jpg,成功示例为 url。 |
| media_info_list[].mask_label | string | 分类 mask 的类别编号,见“分割类别”。总 mask 不包含该字段。 |
按 mask_label 识别分类 mask,不将后续数组下标当作类别编号。原文未说明每次是否返回全部类别。
算法失败字段
| 字段 | 类型 | 说明 |
|---|---|---|
| ErrorCode | integer | 算法错误码。 |
| ErrorMsg | string | 算法错误信息。 |
| Data | string / null | 附加信息,原文失败示例为 null。 |
返回值示例
以下为旧直连接口的原文示例,仅修正 JSON 语法。... 为省略的图片数据,不可直接使用。示例非本 task 的实测响应,也不是完整统一网关响应;其中 rsp_media_type = jpg 与 media_data_type = url 的不一致保留待确认。
算法成功返回示例
原文 HTTP 状态码:200。
{
"parameter": {
"rsp_media_type": "jpg"
},
"media_info_list": [
{
"media_data": "...",
"media_profiles": {
"media_data_type": "url"
}
},
{
"mask_label": "0",
"media_data": "...",
"media_profiles": {
"media_data_type": "url"
}
},
{
"mask_label": "6",
"media_data": "...",
"media_profiles": {
"media_data_type": "url"
}
}
]
}需要查询时
统一网关返回 data.status = 9 时,使用 data.task_id 按任务查询接口继续获取结果;不要将等待超时当成失败重复提交任务。
算法失败返回示例
原文 HTTP 状态码:400。
{
"ErrorCode": 20003,
"ErrorMsg": "detect no face",
"Data": null
}当前 API 特有的错误代码与信息
| 错误码 | 错误信息 | 说明 |
|---|---|---|
| 20001 | PROCESS_ERROR | 处理错误。 |
通用的错误代码与信息
详见 API 错误码。
SDK 调用示例
以下示例内嵌完整请求体,无需创建额外 JSON 文件。调用前替换 AK、SK 和图片 URL,并按对应语言文档引入签名 SDK。
示例仅提交一次并打印响应。任务未完成时,使用任务查询接口获取结果。
Python
import json
import requests
from sign_sdk import sign
def main():
key = "YOUR_ACCESS_KEY"
secret = "YOUR_SECRET_KEY"
url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
params = {
"parameter": {
"rsp_media_type": "base64"
}
}
payload = {
"task": "/v1/clothing_segmentation/488136",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/input.png",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": json.dumps(params, ensure_ascii=True),
"sync_timeout": 30
}
body = json.dumps(payload, ensure_ascii=True)
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, "POST", headers, body)
with requests.Session() as session:
response = session.send(
signed_request, timeout=(10, 60), verify=True, allow_redirects=False
)
print("Status:", response.status_code)
print("Response:", response.text)
if __name__ == "__main__":
main()Go
package main
import (
"fmt"
"io"
"net/http"
"time"
"github.com/mtlab/api/signer"
)
func main() {
url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
body := `{
"task": "/v1/clothing_segmentation/488136",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/input.png",
"profile": {
"media_profiles": {
"media_data_type": "url"
},
"version": "v1"
}
}
],
"params": "{\"parameter\":{\"rsp_media_type\":\"base64\"}}",
"sync_timeout": 30
}`
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set(signer.HeaderHost, "openapi.meitu.com")
signObj := signer.NewSigner("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY")
req, err := signObj.Sign(url, http.MethodPost, headers, body)
if err != nil {
fmt.Println("Sign request failed:", err)
return
}
client := &http.Client{
Timeout: 60 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Send request failed:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Read response failed:", err)
return
}
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Response:", string(responseBody))
}PHP
<?php
require_once __DIR__ . '/signer.php';
$params = json_encode([
'parameter' => [
'rsp_media_type' => 'base64',
],
]);
$body = json_encode([
'task' => '/v1/clothing_segmentation/488136',
'task_type' => 'formula',
'init_images' => [
[
'url' => 'https://example.com/input.png',
'profile' => [
'media_profiles' => ['media_data_type' => 'url'],
'version' => 'v1',
],
],
],
'params' => $params,
'sync_timeout' => 30,
], JSON_UNESCAPED_SLASHES);
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$headers = [
'Content-Type' => 'application/json',
'Host' => 'openapi.meitu.com',
];
$signer = new Signer('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY');
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
$response = curl_exec($curl);
if ($response === false) {
echo 'Error: ' . curl_error($curl) . PHP_EOL;
} else {
echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);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 {
String body =
"{\n" +
" \"task\": \"/v1/clothing_segmentation/488136\",\n" +
" \"task_type\": \"formula\",\n" +
" \"init_images\": [\n" +
" {\n" +
" \"url\": \"https://example.com/input.png\",\n" +
" \"profile\": {\n" +
" \"media_profiles\": {\n" +
" \"media_data_type\": \"url\"\n" +
" },\n" +
" \"version\": \"v1\"\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"params\": \"{\\\"parameter\\\":{\\\"rsp_media_type\\\":\\\"base64\\\"}}\",\n" +
" \"sync_timeout\": 30\n" +
"}";
String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
Signer signer = new Signer("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY");
Map<String, String> signedHeaders = signer.sign(url, "POST", headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
try {
connection.setRequestMethod("POST");
connection.setConnectTimeout(10000);
connection.setReadTimeout(60000);
connection.setInstanceFollowRedirects(false);
connection.setDoOutput(true);
for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
connection.setFixedLengthStreamingMode(bodyBytes.length);
try (OutputStream output = connection.getOutputStream()) {
output.write(bodyBytes);
}
int status = connection.getResponseCode();
System.out.println("Status: " + status);
InputStream stream = status >= 400
? connection.getErrorStream() : connection.getInputStream();
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();
}
}
}