Morphing of the pelvis

I am trying to personalise my Mocap-PlugInSimpleGait model by morphing the source pelvis to match the geometry of STL file obtained from a CT scan.

After selecting the landmarks and obtaining MyScalingFunction.any, I want to proceed by implementing this scaling function into Mocap-Plug-in-gait_Simple model and visualize the dislocation of muscles attachment points.

In the tutorial, there is guidance on how to do the same but for Femur in a standing model. In addition, the explanation is for an older version of AMMR.

1 Like

Hi Ahmed,

To implement your scaling function into the Mocap-Plug-ingait_Simple model you will first need to set the scaling to standard in the Setup/BodyModelConfig.any file (or Setup/BodyModelConfigFullBody if using a full body model). While you have this file open, also include a blank anyscript file entitled ‘CustomScaling.any’:

#define BM_SCALING _SCALING_STANDARD_
#include "CustomScaling.any"

Similar to Tutorial 15.2 (Personalizing your model), within the CustomScaling.any file include the following code:

#define CUSTOM_SCALING_PelvisSeg
#define SOURCE_PELVIS "..\..\..\..\Body\AAUHuman\LegTLEM\TLEM2.1\pelvis"
#define TARGET_PELVIS "..\Input\Target_pelvis.stl"

HumanModel = {
  #include "MyScalingFunction.any"

  Scaling.GeometricalScaling.PelvisSeg = {

    AnyFunTransform3D &ScaleFunction = Main.HumanModel.SubjectSpecificScaling.Pelvis.ScaleFunction;
    AnyFunTransform3D &inv = Main.HumanModel.SubjectSpecificScaling.Pelvis.ReverseTransform;
  };

  //#include "CheckPelvisMorphing.any"
};

Within your MyScalingFunction.any file add the following code:

AnyFolder SubjectSpecificScaling = {

  AnyFolder Pelvis = {

    // Include manually selected points (if topology of stls aren’t the same)
    // as two matrices P0 (source points) and P1 (target points):
    #include "../Input/sourcepoints.any" // contains AnyMatrix P0 = {…};
    #include "../Input/targetpoints.any" // contains AnyMatrix P1 = {…};
    
    AnyFunTransform3D &TSeg2ScaleFrame = Main.HumanModel.Scaling.GeometricalScaling.PelvisSeg.TSeg2ScaleFrame;   
        
    AnyFunTransform3DLin2 AffineTransform = {
      Points0 = .TSeg2ScaleFrame(.P0);
      Points1 = .P1;
      Mode = VTK_LANDMARK_AFFINE;
    };
    
    AnyFunTransform3DLin2 ReverseTransform = {
      Points0 = .AffineTransform.Points1;
      Points1 = .AffineTransform.Points0;
      Mode = VTK_LANDMARK_RIGIDBODY;
    };
    
    AnyFunTransform3DSTL STLTransform = {
      PreTransforms = {&.AffineTransform}; 
      RBFDef.Type = RBF_Triharmonic;    
      RBFDef.Param = 0.2;
    
      AnyFixedRefFrame ref = {
        AnySurfSTL SourceSurf = {
        FileName = SOURCE_PELVIS;
        ScaleXYZ = {1, 1, 1};
        AnyFunTransform3D &pre = ...TSeg2ScaleFrame;
        };
        AnySurfSTL TargetSurf = {
        FileName = TARGET_PELVIS;
        ScaleXYZ = {1, 1, 1};  
        };
      };
      PolynomDegree = 1;
      SurfaceObjects0 = {&ref.SourceSurf};
      SurfaceObjects1 = {&ref.TargetSurf};
      NumPoints = 1500;  // Adjust until there is a good match                    
      BoundingBox.ScaleXYZ = {2, 2, 2};
      BoundingBox.DivisionFactorXYZ = {1, 1, 1};
      BoundingBoxOnOff = On;
      };
    
    AnyFunTransform3DRBF RBFTransform = {
      PreTransforms = {&.AffineTransform};
      RBFDef.Type = RBF_Triharmonic;  
      PolynomDegree = 1;
      Points0 = .AffineTransform.Points0;
      Points1 = .AffineTransform.Points1;
      BoundingBoxOnOff = On;
      BoundingBox.Type = BB_Cartesian;
      BoundingBox.ScaleXYZ={1,2,2}*1.2;
      BoundingBox.DivisionFactorXYZ ={1,1,1}*3;
    }; 

    // Adjust PreTransforms definition depending weather you’d like to use the STL   
    // or RBF transform for morphing

    AnyFunTransform3DIdentity ScaleFunction = {
      PreTransforms = {&.STLTransform, &.ReverseTransform};
      //      PreTransforms = {&.RBFTransform, &.ReverseTransform};
    };
  };  // PelvisSeg
}; //SubjectSpecificScaling Folder

