Intelligent Removal

Description

Remove content from a selected image region and fill the area using an inpainting model. Two input methods are supported:

  • Mask-based removal: provide the original image first, then a mask marking the removal area.
  • Box-based removal: provide the original image and relative-coordinate regions through userboxes.

In mask-based mode, userboxes and use_sod have no effect.

Version

1.0

Image Requirements

JPG and PNG are supported, supplied by image URL. Mask-based removal requires two images in this order: original image, then mask.

Request URL

https://openapi.meitu.com/api/v1/sdk/sync/push

Task name (task): /v1/smart_eraser/488142

Task type (task_type): formula

HTTP Method

POST

Content-Type: application/json

Authentication

Use an AK/SK pair with access to this capability and sign requests using the signing SDK. See API Request Signing.

Request Parameters

RequiredParameterTypeDescription
Yessync_timeoutintegerSynchronous waiting period in seconds. The examples use 10; the source specifies no default.
Yestask_typestringFixed value: formula.
Yesinit_imagesobject[]Input images. Box mode takes the original image; mask mode takes the original image followed by the mask.
YestaskstringFixed value: /v1/smart_eraser/488142.
YesparamsstringJSON-serialized algorithm parameter object.

init_images Element

RequiredParameterTypeDescription
YesurlstringAccessible image URL.

params

The decoded object contains parameter, whose fields are described below. The HTTP body is a JSON object; only the params value is a JSON string. Do not encode the entire request body a second time as a string.

parameter

RequiredParameterTypeDescription
Norsp_media_typestringurl: return a short-lived result image URL. Download and save it promptly.
NouserboxesstringJSON string of selected regions. The outer array contains boxes, each with four relative-coordinate points ordered top-left, top-right, bottom-right, bottom-left. Ignored in mask mode.
Nouse_sodstringWhether to apply salient-object segmentation within selected boxes. The source example uses the string "true", not a boolean. Ignored in mask mode.
Nomodel_typestringInpainting model: lama or fcf. The source specifies no default.

Example userboxes string for one box:

[[[0.1,0.1],[0.4,0.1],[0.4,0.4],[0.1,0.4]]]

Request Examples

Mask-Based Removal

Replace the original image and mask URLs. The example omits use_sod because it has no effect in mask mode.

{
  "sync_timeout": 10,
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.png"
    },
    {
      "url": "https://example.com/mask.png"
    }
  ],
  "task": "/v1/smart_eraser/488142",
  "params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"model_type\":\"lama\"}}"
}

Box-Based Removal

Replace the image URL and coordinates. After decoding params, userboxes is still a string.

{
  "sync_timeout": 10,
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.png"
    }
  ],
  "task": "/v1/smart_eraser/488142",
  "params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"model_type\":\"lama\",\"userboxes\":\"[[[0.1,0.1],[0.4,0.1],[0.4,0.4],[0.1,0.4]]]\",\"use_sod\":\"true\"}}"
}

Decoded params for box mode:

{
  "parameter": {
    "rsp_media_type": "url",
    "model_type": "lama",
    "userboxes": "[[[0.1,0.1],[0.4,0.1],[0.4,0.4],[0.1,0.4]]]",
    "use_sod": "true"
  }
}

Response Fields

code = 0 indicates normal request processing; also check data.status. The fields below follow the legacy API documentation, which uses data.result.urls[0] for the result image. This path has not yet been verified for the new formula.

FieldTypeDescription
codeinteger0 indicates a successful request; nonzero indicates a business error.
messagestringResponse message. PROCESS_ERROR in the source error example; absent from its success example.
dataobjectTask details.
data.statusintegerThe source defines 9 as synchronous wait timeout, 2 as failure, and 10 as success.
data.resultobjectTask result.
data.progressnumberTask progress; 1 in the source example.
data.predict_elapsednumberEstimated processing time. The source does not specify units.

data.result

FieldTypeDescription
idstringGateway task ID.
urlsstring[]Result image URLs. Index 0 contains the processed result.
codeintegerAlgorithm status code in the source error example.

Response Examples

The structures below are retained from the legacy API documentation for reference. The actual response of /v1/smart_eraser/488142 has not been verified. Confirm result field paths and the query ID location against the formula's actual response; these are not live results.

Success Example

HTTP 200.

{
  "code": 0,
  "data": {
    "status": 10,
    "result": {
      "id": "example-task-id",
      "urls": [
        "https://example.com/output.jpg"
      ]
    },
    "progress": 1,
    "predict_elapsed": 10000
  }
}

When to Query

data.status = 9 indicates that synchronous waiting timed out, not that the task failed. Use the source's data.result.id as the task ID with Task Query, rather than resubmitting.

Common query states also include -1 (not found), 0 (created), and 1 (running), as defined in the query documentation.

Error Example

The source example uses HTTP 200. The business error is indicated by code and data.status; HTTP status alone does not establish task success.

{
  "code": 20001,
  "message": "PROCESS_ERROR",
  "data": {
    "status": 2,
    "result": {
      "id": "example-task-id",
      "code": 20001
    },
    "progress": 1
  }
}

Common Error Codes

20001 / PROCESS_ERROR indicates a processing error. See API Error Codes for the complete common error-code reference.

SDK Examples

All four examples use the mask-based request above and embed the entire request body; no separate JSON file is required. Set up the SDK for your language, then replace the AK, SK, original image URL, and mask URL.

Each example submits once and prints the response. For box-based removal, adapt the body using the box-mode JSON above. Sign and send the same final request body.

Python

Python Signing SDK

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"
    inner_params = {
        "parameter": {
            "rsp_media_type": "url",
            "model_type": "lama"
        }
    }
    payload = {
        "sync_timeout": 10,
        "task_type": "formula",
        "init_images": [
            {
                "url": "https://example.com/input.png"
            },
            {
                "url": "https://example.com/mask.png"
            }
        ],
        "task": "/v1/smart_eraser/488142",
        "params": json.dumps(inner_params, ensure_ascii=True)
    }
    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

Go Signing SDK

package main

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

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

func main() {
    body := `{
  "sync_timeout": 10,
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.png"
    },
    {
      "url": "https://example.com/mask.png"
    }
  ],
  "task": "/v1/smart_eraser/488142",
  "params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"model_type\":\"lama\"}}"
}`
    url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
    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 Signing SDK

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

$innerParams = json_encode([
    'parameter' => [
        'rsp_media_type' => 'url',
        'model_type' => 'lama'
    ]
], JSON_UNESCAPED_SLASHES);
$body = json_encode([
    'sync_timeout' => 10,
    'task_type' => 'formula',
    'init_images' => [
        [
            'url' => 'https://example.com/input.png'
        ],
        [
            'url' => 'https://example.com/mask.png'
        ]
    ],
    'task' => '/v1/smart_eraser/488142',
    'params' => $innerParams
], 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

Java Signing SDK

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" +
                "  \"sync_timeout\": 10,\n" +
                "  \"task_type\": \"formula\",\n" +
                "  \"init_images\": [\n" +
                "    {\n" +
                "      \"url\": \"https://example.com/input.png\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"url\": \"https://example.com/mask.png\"\n" +
                "    }\n" +
                "  ],\n" +
                "  \"task\": \"/v1/smart_eraser/488142\",\n" +
                "  \"params\": \"{\\\"parameter\\\":{\\\"rsp_media_type\\\":\\\"url\\\",\\\"model_type\\\":\\\"lama\\\"}}\"\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 responseStream = status >= 400
                    ? connection.getErrorStream() : connection.getInputStream();
            if (responseStream != null) {
                try (InputStream input = responseStream;
                     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();
        }
    }
}