restunity-game-enginefile-uploadautodesk-forgeautodesk-realitycapture

Adding Images to Reality Capture API Results in file size of 0 after accepted request


I am currently working with Reality Capture API. I'm developing on a Mac and using Unity3D as my primary development tool. When adding images to my PhotoScene, I'm seeing that each file size results in the size being 0. I'm also seeing that only a single image is being processed per request via the return response

in the documentation below

https://forge.autodesk.com/en/docs/reality-capture/v1/tutorials/create-3d-mesh-from-photos/

On step 3, adding images to the API, you are able to upload via a path. Currently my path looks like the following with the total images incrementing up to 350. As the API states, you are limited to 20 images per request.

/Users/kreutsx1/Documents/ImagesMe/0001.jpg

The Code I use to create the request and look through the images is below, right now i'm only submitting a request for the first 20 images to verify they're being added to the scene correctly.

[ContextMenu("AddImages")]
    public async void AddImages()
    {
        PhotoSceneAddImage photosceneAddImage = new PhotoSceneAddImage();
        var url = "https://developer.api.autodesk.com/photo-to-3d/v1/file";

        WWWForm form = new WWWForm();
        photosceneAddImage.SceneID = sceneID;
        form.AddField("photosceneid", photosceneAddImage.SceneID);
        form.AddField("type", photosceneAddImage.Type);
        photosceneAddImage.FilePath = filePath;

        photosceneAddImage.Files = new String[photosceneAddImage.totalFiles];
        photosceneAddImage.Files = Directory.GetFiles(photosceneAddImage.FilePath);

        photosceneAddImage.totalFiles = photosceneAddImage.Files.Length;

        Debug.Log(photosceneAddImage.totalFiles);

        for (int i = 0; i < 20; i++) //20 is the total amount of images we can upload in a single request
        {
            form.AddField(String.Format("file[{0}]", photosceneAddImage.fileCount), photosceneAddImage.Files[i]);

            photosceneAddImage.fileCount++;
            Debug.Log(photosceneAddImage.fileCount);
        }


        using var www = UnityWebRequest.Post(url, form);

        Debug.Log(form.ToString());

        www.SetRequestHeader("Authorization", "Bearer " + token);
        www.SetRequestHeader("Content-Type", "multipart/form-data");

        var operation = www.SendWebRequest();

        while (!operation.isDone)
            await Task.Yield();

        if (www.result == UnityWebRequest.Result.Success)
        {

            Debug.Log($"Success: {www.downloadHandler.text}");
            var deserializedPostData = JsonUtility.FromJson<PostResult>(www.downloadHandler.text);
            Debug.Log(deserializedPostData.success);
            string response = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);
        }
        else
        {
            Debug.Log($"Failed: {www.error}");
        }


    }

I submit my Post request to the API and get the following returned response