For this example, we are assuming the user has manually chosen points and the source/target STLs do not have the same topology. However, if you have the same topology for the source and target bones you do not need to manually select/import points to perform the affine transformation, instead use the following code to obtain the source (P0) and target (P1) points (remember to pay attention to units for the target STL):

 AnyFile source_file = "..\Input\Source_pelvis.stl"; 
 AnyFile target_file = TARGET_PELVIS;

 AnyMatrix P0 = STL_Vertices(source_file, iarr(0, STL_Size(source_file, 1)[0] - 1), 1);
 AnyMatrix P1 = STL_Vertices(target_file, iarr(0, STL_Size(target_file, 1)[0] - 1), 1);

**Please note, using this method will require you to have access to the Source_pelvis.stl which I’ve attached at the end of this post. Save it in the same folder (input) as your Target_pelvis.stl.

Additionally, if you are using STLs with the same topology you can switch off UseClosestPointMatchingOnOff within the STLTransform:

AnyFunTransform3DSTL STLTransform = {
  [...]
  UseClosestPointMatchingOnOff = Off;              
};

Finally, if you’d like to check how well your scaling function captures the reality of the target STL please uncomment //#include “CheckPelvisMorphing.any”, create a new anyscript file entitled Check-PelvisMorphing.any, and add the following code within this file:

Main.HumanModel.BodyModel.Trunk.SegmentsLumbar.PelvisSeg = {

  AnyRefNode targetstl = {
    AnyFunTransform3DIdentity RegistrationTranform = {
      PreTransforms = {&Main.HumanModel.Scaling.GeometricalScaling.PelvisSeg.inv,
      &Main.HumanModel.BodyModel.Trunk.SegmentsLumbar.PelvisSeg.Scale_Trunk_Pelvis.ScaleAfterInterfaceMorphingDef.Scale.T1_Inv};
    };

  AnyDrawSurf target_pelvis = {
    FileName=TARGET_PELVIS;
    ScaleXYZ={1,1,1};
    RGB={0,1,0};
    AnyFunTransform3D &reg = .RegistrationTranform;    
    };
  };
};

Please let me know if this works.

Best Regards,
Christine

Source_pelvis.7z (4.9 MB)

Thank you Christine for your detailed reply.
I followed it step by step but unfortutantly I got an error when I tried to load the model.

I followed the following steps:

1- In setup folder, I opened BodyModelConfig.any file
Then set scaling from XYZ to be STANDARD
#define BM_SCALING SCALING_STANDARD
2- In the same file I defined a blank file entitled ‘CustomScaling.any’
#include "CustomScaling.any"
3- Created CustomScaling.any file inside Setup folder,
the file contains the following the code you mentioned in your reply

4- Then created MyScalingFunction.any file inside setup folder with the code you mentioned in your reply

5- Moved sourcepoints.any and targetpoint.any files to input folder
6- Moved target stl file to input folder

I got the following error when I I tried to load the MocapExamples\Plug-in-gait_Simple model:

ERROR(SCR.PRS9) : C:/U..s/a..n/D..s/5..a/3..l/4..s/A..o/A..n/M..s/P..e/S..p/CustomScaling.any(6) : 'HumanModel' : Unresolved object
Model loading skipped

How to resolve this error?

Also, I have a question concerning
#define SOURCE_PELVIS "........\Body\AAUHuman\LegTLEM\TLEM2.1\pelvis"
Should I replace the pelvis.anysurf3 in TLEM2.1 folder by the stl file provided by you?
I tried this also, but I still obtain the same error!

I want to add the following:

My previous reply and it’s associated error was based on edition BodyModelConfig.any file:
Setting scaling to STANDARD and including customscaling.any

#path BM_PLUGIN_FILE “BodyModelConfig.any”
#define BM_CONFIG_PLUGIN BM_PLUGIN_FILE

