"Decoding error, image format unsupported" 在 Microsoft Face API

"Decoding error, image format unsupported" in Microsoft Face API

我正在尝试使用 Microsoft Face API。为此,我有以下 Microsoft 提供的示例代码(在本页末尾 https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395236):

HttpClient httpclient = HttpClients.createDefault();

try {
    URIBuilder builder = new URIBuilder("https://api.projectoxford.ai/face/v1.0/detect");

    builder.setParameter("returnFaceId", "false");
    builder.setParameter("returnFaceLandmarks", "false");
    builder.setParameter("returnFaceAttributes", "age,gender");

    URI uri = builder.build();
    HttpPost request = new HttpPost(uri);
    request.setHeader("Content-Type", "application/octet-stream");
    request.setHeader("Ocp-Apim-Subscription-Key", "...");

    String body = Base64.encodeBase64String(img);

    StringEntity reqEntity = new StringEntity(body);
    request.setEntity(reqEntity);

    HttpResponse response = httpclient.execute(request);
    HttpEntity entity = response.getEntity();

    if (entity != null) {
            System.out.println(EntityUtils.toString(entity));
            return JsonParser.parse(EntityUtils.toString(entity));
    }
} catch (URISyntaxException | IOException | ParseException e) {
        System.out.println(e.getMessage());
}

return null;

但我收到以下错误:

{"error":{"code":"InvalidImage","message":"Decoding error, image format unsupported."}}

我用来测试的图片是这张: http://www.huntresearchgroup.org.uk/images/group/group_photo_2010.jpg (通过快速搜索在互联网上找到它)

它尊重 Microsoft 设置的所有要求,大小和格式...如果我在站点中使用它,它就可以工作 https://www.projectoxford.ai/demo/face#detection

我的字节数组转成base64字符串的String body也可以,我在这个网站测试过:http://codebeautify.org/base64-to-image-converter

报错信息很简单,就是看不出我错在哪里。有人可能知道问题出在哪里吗?

更新

变量img:

img = Files.readAllBytes(Paths.get(imgPath));

我进行了以下更改。我没有发送编码图像,而是发送图像的 URL。

request.setHeader("Content-Type", "application/json");
request.setHeader("Ocp-Apim-Subscription-Key", "{YOUR_FACES_API_KEY}");

StringEntity reqEntity = new StringEntity("{ \"url\":\"http://www.huntresearchgroup.org.uk/images/group/group_photo_2010.jpg\" }");
request.setEntity(reqEntity);

这得到响应:

[{"faceRectangle":{"top":878,"left":2718,"width":312,"height":312},"faceAttributes":{"gender":"male","age":28.5}},{"faceRectangle":{"top":593,"left":573,"width":310,"height":310},"faceAttributes":{"gender":"male","age":27.5}},{"faceRectangle":{"top":1122,"left":1014,"width":294,"height":294},"faceAttributes":{"gender":"female","age":27.7}},{"faceRectangle":{"top":915,"left":1773,"width":277,"height":277},"faceAttributes":{"gender":"female","age":36.7}},{"faceRectangle":{"top":566,"left":1276,"width":269,"height":269},"faceAttributes":{"gender":"male","age":40.7}},{"faceRectangle":{"top":677,"left":2134,"width":257,"height":257},"faceAttributes":{"gender":"female","age":35.2}}]

将尽快发送编码图像。将相应地更新此 post。

编辑:

正在从 URL

下载图像
String base64Img = null;
byte[] bytes = null;
String imgBinaryString = null;
String base64ImgBinaryString = null;
try {
    URL url = new URL("http://www.businessstudynotes.com/wp-content/uploads/2015/09/Role-of-Group.jpg");
    //"http://www.huntresearchgroup.org.uk/images/group/group_photo_2010.jpg");
    BufferedImage image = ImageIO.read(url);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(image, "jpg", baos);
    bytes = baos.toByteArray();
    StringBuilder sb = new StringBuilder();
    for (byte by: bytes)
        sb.append(Integer.toBinaryString(by & 0xFF));
    imgBinaryString = sb.toString();

    base64Img = Base64.getEncoder().encodeToString(bytes);
    byte[] base64Bytes = base64Img.getBytes("UTF-8");
    sb = new StringBuilder();
    for (byte by: base64Bytes) {
        sb.append(Integer.toBinaryString(by & 0xFF));
    }
    base64ImgBinaryString = sb.toString();

} catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    System.out.println("Download issue");
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    System.out.println("ImageIO issue");
    e.printStackTrace();
}

imgBinaryString 包含图像的二进制表示; base64ImgBinaryString 包含图像的 Base 64 表示的二进制表示。

要上传此图片...

URI uri = builder.build(); // builder = new URIBuilder("https://api.projectoxford.ai/face/v1.0/detect");
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/octet-stream");
request.setHeader("Ocp-Apim-Subscription-Key", "{YOUR_FACES_API_KEY");