{"Usage":"1.0667450428009",
"Resource":"\/file",
"photosceneid":"jz4IuwGoPy6nT1isatnezWwnuZBiMYG3DqOSkulAOQQ",
"Files":{"file":{"filename":"1.jpg","fileid":"AxyOFMJOBN1wyUgKQoXQrioUrhLPbU3apE8W6Ih5m2M=-001","filesize":"0","msg":"No error","url":"https:\/\/adsk-rc-photofly-prod.s3.amazonaws.com\/IMAGES\/AxyO\/FMJO\/BN1w\/yUgK\/QoXQ\/rioU\/rhLP\/bU3a\/pE8W\/6Ih5\/m2M%3D-001?x-amz-server-side-encryption=AES256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEPz%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIQC2iNoL1MNS2cN4EJwprPdr4kC4zE16dTE8t5Htv%2Fr8fQIgVo8NqtHMl3Erhph1vvniO9YQYvoBFzV5eUf2mpDxzJ4qvQMIlf%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw0MzY5MDc0MzgyMzYiDGY88UZM%2BhV%2F%2BzhfbyqRA8gY%2FK7MwV5SKcMM9lpo4Y2Tdzejnw0%2BdBswlX%2BkNDM9SaBlnjh2JE%2FoTv0%2BZyAGGhMQ0JzlyunJufMB5xA3Ty8YDt9Kl4BmcCtbX0U4iBkLG4ccbFX1EfHj3YostA371hQuheiGm15RVv1bkrEgHINM%2FjmARrMsHYsnXW%2F4GzXOihtLXDOu5hyqkjnbBZ32ZlSDUJvpk2EUVC%2BcF6%2BzMRa4dcNhMr%2FiUL3BVKX9rmJhk9SFirw0NYVgBUqhhMvQT0%2B0iPJw61fb557fPGvX9cFu9GH4Mu7qcytwCzFe%2BqEsbdgDjaMaYEqmNFoZXPw3zM2G7Jv3974og9tT7BXbNbp5cPTtiB2NJ4kfO4nEfRiuqXrOFliFRk2y0mn9H3DzTiVuVZ52jlAPYbyZsu%2FgGEd7Cel%2FqGCvq5kEVeK%2F6evoHV9YvFzmS3sQwBEWRMjZKdGp5TH5MM1%2BjlGDBcL2dLKVJYE6NfLjyGLIbuosMO7paWZhGEh%2Fr0sD3KR9BXRIwKzOflCAgTRnsT42Hj9W8n0iMMv3moUGOusBX1cXrOSXyTrkGs0UVo7aFaugYgUosCGkJHhcCaZoq94YgU1ZeVIqR%2FqgTXbX9F937FbJ9rZNwz7PoX7a5iMOrOYcGTlHk5LBCA5H4%2FPMLUGqKNBLnNVpTYA3Xb%2Bv%2F3ItycqdKqagqINA4sVlqqZ%2BK4wcaXVZhMVO7wZ2bDFH6rE0eg0LyCL%2BFz7qVqDZoxtQzg1ilLKt4XmyX4qVTsycgX882V7f4dWa2wIm10xTqSKZ1OaeF31gl2CFH8QeNWKxm2MztmzKQDPRCHfzBBkKptYqToIzj5I4z7AycIAuNN80nb6LK1OwXHepuQ%3D%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAWLONWOCOAUKYLIWW%2F20210520%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210520T194701Z&X-Amz-SignedHeaders=host%3Bx-amz-server-side-encryption&X-Amz-Expires=7200&X-Amz-Signature=e06ce57a531f31a68f0121345c59c0dd9c9571c5dffffb7204fcb21d09a52b0e"}}}

From what I can see, it looks like I have two issues,

  1. The resulting file size "filesize":"0"
  2. I'm only seeing a single image being added to the scene even when adding the allocated 20 max images to my form with the following.
        for (int i = 0; i < 20; i++) //20 is the total amount of images we can upload in a single request
        {
            form.AddField(String.Format("file[{0}]", photosceneAddImage.fileCount), photosceneAddImage.Files[i]);

            photosceneAddImage.fileCount++;
            Debug.Log(photosceneAddImage.fileCount);
        }

Update

I've been going through the code and updated to the following

