DavidBoja / SMPL-Anthropometry

Measure the SMPL body model
MIT License
171 stars 25 forks source link

Not accurate measurements #24

Open AndreAhmed opened 1 month ago

AndreAhmed commented 1 month ago

Thanks for your contributions, I have integrated your code, into https://github.com/vchoutas/smplify-x I fitted an image then I get a 3D SMPLX Model, then I have used your code to calculate the measurments The pose is little bit correct, however as first insight, my height is not 162.31, it's around 176. image

And the following has been integrated into :

` measurer = MeasureBody(model_type) measurer.from_verts(torch.tensor(vertices)) measurement_names = measurer.all_possible_measurements measurer.measure(measurement_names) measurer.label_measurements(STANDARD_LABELS)

    # Add measurements to the result dictionary
    results[min_idx]['result']['measurements'] = measurer.measurements
    results[min_idx]['result']['labeled_measurements'] = measurer.labeled_measuremen`

in the following line :

https://github.com/vchoutas/smplify-x/blob/master/smplifyx/fit_single_frame.py#L508

AndreAhmed commented 1 month ago

tried the following also

      measurer.measure(measurement_names)
        new_height = 175
        measurer.height_normalize_measurements(new_height)

        measurer.label_measurements(STANDARD_LABELS)

        # Add measurements to the result dictionary
        results[min_idx]['result']['measurements'] = measurer.measurements
        results[min_idx]['result']['labeled_measurements'] = measurer.labeled_measurements
kristijanbartol commented 1 month ago

Hi @AndreAhmed ,

Could you also provide the results for the updated height? Are the measurements now more accurate?

Note that the results you get from a single image might not necessarily reflect your actual body shape, especially with methods that are not state-of-the-art, such as "vanilla" Smplify-X. You have correctly identified the problem of scale ambiguity from a single image, hence, the inaccurate body height estimation.

The purpose of this repository is that, once you have an SMPL(-X) mesh, you can extract a set of body measurements. The purpose is not to serve as a tool for accurate body measurement estimation. In addition, the problem of single-view human shape estimation is still an active area of research.

For better estimation results, try SHAPY: https://shapy.is.tue.mpg.de.

AndreAhmed commented 1 month ago

@kristijanbartol Thanks for your quick input. But how about other measurements, like Waist, stomach,..etc? I assume they are fixed ?

kristijanbartol commented 1 month ago

All the measurements are extracted exactly as shown in the Figure you attached. You might say their definition is "fixed" w.r.t. SMPL(-X) meshes, yes. If you specify a different height, the mesh is scaled and so are the corresponding body measurements. Maybe I misunderstood your question...

AndreAhmed commented 1 month ago

@kristijanbartol I have tried to export the betas, but they are not reflecting the actual shape parameters. Is what I did wrong? I mean the exported body. So What I did is to export the json, and render the SMPLX in Unity3D, and attach the shape parameters, but the body is not exactly the same as the one you constructed for measurments, in terms of height, body size,..etc.

