DavidBoja / SMPL-Anthropometry

Measure the SMPL body model
MIT License
165 stars 22 forks source link

Not accurate measurements #24

Open AndreAhmed opened 2 weeks ago

AndreAhmed commented 2 weeks 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 2 weeks 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 2 weeks 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 2 weeks ago

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

kristijanbartol commented 2 weeks 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 week 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}")