// ----------------------------------------------------------
// Model configuration:
// For more info on body model configuration options please load the model and double click on:
// #path HTML_DOC “<AMMR_PATH_DOC>/bm_config/index.html”
// ----------------------------------------------------------
Main = {

#define BM_SCALING SCALING_XYZ
// #include “CustomScaling.any”

#ifndef BM_LEG_MODEL
#define BM_LEG_MODEL LEG_MODEL_TLEM2
#endif

#define BM_TRUNK_MUSCLES OFF
#define BM_ARM_RIGHT OFF
#define BM_ARM_LEFT OFF

};

However, while trying to use BodyModelConfigFullBody:
Setting scaling to STANDARD and including customscaling.any

#path BM_PLUGIN_FILE “BodyModelConfigFullBody.any”
#define BM_CONFIG_PLUGIN BM_PLUGIN_FILE

// ----------------------------------------------------------
// Model configuration:
// For more info on body model configuration options please load the model and double click on:
// #path HTML_DOC “<AMMR_PATH_DOC>/bm_config/index.html”
// ----------------------------------------------------------
Main = {

#define BM_SCALING SCALING_STANDARD
#include “CustomScaling.any”

#ifndef BM_LEG_MODEL
#define BM_LEG_MODEL LEG_MODEL_TLEM2
#endif

#define BM_TRUNK_CERVICAL_MUSCLES ON
#define BM_TRUNK_MUSCLES ON
#define BM_ARM_RIGHT ON
#define BM_ARM_LEFT ON

};
#define BM_ARM_DETAILED_HAND OFF
#define BM_LEG_MUSCLES_RIGHT MUSCLES_SIMPLE
#define BM_ARM_SHOULDER_RHYTHM OFF

I got the following error:

ERROR(SCR.PRS20) : …HumanModel.any(40) : Defined at : …AnyMan.ClassTemplates.any(441) : ‘BodyMass’ : Illegal assignment:
‘BodyMass’ already assigned at : AnyBody.7.2.x\AMMR.v2.2.0\Application\MocapExamples\Plug-in-gait_Simple\Setup\SubjectSpecificData.any(6)
Model loading skipped

By following error sources:
HumanModel.any >>>>> Template_Anthropometrics_50th_percentile Anthropometrics = {};
AnyMan.ClassTemplates.any >>>> AnyVar BodyMass = 75;
SubjectSpecificData.any >>>>> BodyMass = 66;

Hi Ahmed,

This must have been something I forgot to include in the instructions, within the SubjectSpecificData.any file comment out the code between the lines

Main.ModelSetup.SubjectSpecificData = {
//  {
//     BodyMass = 66;
//     BodyHeight = 1.75;
//     [...]
//     [...]
};

That should get rid of that error. Also, you do not need to replace that pelvis.anysurf file.

Best Regards,
Christine

Hi Christine,

Thank you for your quick feedback which solved the previously mentioned error of Anthropometrics.
However, now the model gives the following warning&error:

WARNING(OBJ1) : C:/U…s/a…n/D…s/5…a/3…l/4…s/A…o/Body/A…n/S…g/ScalingCustom.any(402) : PelvisSeg.scaling_message_PelvisSeg : Custom scaling for ‘PelvisSeg’ segment is used! Please specify a scaling law should an ‘Unresolved object’ error occur

This warning message led me to the ScalingCustom.any file which is found in folder
\Body\AAUHuman\Scaling

Does this mean there is a conflict now between the ScalingCustom.any file -which is the general custom scaling file of AAUHuman- and the CustomScaling.any file which was created specifically for the pelvis and inserted into setup folder of Mocap model?

ERROR(SCR.PRS9) : C:/U…s/a…n/D…s/5…a/3…l/4…s/A…o/Body/A…n/Arm/AddOnOutsideBlockForKinematics.any(26) : ‘Thorax’ : Unresolved object
Model loading skipped

This error led me to line:
&…Scaling.GeometricalScaling.Thorax.ScaleFunction
of AddOnOutsideBlockForKinematics.any file

Did you try the suggested pelvis morphing protocol in a Mocap model, does it work for you?

Hi Ahmed,

The warning that comes up is normal, think of it more as an ‘are you sure you meant to do that’ kind of warning. And in this case yes we did want to define a CustomPelvis. You will get additional warning messages for each of new CustomScaling segment you define.

The error says that something ‘Thorax’ isn’t define properly/does not exist. I wrote the suggested protocol based on implementing the pelvis morphing into the Mocap model, it did work. Now I think its just a couple rerouting of paths for you until it works, hopefully this will be fixed soon. What is happening in ‘AddOnOutsideBlockForKinematics.any’?