StringEntity reqEntity = new StringEntity(base64ImgBinaryString);
request.setEntity(reqEntity);

HttpResponse response = httpclient.execute(request);

StringEntity 设置为 imgBinaryStringbase64ImgBinaryString 会产生相同的响应...

{"error":{"code":"InvalidImage","message":"Decoding error, image format unsupported."}}

现在,好东西。这有效...

ByteArrayEntity reqEntity = new ByteArrayEntity(bytes, ContentType.APPLICATION_OCTET_STREAM);
request.setEntity(reqEntity);

其中 bytes 是图像的字节数组;但是这个的 Base64 表示不起作用。有人 确实 需要更新文档。

我设法发现了问题...而不是:

String body = Base64.encodeBase64String(img);
StringEntity reqEntity = new StringEntity(body);
request.setEntity(reqEntity);

我需要做的:

ByteArrayEntity reqEntity = new ByteArrayEntity(img, ContentType.APPLICATION_OCTET_STREAM);
request.setEntity(reqEntity);

我认为文档已过时...

您可以看看 CognitiveJ,这是一个开源库,它将处理与 MS 界面的通信和交互 API。如果您不想使用该库,那么您可以查看代码以了解 REST API 的期望。

(披露 - 我是图书馆的作者)。

import okhttp3.*;

import java.io.File;
import java.io.IOException;


public class Main {


    public static void main(String[] args) {
        try {
            doRequest();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    public static void doRequest() throws IOException {
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"),
                new File(".//src//main//java//Archivo_001.png"));

        Request request = new Request.Builder()
                .url("https://westcentralus.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise")
                .post(body)
                .addHeader("Ocp-Apim-Subscription-Key", "1d88f949af3443ea8cc16b7146bd7501")
                .addHeader("Content-Type", "application/json")
                .addHeader("cache-control", "no-cache")
                .build();
        Response response = client.newCall(request).execute();
        System.out.println(response.body().string());

    }


}

希望这个答案对以后的人有所帮助,因为在找到这个帖子并意识到问题出在文档之前我为此苦苦挣扎了一段时间。

我设法让 octet-stream 类型请求与 HttpClient 和 RestTemplate 一起工作。

  1. HttpClient 版本:

    HttpClient httpclient = HttpClients.createDefault();
    try
    {
        URIBuilder builder = new URIBuilder(String.format("https://%s.api.cognitive.microsoft.com/face/v1.0/detect", region));
    
        List<String> faceAttributes = Arrays.asList("age","gender","headPose","smile","facialHair","glasses","emotion","hair","makeup","occlusion","accessories","blur","exposure","noise");
        String faceAttributesCommaSeparated = String.join(",", faceAttributes);
        builder.setParameter("returnFaceId", "true");
        builder.setParameter("returnFaceLandmarks", "false");
        builder.setParameter("returnFaceAttributes", faceAttributesCommaSeparated);
    
        URI uri = builder.build();
        HttpPost request = new HttpPost(uri);
        request.setHeader("Content-Type", "application/octet-stream");
        request.setHeader("Ocp-Apim-Subscription-Key", subscriptionKey);
    
        ByteArrayEntity reqEntity = new ByteArrayEntity(fileContentBytes, ContentType.APPLICATION_OCTET_STREAM);
        request.setEntity(reqEntity);
    
        HttpResponse response = httpclient.execute(request);
        HttpEntity entity = (HttpEntity) response.getEntity();
    
    }
    catch (Exception e)
    {
        System.out.println(e.getMessage());
    }
    
  2. 休息模板:

    private RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    headers.add("Ocp-Apim-Subscription-Key", subscriptionKey);
    
    List<String> faceAttributes = Arrays.asList("age","gender","headPose","smile","facialHair","glasses","emotion","hair","makeup","occlusion","accessories","blur","exposure","noise");
    String faceAttributesCommaSeparated = String.join(",", faceAttributes);
    
    MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
    paramsMap.add("returnFaceId", "true");
    paramsMap.add("returnFaceLandmarks", "false");
    paramsMap.add("returnFaceAttributes", faceAttributesCommaSeparated);
    
    HttpEntity<byte[]> requestEntity = new HttpEntity<>(fileContentBytes, headers);
    ResponseEntity<String> response = null;
    try {
        response = restTemplate.exchange(
                String.format("%s/face/v1.0/detect", endpoint),
                HttpMethod.POST,
                requestEntity,
                String.class,
                paramsMap
        );
    } catch (HttpClientErrorException e) {
        e.printStackTrace();
    }
    

我留下了一些特定的值作为变量,但它的要点应该很清楚。我将在生产代码中使用 restTemplate 版本并进行一些小改动。