GMFoot MoCap and RBF Scaling

Hello, I’ve been trying to get the GM foot model to run with the suggested RBFLandmark scaling for each individual bones. I can scale and morph each bone with the GMFreePosture Model, but would like to incorporate this with gait data. I’ve attached my model in a zip file below.

When i run my model it returns with:

ERROR(SCR.SCN6) :   D:/D..s/A..s/A..y/Body/A..n/B..s/G..t/BodyModel.any(37)  :   'TRUNK' :  Unexpected character.
Model loading skipped

Thank you for any help you can provide.
Thanks,
Zach

Hi Zach,

I am sorry for the late reply.

Unfortunately the structure of the MoCap models is a little different from other models. You need to do a few modifications to make it work with the subject-specific scaling functions.

  1. Please copy Body\AAUHuman\Scaling\FootScaling\ScalingLengthMassFatRBF.any into the Model folder.

In MoCap-Model/Model you need to find HumanModel.any and change the path to be relative and looking at the file that you copied:


//     #include "<ANYBODY_PATH_BODY>\Scaling\FootScaling/ScalingLengthMassFatRBF.any"
   #include "ScalingLengthMassFatRBF.any"

  1. In ScalingLengthMassFatRBF.any for the segments that you individualize you would need to define a block like the example below:
      
      AnyFolder Thigh = {
        AnyVar LengthScale  = ...AnthroSegmentLengths.Right.ThighLength / ...StandardParameters.Right.Thigh.Length;
        AnyVar ms = ...MassScaling.Right.Thigh.MassScale;
        AnyVar ls = LengthScale;
        
        #ifndef CUSTOM_SCALING_Right_Thigh
        AnyFunTransform3DLin ScaleFunction = {
          ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
          Offset = {0, 0, 0};
        };
        #else
        
        #endif
        
      };
    }; // Right

This block of code should exclude ScaleFunction if CUSTOM_SCALING_#SIDE#_#SEGMENT# is specified.

This should be sufficient. Please let me know if that makes sense and you can make it work.

Kind regards,
Pavel

Hi Pavel, again thank you for your time, I see where the differences exist between the free posture and the mocap models.

I’ve completed the changes and the model is returning:

Closing model...
Deleting last loaded model...
...Model deleted.
Loading  Main  :  "D:\Documents\Anyscripts\AMMR.v1.6.2-MyDemo - Copy\Application\Beta\MoCap-GMFoot\MoCap-GMFoot.main.any"
Scanning...
Parsing...
Constructing model tree...
Linking identifiers...
Evaluating constants...
ERROR(SCR.EXP0) :   D:/D..s/A..s/A..y/A..n/Beta/M..t/M..l/Environment.any(53)  :   'sRel'  :  Error in expression. Please refer to the following error messages for details ...
ERROR(SCR.EXP.FUN.EXT8) :   D:/D..s/A..s/A..y/A..n/Beta/M..t/M..l/Environment.any(37)  :   LocationFunction  :  Exception in Python extention module.
  Python error : 
Model loading skipped

The Python file FootLocation4 is already in the model folder.
I look forward to your reply.
Many Thanks,
Zach

Zach,

I tried and got the same error. And it seems that you may be using Python 3 and it has changed a couple of functions. Please try this correction, it worked for me.

Kind regards,
Pavel

Please rename it into .py

Thanks Pavel, the model is loading now. As you can probably see too, there seems to be a problem with the location rest of the foot, but I will investigate this further when i try an individualise more bones into the GM model, perhaps this will adjust the foot when these bones are morphed.

Thanks for your help Pavel.
Zach

Hi Pavel, I can get it to work with each the calcaneus and talus separately, but I am getting an “object already declared at” error when i try to combine the laws. I tried to change the name of the scale function of one of the bones but then i get another error at the AnyInt.