Best Regards,
Christine

Hi Christine,

Thank you for the clarification.

I managed to bypass the previously the following two errors:
-Knowing I implemented morphing protocol based on BodyModelConfigFullBody.any of AnyBody V7.2.x and its associated AMMR, on the other hand when I try BodyModelConfig.any the model shows no response at all for the assigned scaling, I think this is maybe due to that starting from V.2.x and onwards Full body morphology is activated by default, am I right?-

First error) Thorax unresolved in AddOnOutsideBlockForKinematics.any

ThoraxSegRef ={

AnyMat33 Mirror ={{.Sign,0,0},{0,1,0},{0,0,1}};
AnyFunTransform3DLin Scale = {
AnyFunTransform3DLin Transform_ijNode = {
ScaleMat = …ARel;
Offset = …sRelStd*…ARel;
};
PreTransforms = {
&Transform_ijNode ,
&…Scaling.GeometricalScaling.Thorax.ScaleFunction //I skipped the error here by replacing it with PelvisSeg -this was just a try to get the model loaded-
};
ScaleMat = .ARel’;
Offset = -.sRel;
};

Second error) Trunk unresolved in ScalingCustom.any

AnyFolder Trunk = {
#ifndef CUSTOM_SCALING_Trunk
AnyFunTransform3D &ScaleFunction = …Scaling.GeometricalScaling.Trunk.ScaleFunction; //Again, I skipped the error here by replacing it with PelvisSeg -this was just a try to get the model loaded-
#else
/// The rigid body transform from segmental to scaling reference frame
AnyFunTransform3DIdentity TSeg2ScaleFrame = {};
AnyMessage scaling_message_Trunk =
{
TriggerPreProcess = On;
Type = MSG_Warning;
Message = “Custom scaling for ‘Trunk’ segment is used! Please specify a scaling law should an ‘Unresolved object’ error occur”;
};
#endif
};

then the model loaded and the analysis was run without any issue. However, I think I can’t trust the scaling after both modifications.

Alternatively, I tried to implement the protocol utilising MoCap model of AnyBody V.7.1.x and its associated AMMR, considering BodyModelConfig.any (Knowing that in that version of AMMR BodyModelConfigFullBody.any file isn’t included in setup folder of MocAp models, however, when considering BodyModelConfig.any, morphology still set to TLEM2, am I right?)

This time, the model runs perfectly without any errors!


Now, I have a question concerning subject anthropometrics data:

After commenting out all the code of SubjectSpecificData.any,

Does the subject mass and height still locked to:
BodyMass = 66;
BodyHeight = 1.75;

In addition, how to access the control to

  • BodyMass
  • BodyHeight
  • Fat%

in order to consider any patient-specific anthropometrics.

Hi Christine,

I noticed that after performing the scaling, not only the pelvis is morphed, but all of te human model is scalled!
I think this is expected because we switched scaling to STANDARD from LENGTHMASSFAT.

Is the model still valid, as I understand Mocap model is caled to adapt subject specifict data, and by switching scaling to STANDARD from LENGTHMASSFAT, the model doesn't represent the subject in the trial anymore, am I right?

How to keep the model in its generic scaling while morphing only the pelvis?

Is the model still valid after the scaling?
Refering to tutorial 16. Validation of Models
Do you recommend certain validation procedures to follow in order to validate the model after morphing certain parts.

Hi Ahmed,

Apologizes for the confusion, you can use any scaling law you prefer and have data for. I only mentioned STANDARD, because this was the one used as an example in the tutorial. I have used the LENGTH-MASS-FAT scaling in the past when I morphed all of the lower limb bones and used the Mocap model. In this case comment back in the data in SubjectSpecificData.any and define whatever you have data for. With regards to validation procedures, this is always a very tricky subject. I recommend the following paper on the topic:

Lund ME, de Zee M, Andersen MS, Rasmussen J. On validation of multibody musculoskeletal models. Proc Inst Mech Eng H 2012;226:82–94. doi:10.1177/0954411911431516.

Best Regards,
Christine

Hi Christine,

Thank you for the clarification.
I will check the paper you recommended.

Kind regards,
Ahmed

Hi, I am not able to run this codes. I am getting constant error. Please Help!
Regards,
Lewis

What kind of error you got?

This topic was automatically closed 125 days after the last reply. New replies are no longer allowed.