/SMPL-Anthropometry

Measure the SMPL body model

Primary LanguagePythonMIT LicenseMIT

SMPL-Anthropometry

Measure the SMPL/SMPLX body models and visualize the measurements and landmarks.


🔨 Getting started

You can use a docker container to facilitate running the code. Run in terminal:

cd docker
sh build.sh
sh docker_run.sh CODE_PATH

by adjusting the CODE_PATH to the SMPL-Anthropometry directory location. This creates a smpl-anthropometry-container container.

If you do not want to use a docker container, you can also just install the necessary packages from docker/requirements.txt into your own enviroment.

Next, provide the body models (SMPL or SMPLX) and:

  1. put the SMPL_{GENDER}.pkl (MALE, FEMALE and NEUTRAL) models into the data/smpl folder
  2. put the SMPLX_{GENDER}.pkl (MALE, FEMALE and NEUTRAL) models into the data/smplx folder

All the models can be found here.


🏃 Running

First import the necessary libraries:

from measure import MeasureBody
from measurement_definitions import STANDARD_LABELS

Next define the measurer by setting the body model you want to measure with model_type (smpl or smplx):

measurer = MeasureBody(model_type)

Then, there are two ways of using the code for measuring a body model depending on how you want to define the body:

  1. Define the body model using the shape betas and gender gender parameters:
measurer.from_body_model(gender=gender, shape=betas) 
  1. Define the body model using the N x 3 vertices verts (N=6890 if SMPL, and 10475 if SMPLX):
measurer.from_verts(verts=verts) 

     📣 Defining the body using the vertices can be especially useful when the SMPL/SMPLX vertices have been
          further refined to fit a 2D/3D model and do not satsify perfectly a set of shape parameters anymore.

Finally, you can measure the body with:

measurement_names = measurer.all_possible_measurements # or chose subset of measurements 
measurer.measure(measurement_names) 
measurer.label_measurements(STANDARD_LABELS) 

Then, the measurements dictionary can be obtained with measurer.measurements and the labeled measurements can be obtained with measurer.labeled_measurements. The list of the predefined measurements along with its standard literature labels are:

STANDARD_MEASUREMENT = {
    'A': 'head circumference',
    'B': 'neck circumference',
    'C': 'shoulder to crotch height',
    'D': 'chest circumference',
    'E': 'waist circumference',
    'F': 'hip circumference',
    'G': 'wrist right circumference',
    'H': 'bicep right circumference',
    'I': 'forearm right circumference',
    'J': 'arm right length',
    'K': 'inside leg height',
    'L': 'thigh left circumference',
    'M': 'calf left circumference',
    'N': 'ankle left circumference',
    'O': 'shoulder breadth',
    'P': 'height'
    }

All the measurements are expressed in cm.


You can also compute the mean absolute error (MAE) between two sets of measurements as:

from evaluate import evaluate_mae
MAE = evaluate_mae(measurer1.measurements,measurer2.measurements)

where measurer1 and measurer2 are two intances of the MeasureBody class.


💿 Demos

You can run the measure.py script to measure all the predefined measurements (mentioned above) and visualize the results for a zero-shaped T-posed neutral gender SMPL body model:

python measure.py --measure_neutral_smpl_with_mean_shape

The output consists of a dictionary of measurements expressed in cm, the labeled measurements using standard labels,and the viualization of the measurements in the browser, as in the Figure above.

Similarly, you can measure a zero-shaped T-posed neutral gender SMPLX body model with:

python measure.py --measure_neutral_smplx_with_mean_shape

You can run the evaluate.py script to compare two sets of measurements of randomly shaped SMPL bodies as:

python evaluate.py

The output consists of the mean absolute error (MAE) between two sets of measurements.



📝 Notes

Measurement definitions

There are two types of measurements: lenghts and circumferences.

  1. Lengths are defined as distances between landmark points defined on the body model
  2. Circumferences are defiend as plane cuts of the body model

To define a new measurement:

  1. Open measurement_definitions.py
  2. add the new measurement to the MEASUREMENT_TYPES dict and set its type: LENGTH or CIRCUMFERENCE
  3. depending on the measurement type, define the measurement in the LENGTHS or CIRCUMFERENCES dict of the appropriate body model (SMPLMeasurementDefinitions or SMPLXMeasurementDefinitions)
    • LENGTHS are defined using 2 landmarks - the measurement is found as the distance between the landmarks
    • CIRCUMFERENCES are defined with landmarks and joints - the measurement is found by cutting the body model with the plane defined by a point (landmark point) and normal ( vector connecting the two joints)
  4. If the measurement is a CIRCUMFERENCE, a possible issue that arises is that the plane cutting results in multiple body part slices. To alleviate that, define the body part where the measurement should be located in CIRCUMFERENCE_TO_BODYPARTS dict. This way, only the slice in the corresponding body part is used for finding the measurement. The body parts are defined by the face segmentation located in data/smpl_body_parts_2_faces.json or data/smplx_body_parts_2_faces.json.

Measurement normalization

If a body model has unknown scale (ex. the body was regressed from an image), the measurements can be height-normalized as so:

measurer = MeasureBody(model_type) # assume given model type
measurer.from_body_model(shape=betas, gender=gender) # assume given betas and gender

all_measurement_names = measurer.possible_measurements
measurer.measure(all_measurement_names)
new_height = 175
measurer.height_normalize_measurements(new_height)

This creates a dict of measurements measurer.height_normalized_measurements where each measurement was normalized with:

new_measurement = (old_measurement / old_height) * new_height

Additional visualizations

To visualize the SMPL and SMPLX face segmentation on two separate plots, run:

python visualize.py --visualize_smpl_and_smplx_face_segmentation

To visualize the SMPL and SMPLX joints on the same plot, run:

python visualize.py --visualize_smpl_and_smplx_joints

To visualize the SMPL and SMPLX point segmentations on two side-by-side plots, run:

python visualize.py --visualize_smpl_and_smplx_point_segmentation

NOTE: You need to provide the point_segmentation_meshcapade.json files in the folders data/smpl and data/smplx from here.

To visualize the SMPL and SMPLX landmarks on two side-by-side plots, run:

python visualize.py --visualize_smpl_and_smplx_landmarks


TODO

  • Implement SMPL-X body model
  • Implement STAR body model
  • Implement SUPR body model
  • Add height normalization for the measurements
  • Allow posed and shaped body models as inputs, and measure them after unposing

Leave a star if you find this repository useful