[ContextMenu("AddImages")]
    public async void AddImages()
    {
        PhotoSceneAddImage photosceneAddImage = new PhotoSceneAddImage();
        var url = "https://developer.api.autodesk.com/photo-to-3d/v1/file";

        WWWForm form = new WWWForm();
        photosceneAddImage.SceneID = sceneID;
        form.AddField("photosceneid", sceneID);
        form.AddField("type", photosceneAddImage.Type);
        photosceneAddImage.FilePath = filePath;

        photosceneAddImage.Files = new String[photosceneAddImage.totalFiles];
        photosceneAddImage.Files = Directory.GetFiles(photosceneAddImage.FilePath);

        
        photosceneAddImage.totalFiles = photosceneAddImage.Files.Length;
        for (int i = 0; i < 20; i++) //20 is the total amount of images we can upload in a single request
        {
            byte[] img = File.ReadAllBytes("/Users/kreutsx1/Documents/ImagesMe/" + String.Format("{0}.jpg", photosceneAddImage.fileCount + 1));
            form.AddBinaryData(String.Format("file[{0}]", photosceneAddImage.fileCount+1), img);
            photosceneAddImage.fileCount++;
            Debug.Log(photosceneAddImage.fileCount);
        }

        
        Debug.Log(photosceneAddImage.totalFiles);
        using var www = UnityWebRequest.Post(url, form);
        Debug.Log(www.responseCode);
        www.SetRequestHeader("Authorization", "Bearer " + token);
        www.SetRequestHeader("Content-Type", "multipart/form-data");

        Debug.Log(form.data);

        Debug.Log(www.GetRequestHeader("photosceneid") + "PhotoId");
 
        var operation = www.SendWebRequest();
        if(www.uploadProgress <1)
        {
            Debug.Log(www.uploadProgress);
        }
        while (!operation.isDone)
        {
            if (www.uploadProgress < 1f)
            {
                Debug.Log(www.uploadProgress);
            }
            else
            {
                Debug.Log("finished");
            }
            await Task.Yield();
        }

        if (www.result == UnityWebRequest.Result.Success)
        {

            Debug.Log($"Success: {www.downloadHandler.text}");
            var deserializedPostData = JsonUtility.FromJson<PostResult>(www.downloadHandler.text);
            Debug.Log(deserializedPostData.success);

            string response = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);
        }
        else
        {
            Debug.Log($"Failed: {www.error}");
        }


    }

I'm still unable to achieve the upload as the current code is returning the following response from the request

"Usage":"2.1459798812866","Resource":"\/file","Error":{"code":"19","msg":"Specified Photoscene ID doesn't exist in the database"}}
UnityEngine.Debug:Log (object)

What I've noticed during the debugging process is that upon removing the following code snippet, I no longer receive error code 19 . But when trying to add even a single image with it's byte data am returned to the issue of no Photoscene ID.

        for (int i = 0; i < 20; i++) //20 is the total amount of images we can upload in a single request
        {
            byte[] img = File.ReadAllBytes("/Users/kreutsx1/Documents/ImagesMe/" + String.Format("{0}.jpg", photosceneAddImage.fileCount + 1));
            form.AddBinaryData(String.Format("file[{0}]", photosceneAddImage.fileCount+1), img);
            photosceneAddImage.fileCount++;
            Debug.Log(photosceneAddImage.fileCount);
        }

Solution

  • It looks like the problem is at code level. If the file shows in photoscene, but has a zero filesize, it means that the file was allocated, but the "upload protocol" is wrong. From my humble experience, it is usually due to wrong content-type or file upload.

    I am not very "tech savvy" in Unity, nor in C#, but my suggestion would be to try uploading it not as "multipart/form-data", but rather as "application/x-www-form-urlencoded".

    Just try something like this outside Unity in vanilla C# env:

    var client = new RestClient("https://developer.api.autodesk.com/photo-to-3d/v1/file");
    client.Timeout = -1;
    var request = new RestRequest(Method.POST);
    request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
    request.AddHeader("Authorization", "Bearer <YOUR_TOKEN_HERE>");
    request.AddParameter("photosceneid", "<YOUR_PHOTOSCENE_ID_HERE>");
    request.AddParameter("type", "image");
    request.AddFile("file[0]", "/C:/Users/denix/Downloads/20160625_081727.jpg");
    IRestResponse response = client.Execute(request);
    Console.WriteLine(response.Content);
    

    I suggest, before jumping into the code, to check the Reality Capture workflow in things like Postman, to get accommodated with the API and the eventual problems. Have a look at this blogpost: https://forge.autodesk.com/blog/hitchhikers-guide-reality-capture-api

    Where you will find not only the Postman Collection ready to be used, but also the undocumented calls like investigating the photoscene contents to see the number of uploaded files and their sizes.