def export_smpl_data_for_unity(updated_length_definitions, body_model, body_pose, measurer, camera, result_fn='smpl_data_for_unity.json'):
    # Extract SMPL keypoints (joints) and vertices
    model_output = body_model(return_verts=True, body_pose=body_pose)  # Run the body model
    vertices = model_output.vertices.detach().cpu().numpy().squeeze()
    faces = body_model.faces.astype(int)
    betas = body_model.betas.detach().cpu().numpy().squeeze()

    print("Available landmarks:")
    for key, value in measurer.landmarks.items():
        print(f"{key}: {value}")

    # Extract landmarks and their corresponding vertex indices
    landmarks = {}
    landmark_to_vertex = {}  # To map landmarks to their corresponding vertices
    for landmark_name, landmark_index in measurer.landmarks.items():
        if isinstance(landmark_index, tuple):
            # If it's a tuple, take the average of the specified vertices
            landmark_position = np.mean(vertices[list(landmark_index)], axis=0)
            landmark_to_vertex[landmark_name] = list(landmark_index)
        else:
            landmark_position = vertices[landmark_index]
            landmark_to_vertex[landmark_name] = [landmark_index]

        # Convert landmark position to a dict with x, y, z keys
        landmarks[landmark_name] = {
            "x": float(landmark_position[0]),
            "y": float(landmark_position[1]),
            "z": float(landmark_position[2])
        }

    # Prepare measurement definitions
    length_definitions = {}
    for name, definition in updated_length_definitions.items():
        valid_landmarks = [lm for lm in definition if lm in landmarks]
        if len(valid_landmarks) == len(definition):
            # Convert the landmarks to dict format for Unity
            length_definitions[name] = [landmarks[lm] for lm in valid_landmarks]
        else:
            print(f"Warning: Some landmarks missing for length definition '{name}'")

    circumference_definitions = {}
    for name, definition in measurer.circumf_definitions.items():
        circumference_definitions[name] = {
            "LANDMARKS": definition["LANDMARKS"],
            "JOINTS": definition["JOINTS"]
        }

    # Convert vertices to dict format with x, y, z keys
    vertex_dicts = [{"x": float(v[0]), "y": float(v[1]), "z": float(v[2])} for v in vertices]

    # Prepare data for export
    unity_data = {
        "landmarks": landmarks,
        "shape_parameters": betas.tolist(),  # Add shape parameters (betas) to the output
        "vertices": vertex_dicts,
        "faces": faces.tolist()
    }

    # Export to JSON
    with open(result_fn, 'w') as f:
        json.dump(unity_data, f, indent=2)

    print(f"SMPL data exported to {result_fn}")
DavidBoja commented 3 weeks ago

Hi @AndreAhmed

Thanks for your contributions, I have integrated your code, into https://github.com/vchoutas/smplify-x I fitted an image then I get a 3D SMPLX Model, then I have used your code to calculate the measurments The pose is little bit correct, however as first insight, my height is not 162.31, it's around 176.

@kristijanbartol Thanks for your quick input. But how about other measurements, like Waist, stomach,..etc? I assume they are fixed ?

Measurements are defined in measurement_definitions.py and adding new measurements is explained in the Readme

https://github.com/DavidBoja/SMPL-Anthropometry/blob/bde9bb99dcdb95d07f5c398c85e5639ac2b0e029/README.md?plain=1#L144-L162

@kristijanbartol I have tried to export the betas, but they are not reflecting the actual shape parameters. Is what I did wrong? I mean the exported body. So What I did is to export the json, and render the SMPLX in Unity3D, and attach the shape parameters, but the body is not exactly the same as the one you constructed for measurments, in terms of height, body size,..etc.

Are you using the same SMPL / SMPLX model in all cases?

AndreAhmed commented 3 weeks ago

@DavidBoja Yes I'm using the same SMPL/SMPLX

AndreAhmed commented 3 weeks ago

@DavidBoja The triangulated mesh has exact same shape parameters in terms of belly stomach, and other features. but using just the betas alone, they don't define well the exact smplx mesh if they are used alone.

DavidBoja commented 3 weeks ago

@DavidBoja The triangulated mesh has exact same shape parameters in terms of belly stomach, and other features. but using just the betas alone, they don't define well the exact smplx mesh if they are used alone.

So you have an SMPL with its shape parameters. You load those shape parameters into Unity3D to create the SMPL. And then the SMPL mesh from this repository and from from Unity3D do not correspond?

AndreAhmed commented 3 weeks ago

@DavidBoja

Yes they don't correspond at all, I asked Shapy guys, but they didn't answer. Also how do I export your measurment points done in python to Unity3D ? If you notice the woman, I just exported her betas, and they don't correspond at all. image image

DavidBoja commented 2 weeks ago

Well, then I'd presume that you are using different models; they should be equal if you are using the same model. There are several SMPL models: SMPL, SMPL+H, SMPLX, STAR,.. so check what are you using. This repo uses either SMPL or SMPLX. I'm not familiar with Unity so I really couldn't tell you what is going on under the hood.

Measurement points for lengths are basically the landmarks which are defined in landmark_definitons.py. To get the circumference points, you can edit the code here:

https://github.com/DavidBoja/SMPL-Anthropometry/blob/22324d1f23dcbd7922781ca26f7ac333354caf45/measure.py#L158-L198

and take the slice_segments_hull, which are basically segment points on the mesh that create the circumference measurement.