My ScalingLengthMassFatRBF folders look like

 // AnyFolder &Talus = Foot;
		
        AnyFolder Talus = {
        AnyVar LengthScale  = ...AnthroSegmentLengths.Right.TalusLength / ...StandardParameters.Right.Talus.Length;
        AnyVar ms = ...MassScaling.Right.Talus.MassScale;
        AnyVar ls = LengthScale;
        
        #ifndef CUSTOM_SCALING_Right_Talus
        AnyFunTransform3DLin ScaleFunction = {
          ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
          Offset = {0, 0, 0};
        };
        #else
        
        #endif
        
      };
        
     // AnyFolder &Calcaneus = Foot;
        
        AnyFolder Calcaneus = {
        AnyVar LengthScale  = ...AnthroSegmentLengths.Right.CalcaneusLength / ...StandardParameters.Right.Calcaneus.Length;
        AnyVar ms = ...MassScaling.Right.Calcaneus.MassScale;
        AnyVar ls = LengthScale;
        
        #ifndef CUSTOM_SCALING_Right_Calcaneus
        AnyFunTransform3DLin ScaleFunction = {
          ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
          Offset = {0, 0, 0};
        };
        #else
        
        #endif
        
      };

and my HumanModel file looks like:

 //Choose between scaling laws
  //#include "<ANYBODY_PATH_BODY>Scaling\ScalingUniform.any"
  //#include "<ANYBODY_PATH_BODY>Scaling\ScalingLengthMass.any" 
  //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\ScalingLengthMassFat.any" 
  //#include "<ANYBODY_PATH_BODY>\Scaling\FootScaling/ScalingLengthMassFatRBF.any"
    #include "ScalingLengthMassFatRBF.any"
 
  Scaling = {
    //This is the file which set the segments lenghts
    #include "AnyManRBF.any" 
    
    //GeometricalScaling.Right.Foot = {#include "../Scaling/RBFLandmarksTalus.any"};
	GeometricalScaling.Right.Foot = {#include "../Scaling/RBFLandmarksCalcaneus.any"};
    
    //MorphingLandmarks = {AnyFolder &SegRef = Main.Studies.HumanModel.BodyModel.Right.Leg.Seg;};
    //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\MorphingLandmarks.any"
  };
  #include "FootType.any"
};

I’m sure it’s a trivial organisational problem, sorry!

Hi Zach,

Yes, it is simple. You provide your RBF scaling functions and redefine the scaling law at the same time to contain a linear scaling functions. They conflict.

The way I expected you to work was to modify the scaling law, and externally add this block:

 
#define CUSTOM_SCALING_Right_Talus
#define CUSTOM_SCALING_Right_Calcaneus

Scaling = {
    //This is the file which set the segments lenghts
    #include "AnyManRBF.any" 
    
    GeometricalScaling.Right.Foot = {#include "../Scaling/RBFLandmarksTalus.any"};
    GeometricalScaling.Right.Foot = {#include "../Scaling/RBFLandmarksCalcaneus.any"};
    
    //MorphingLandmarks = {AnyFolder &SegRef = Main.Studies.HumanModel.BodyModel.Right.Leg.Seg;};
    //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\MorphingLandmarks.any"
  };

Please note that this code should be included before HumanModel.any so it would have an effect. Just remove it and define before:

  #if MotionAndParameterOptimizationModel
  #include "Model/Kinematics.any"
  #endif 
  
  #if InverseDynamicModel
  #include "Model/InverseDynamics.any"
  #endif

Hope this makes sense.

Kind regards,
Pavel

Hi Pavel, i’m getting back error:


Closing model...
Deleting last loaded model...
...Model deleted.
Loading  Main  :  "D:\Documents\Anyscripts\AMMR.v1.6.2-MyDemo - Copy (2)\Application\Beta\MoCap-GMFoot\MoCap-GMFoot.main.any"
Scanning...
Parsing...
Constructing model tree...
ERROR(SCR.PRS9) :   D:/Documents/A..s/A..)/Body/A..n/FootGM/Seg.any(223)  :   'ScaleFunction'  :  Unresolved object
Model loading skipped

this is after defining the custom scaling laws.

Main = {
  
 //** ModelSetup will let you edit the general Marker setup and the Foot Folder location** 
  #include "Model/ModelSetup.any" 
 //** Trials will let you edit names and Start-End times of the trials** 
  #include "Model/TrialSpecificData3.any"

  #define CUSTOM_SCALING_Right_Talus
  #define CUSTOM_SCALING_Right_Calcaneus
  
  #if MotionAndParameterOptimizationModel
  #include "Model/Kinematics.any"
  #endif 
  
  #if InverseDynamicModel
  #include "Model/InverseDynamics.any"
  #endif

}; //Main

Sorry if i have misunderstood Pavel.
Many Thanks,
Zach

Zach,

The place to provide these #defines is correct. Did you remove definition of custom scaling functions from HumanModel.any?

If yes, you need to provide them again. If not - it could be that the one for calcaneus is commented out. Please check.

The logic is simple: the scaling law should either use linear one or custom - these switched control behaviour.

Pavel

New error:

ERROR(SCR.PRS1) :   D:/D..s/A..s/A..)/A..n/Beta/M..t/S..g/RBFLandmarksCalcaneus.any(2)  :   'Transform'  :  Object already declared at  : 
  D:\Documents\Anyscripts\AMMR.v1.6.2-MyDemo - Copy (2)\Application\Beta\MoCap-GMFoot\Scaling\RBFLandmarksTalus.any(2)  :  'Transform'

HumanModel.any

AnyFolder HumanModel={
  
  
  
//    // Select the body model:
//    // ----------------------
//    // This file contains a list of all body parts, select them to create
//    // the body model wanted.
//    #include  "BodyPartsSetup.any"
//    
    // This file creates the body model from the selected list.
    #include  "<ANYBODY_PATH_BODY>BodyModels\GenericBodyModelFoot\BodyModel.any"

 
 AnyFolder StrengthParameters={
    AnyVar SpecificMuscleTensionSpine= 150; //N/cm^2
    AnyVar StrengthIndexLeg= 1.53; 
    AnyVar SpecificMuscleTensionShoulderArm= 150; //N/cm^2
    
    AnyVar PlantarFasciaStiffnessCoeffPh = 0.2;
    AnyVar PlantarFasciaStiffnessCoeffMt = 0.5;
  };
  
  //Choose between scaling laws
  //#include "<ANYBODY_PATH_BODY>Scaling\ScalingUniform.any"
  //#include "<ANYBODY_PATH_BODY>Scaling\ScalingLengthMass.any" 
  //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\ScalingLengthMassFat.any" 
  //#include "<ANYBODY_PATH_BODY>\Scaling\FootScaling/ScalingLengthMassFatRBF.any"
    #include "ScalingLengthMassFatRBF.any"
    
  Scaling = {
    //This is the file which set the segments lenghts
	
    #include "AnyManRBF.any" 
	
    GeometricalScaling.Right.Foot = {#include "../Scaling/RBFLandmarksTalus.any"};
    GeometricalScaling.Right.Foot = {#include "../Scaling/RBFLandmarksCalcaneus.any"};
    
    //MorphingLandmarks = {AnyFolder &SegRef = Main.Studies.HumanModel.BodyModel.Right.Leg.Seg;};
    //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\MorphingLandmarks.any"
  };
  #include "FootType.any"
};

ScalingLengthMassFatRBF.any



// AnyFolder &Talus = Foot;
		
        AnyFolder Talus = {
        AnyVar LengthScale  = ...AnthroSegmentLengths.Right.TalusLength / ...StandardParameters.Right.Talus.Length;
        AnyVar ms = ...MassScaling.Right.Talus.MassScale;
        AnyVar ls = LengthScale;
        
        #ifndef CUSTOM_SCALING_Right_Talus
        AnyFunTransform3DLin ScaleFunction = {
          ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
          Offset = {0, 0, 0};
        };
        #else
        
        #endif
        
      };
        
		//AnyFolder &Calcaneus = Foot;
		
	  AnyFolder Calcaneus = {
        AnyVar LengthScale  = ...AnthroSegmentLengths.Right.CalcaneusLength / ...StandardParameters.Right.Calcaneus.Length;
        AnyVar ms = ...MassScaling.Right.Calcaneus.MassScale;
        AnyVar ls = LengthScale;
        
        #ifndef CUSTOM_SCALING_Right_Calcaneus
        AnyFunTransform3DLin ScaleFunction = {
          ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
          Offset = {0, 0, 0};
        };
        #else
        
        #endif
        
      };

Regards,
Zach

Code:
AnyFolder HumanModel={
  
  
  
//    // Select the body model:
//    // ----------------------
//    // This file contains a list of all body parts, select them to create
//    // the body model wanted.
//    #include  "BodyPartsSetup.any"
//    
    // This file creates the body model from the selected list.
    #include  "<ANYBODY_PATH_BODY>BodyModels\GenericBodyModelFoot\BodyModel.any"

 
 AnyFolder StrengthParameters={
    AnyVar SpecificMuscleTensionSpine= 150; //N/cm^2
    AnyVar StrengthIndexLeg= 1.53; 
    AnyVar SpecificMuscleTensionShoulderArm= 150; //N/cm^2
    
    AnyVar PlantarFasciaStiffnessCoeffPh = 0.2;
    AnyVar PlantarFasciaStiffnessCoeffMt = 0.5;
  };
  
  //Choose between scaling laws
  //#include "<ANYBODY_PATH_BODY>Scaling\ScalingUniform.any"
  //#include "<ANYBODY_PATH_BODY>Scaling\ScalingLengthMass.any" 
  //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\ScalingLengthMassFat.any" 
  //#include "<ANYBODY_PATH_BODY>\Scaling\FootScaling/ScalingLengthMassFatRBF.any"
    #include "ScalingLengthMassFatRBF.any"
    
  Scaling = {
    //This is the file which set the segments lenghts
	
    #include "AnyManRBF.any" 
	
    GeometricalScaling.Right.[b]Talus[/b] = {#include "../Scaling/RBFLandmarksTalus.any"};
    GeometricalScaling.Right.[b]Calcaneus [/b]= {#include "../Scaling/RBFLandmarksCalcaneus.any"};
    
    //MorphingLandmarks = {AnyFolder &SegRef = Main.Studies.HumanModel.BodyModel.Right.Leg.Seg;};
    //#include "<ANYBODY_PATH_BODY>Scaling\FootScaling\MorphingLandmarks.any"
  };
  #include "FootType.any"
};

Try this.

Hi Pavel,

ERROR(SCR.PRS9) :   D:/Documents/A..s/A..)/Body/A..n/FootGM/Seg.any(223)  :   'ScaleFunction'  :  Unresolved object
Model loading skipped

Zach

Main.any:


Main = {
 ...  
  #define CUSTOM_SCALING_Right_Talus
  #define CUSTOM_SCALING_Right_Calcaneus
  
  #if MotionAndParameterOptimizationModel
  #include "Model/Kinematics.any"
  #endif 
  ... 
}; //Main

ScalingLengthMassFat.any:


      AnyFolder Right ={
                
        AnyFolder Foot  = {
          AnyVar LengthScale = ...AnthroSegmentLengths.Right.FootLength / ...StandardParameters.Right.Foot.Length; 
          AnyVar WidthScale = ...AnthroSegmentLengths.Right.FootWidth / ...StandardParameters.Right.Foot.Width;
          AnyVar HeightScale = ...AnthroSegmentLengths.Right.FootHeight / ...StandardParameters.Right.Foot.Height;
          AnyVar ms = ...MassScaling.Right.Foot.MassScale;
          AnyVar ls = LengthScale;
          AnyVar ws = WidthScale;
          AnyVar hs = HeightScale;
          
          AnyFunTransform3DLin ScaleFunction = {
            ScaleMat = {{.hs, 0, 0},{0, .ls, 0},{0, 0, .ws}};
            Offset = {0, 0, 0};
          };
       };
        
       // AnyFolder &Talus = Foot;
		
       AnyFolder Talus = {
         AnyVar LengthScale  = ...AnthroSegmentLengths.Right.TalusLength / ...StandardParameters.Right.Talus.Length;
         AnyVar ms = ...MassScaling.Right.Talus.MassScale;
         AnyVar ls = LengthScale;
         
         #ifndef CUSTOM_SCALING_Right_Talus
         AnyFunTransform3DLin ScaleFunction = {
           ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
           Offset = {0, 0, 0};
         };
         #else
         
         #endif
         
       };
       AnyFolder Calcaneus = {
         AnyVar LengthScale  = ...AnthroSegmentLengths.Right.TalusLength / ...StandardParameters.Right.Talus.Length;
         AnyVar ms = ...MassScaling.Right.Talus.MassScale;
         AnyVar ls = LengthScale;
         
         #ifndef CUSTOM_SCALING_Right_Talus
         AnyFunTransform3DLin ScaleFunction = {
           ScaleMat = {{(.ms/.ls)^0.5, 0, 0},{0, .ls, 0},{0, 0, (.ms/.ls)^0.5}} ;
           Offset = {0, 0, 0};
         };
         #else
         
         #endif
         
       };
       

HumanModel.any:

  Scaling = {
    #include "AnyManRBF.any" 
    
      GeometricalScaling.Right.Talus = {#include "../Scaling/RBFLandmarksTalus.any"};
	GeometricalScaling.Right.Calcaneus = {#include "../Scaling/RBFLandmarksCalcaneus.any"};
  };

You will get an error that there is a circular dependency in the definition of foot scaling function, which is fair enough - this is how you specified height/length of foot in AnyManRBF.any:

  // Those two folders are used by the TD leg
  AnyFolder Right ={
    AnyVar ThighLength = Main.TrialSpecificData.Anthropometrics.ThighLength ;
    AnyVar ShankLength =Main.TrialSpecificData.Anthropometrics.ShankLength ;
    AnyVar FootLength = ...BodyModel.Right.Leg.Seg.Calcaneus.TuberCalcanei.sRel[1] - ...BodyModel.Right.Leg.Seg.DistalPhalange2.ToeTip.sRel[1]; //Back of heel (tuber calcanei) to second toe tip.
    AnyVar FootWidth = abs(...BodyModel.Right.Leg.Seg.Metatarsal5.MtPhalJoint.sRel[2] - ...BodyModel.Right.Leg.Seg.Metatarsal1.MtPhalJoint.sRel[2]); //MPjnt1 center to MPjnt5 center.
    AnyVar FootHeight = ...BodyModel.Right.Leg.Seg.Talus.AnkleJoint.sRel[0] - ...BodyModel.Right.Leg.Seg.Calcaneus.MedialProcess.sRel[0]; //vertical from base of heel (medial process) to ankle joint.
    AnyVar TalusLength = 0.03808687;

The model cannot compute distances and use them for constructing scaling functions, because it starts looping. So try using fixed values as TalusLength for now. Once you have all bones morphed - you can simply use identity matrix to redefine foot scaling function.

Kind regards,
Pavel

Hi Pavel I see, complex models require complicated solutions…

So I have been morphing the individual bones of the FreePostureGM model and nearly completed every bone in the foot. How would I start defining a matrix scaling function, is this similar to the process I have been following? If so is this essentially just combing the picked points on all the bones as one matrix?

Alternatively, Is there a way to scale a whole foot stl? I have been able to merge my individual segmented bones into one stl file see attached WholeModelMorphed.zip file - it’s not perfect, but shows you what i mean.

I appreciate your time and I understand these are not easy questions Pavel.
Kind Regards,
Zach

Hi Pavel I found a solution, but i’m not sure if it is appropriate.

In the Scaling folder in MoCap-GMFoot I have changed the points picked from the SkinLandmarks to random landmarks on the GM segments to corresponding points on my foot.

Scaling folder/ RBFLandmarks.any


....

AnyFolder MorphingLandmarks = {
  
  AnyFolder &SegRef = .....BodyModel.Right.Leg.Seg;
  
  
 
  
  //Matrix of the point cloud in foot ref frame.
  AnyMatrix MorpingPointCloud0 = 
  
  FunCEx("GMfoot_picked_points_25.pp", Main.FootPrintFolderPath +"/Scaling");
//  {
//    SegRef.Calcaneus.MorphingNode1.sRel,
//    SegRef.Talus.MorphingNode4b.sRel,
//    SegRef.Calcaneus.MorphingNode2.sRel,
//    SegRef.Calcaneus.MorphingNode3.sRel,
//    SegRef.Talus.MorphingNode1b.sRel,
//    SegRef.Talus.MorphingNode2b.sRel,
//    SegRef.Talus.MorphingNode3b.sRel,
//    SegRef.Navicular.MorphingNode2.sRel,
//    SegRef.Navicular.MorphingNode1.sRel,
//    SegRef.Metatarsal5.MorphingNode1.sRel,
//    SegRef.Metatarsal1.MorphingNode1.sRel,
//    SegRef.Metatarsal3.MorphingNode1.sRel,
//    SegRef.Talus.MorphingNode5b.sRel,
//    SegRef.DistalPhalange1.MorphingNode1.sRel,
//    SegRef.DistalPhalange2.MorphingNode1.sRel,
//    SegRef.DistalPhalange5.MorphingNode1.sRel
//  };

//{{-0.005, 0.115, -0.006}, 
//  {-0.028, 0.081, 0.003}, 
//  {-0.004, 0.078, -0.035}, 
//  {-0.005, 0.084, 0.034}, 
//  {0.044, 0.118, -0.008}, 
//  {0.068, 0.06, -0.038}, 
//  {0.055, 0.077, 0.035}, 
//  {0.029, 0.023, -0.032}, 
//  {0.06, 0.012, -0.002}, 
//  {-0.01, 0.012, 0.058}, 
//  {0.002, -0.063, -0.033}, 
//  {0.035, -0.027, 0.016}, 
//  {-0.018, -0.06, 0.015}, 
//  {0.003, -0.132, 0}, 
//  {-0.005, -0.124, 0.025}, 
//  {-0.012, -0.08, 0.065}};
  
  
  
  AnyInt Size = 26;
  AnyFunEx FunCEx = 
  {
    AnyMatrix Return = {iarr(1,.Size)*0,iarr(1,.Size)*0,iarr(1,.Size)*0}';
    AnyFunExMonoPy ReadMLFile =
    {
      ModuleFile = "ReadMeshlabIn.py";
      ArgList = 
      {
        AnyStringVar filename = "";
        AnyStringVar path = "";
      };
    };
  };
  AnyMatrix MorpingPointCloud1Millimeter =  FunCEx("MBFOOT5_picked_points_25.pp", Main.FootPrintFolderPath +"/Scaling");
  
  AnyMatrix MorpingPointCloud1 =  MorpingPointCloud1Millimeter*0.001;
  
  
};//MorphingLandmarks

Thanks,
Zach

Hi Zach,

Could you elaborate what you are trying to do and why? If you have all or almost bones in the foot morphed - why would you want to morph a rigid foot?

Thanks,
Pavel

I would still like to hear what you are trying to do.

Thanks,
Pavel

Hi Pavel, my main goal is to analyse kinematic differences (to start with) in the segments within the GM model between flat and high arched foot types that have been systematically described through a statistical shape model.
Regards,
Zach

So you want to scale all bones using the same transformation? All source bones are in the same ref. frame, and the target bones are too. Yes, that could work, but it will only change the shape of the bones, it might make things easier. Effectively, instead of having many different functions - you refer to the common foot morphing function. But you would need to have all CUSTOM_SCALING_… defines

You should be careful because this morphing does not necessarily transform joint nodes into patient-specific joint nodes. Possibly you could implement a some sort of calibration analysis, where you find patient-specific joint nodes.

I looked at the morphed foot - looks like a moprhed foot :slight_smile: Not sure how good it will be for your application. Just try.

Regards,
Pavel