Scale shoulder model

Hi everybody !
I’m working on scaling the shoulder model and would really need your help and advice.

To do it simple, I’m trying to morphe the anybody scapula and humerus on my own bones (reconstructed from CT-scans). I followed the tutorial “scaling” and in that sens I included custom scaling function for this two bones.

My custom scaling included :
1/ AnyFunTransform3DLin2 of 6 points to transform bone linearly
2/ AnyFunTransform3DRBF to scale them non linearly (38 points)
3/ AnyFunTransform3DSTL to a better fit of surfaces

You can find attached 2 screenshots of the two morphed bones.

My questions are the following :

  • for the 2 bones : how to well choose the corresponding point on the source and on the target ? My problem is that I think I don’t have enough point for a good scale if I only pick anatomical landmarks. So I’d like to pick other points but, to my mind, just picking them approximately is not accurate enough…

  • espacially for the scapula : on the screenshot you can see some dark parts (in particular on the infraspinatus and/or subscapularis fossea). It represents the fact that the mesh comes from one side to the other (e.g. mesh of the subscapularis fossea on the side of the supraspinatus fossea). According to me, the problem comes from the fact that the AnyFunTransform3DSTL algorithm computes a point to point (or point to surface ?) distance to make source and target fitting (right ??). Consequently, this part of bone being really thin, it results in mistakes. My question is so : would you have any idea on how to improve the accuracy ? Note that I already added lots of points without solving the problem and that this related to my first question : how to accurately pick the points on both the source and target bones ?

  • I only scaled the humerus and scapula and it resulted in some problems with other bones. For exemple at the elbow location, humerus and [ulna + radius] overlapped. Same between scapula and clavicula. Would it means that my linear transform is not accurate enough ??

Thank you in advance for your help !
Lauranne

Hi Lauranne,

  1. Well, there is no general safe rule - I typically try to match masses by picking corner landmarks and use obvious anatomic landmarks, which frequently go together.

  2. Yes, this is a difficult case. You are right - AnyFunTranform3DSTL uses the point-to-surface approach. This is why if two walls are close enough and a source point is between them - it might “shoot” to the other side. The initial registration is essential in that case. I would try to assess whether this is a sensitive area or not - try to visualize muscle attachment nodes and if they are not in the problematic area - it can be ignored.

Otherwise you might add landmarks to preserve masses by, for example, having matching flat triangular cylinders on both sides of source and target surfaces.

You could also try playing with/reducing number of points for your STL transform. - it will make the surface a little smoother and skip problematic place, but it also might solve the problem. As well as that you could try to switch on the PolynomDegree to 1 and try Triharmonic/Thin-Plate morphing schemes.

And again a good initial RBF registration should also solve the problem. I sometimes even stop at the RBF step, because it gives a good accuracy.

  1. Please check how the joint node is being morphed. It might be the extrapolative part that causes the problem. You could also include it in your landmark set if you could estimate/measure it by fitting geometric primitives.

Best regards,
Pavel

P.S. You mention only 3 transforms - please remember that you will need a reverse rigidbody transform to get back to the AnyBody reference frame for the sake of inertia and mass properties. It is described in the tutorial, but might not be highlighted well enough.

Hi Pavel,
Thank you really for your detailed answer !

  1. & 2. : I followed you advices about how to improve the scapula scale ; I thought it conducted to a pretty acceptable scale, by comparing nodes locations on the inital vs the target bones.

However, I’m unable to complete my analysis (abduction from 15° to 120° in the scapular plane). Please, note that I hadn’t any problems before scaling with this analysis.

The reported error relates to the AugLagCoef for the SP.Line infraspinatus 5 and 6. I had a look into the reference manual and, as proposed, augmented it for all infraspinatus fibers (SPLine.AugLagCoef = 100 000 rather than SPLine.AugLagCoef =1000 by default), but it did not solved the problem. I get exactly the same forces - kinematics - error at the same step.

I also get some warning during the inverse dynamic analysis related to these same fibers :

WARNING(OBJ1) :   D:/S..e/4..y/1..s/P..y/Body/A..n/Arm/Muscle.any(380)  :   infraspinatus_5.SPLine  :  Solver switched to fallback algorithm due to bad formed reduced system. If the computational speed appears to be too large consider to change to SPSolverFull.

Can you help me about this specific problem ?? What does this error mean ? What could I do to improve my model and avoid it ?

  1. I didn’t tried that for the moment because I’m not sure to understand the idea. Do you mean that adding an artificial landmark corresponding to the GH joint could force the humerus to have a better location relative to other bones ?
    Regarding the method, I’m not sure that it could be possible given that I only have cadavaer bones and consequently don’t know the “real” location of the joint… Or maybe would you have an idea about how to approximate it ??

Your P.S. : Yes, I did ; I just not mentioned because I assumed “normal” and necessary :wink:

Thanks again for all you advices !
Lauranne

Hi !
Still me :wink:

I would have a small update. I was interested in the muscles, since it seems being some problems with infraspinatus. It appears that some paths are really weird. For example the teres minor is over the deltoid (scapular part) when I scale the bones. Normally, TM should be under deltoid…

If I have a look on the “collum_hum_teres_minor” cylinder, used to construct the teres minor muscle, I can see that the cylinder does not have the same orientation than without scaling, i.e. the z-axis is no more following the humeral shaft axis. I don’t know what to think about that point and maybe could you help me ? Would it mean that my scale isn’t accurrate enough ?? Would you have any advice to improve the orientation / location of the cylinders ?

Best regards,
Lauranne

Hi Lauranne,

when you look at the construction of the cylinder you mentioned, you can see that the construction uses three scaled points. When the cyclinder changes the orientation, I would assume that the points changed places relative to each other. Since you are using nonlinear transformations, could it be that these points are too far away from the scaled surfaces so that the scaling of the points gets inaccurate?

About the warning you mentioned in the other post: in AMS 6.0 a new wrapping algorithm was introduced which gave a speed-up for the wrapping problem for most of the applications. In case this algorithm fails for some reason, a slower but more robust algorithm is used. This is what the message says.
To avoid this, you could try to reduce the size of the time-steps (if they are big) or you could try to increase the number of wrapping points for the muscle. But since there are problems with the wrapping surface, I would try to fix these first. It could be that the warning goes away then.

Best regards
Daniel

Hi Daniel,
Thank you for your explanations.

I think you’re right when assuming that the scale makes things wrong. In fact, when no scale, infraspinatus goes under the deltoid (scapular part). In case of scale, the infraspinatus goes over the deltoid. Moreover, the cylinder is really far away the humeral head center when it should not (see attached pictures).

However, I haven’t any idea on how to improve my scale in order to reduce the distance between humeral head and cylinder.

In fact my problem is that I don’t exactly understand how you constructed the cylinder. I know that it needs a ref frame for the origin and that the length is defined according to the z-axis of this ref frame. But how did you choose your points P2 and P3 ?? Other question why do not directly use the humeral head center to define the z-axis ?

To conclude, would you have any advice to improve my scale in order to decrease these problematic distances ??

Hello Lauranne,

I am sorry that I do not have a good answer to your questions about the construction.

As a quick fix, I can only offer you an alternative construction of the wrapping cylinder. It is based on 5 points chosen from joint center and muscle attachment points on the humerus, so it does not fit exactly, but gets into the same direction as the original one.

AnyRefNode collum_hum = {
      AnyMatrix HumerusWrapLandmarks = {
        {0,0,0},                       //gh node
        ({0.013072-.01, -0.331048 , -0.007917}+.OffSet )* .Mirror, //fe node
        ({ -0.004730, -0.136631 , 0.003461}+.correction+.OffSet) * .Mirror, // O_Triceps_LA_1 node
        ({0.006551, -0.256586 , 0.006249}+.Correction+.OffSet) * .Mirror, // O_BrachRad1 node
        ({0.002343+.xi, 0.021655+.yi , 0.016554+.zi}+.OffSet) * .Mirror // I_infraspinatus_3 node
      };
    AnyMatrix p = .Scale(HumerusWrapLandmarks);
    AnyDrawPointCloud drw2 = { Points = .HumerusWrapLandmarks; PointStyle.Style = PointStyleSphere ;RGB = {1,0,0};};
    AnyFloat lengthscalefactor = 1.4;
    AnyFloat radiusscalefactor = 1;

    AnyMat33 transform = RotMat(pi*(1-...Sign)*0.5, y);
    
    #include "../ToolBox/WrappingSurfaces/WrappingCylinder5PointFit.any"
    cyl = {
       AnyDrawParamSurf drw={RGB={1,0,0};};
    };
   AnySurfCylinder &collum_hum = cyl;
  };

Since it is a quick fix, it is not tested in detail if it always scales right and how it influences muscle forces. But maybe you could try if it fixes some of your issues about the scaling.

Best regards
Daniel

Hi Lauranne,

Sorry for late reply. Could you isolate your scaling to surfaces and share it with us to debug? I could have a look to suggest what can be done with the scaling. Otherwise Daniel suggested the most sensible way to construct the wrapping surface. Let us know if you still have the problem.

Regards,
Pavel

Hello !
First, I really would like to thank you for your time to help me !

Daniel, I tried to integrate your code into my model. However I get an error :

ERROR(SYS1) :   Model View Graph Creation  :  Unknown error
  Model view graph could not be created.
ERROR(SYS1) :   Model View Graph Creation  :  Unknown error
  Model view graph could not be created.
ERROR(SYS1) :   Model View Draw  :  Unknown error
  Model View failed to render scene.
ERROR(SYS1) :   Tooltip generation caused an error  :  Unknown error
  Model View Tooltip

This error was linked to the AnyDrawPointCloud function since I didn’t get it when commented. Would you have any idea about the reason of this error ?

Of what I saw, this way to define the collum_hum did not change the cylinder in terms of orientation/location/radius. Then I still get the same error when launching my analysis.

In an other side, I believe that I did a mistake when describing my problem: in fact the main problematic fibers are probably the Teres-Minor which go over the deltoid (see the pictures of my previous post). In that sense, I looked on the collum_hum_teres_minor. My question is why do not use the same cylinder than those used for the infraspinatus ? Anatomicaly couldn’t it make sense at least for the position and orientation of the cylinder ? It is what I tried but with a bigger radius (otherwise fibers went into the humerus…). However results of analysis are somehow weird. In fact and again, I believe my scale is not good enough, making strange thinks with muscles paths.

So, Pavel, as you proposed, I tried to isolate changed files for my scaling. I made a .zip file containing them in the appropriate folders compared with the AMMR v1.6. I’m not sure it’s the right way to proceed and hope it’ll be working for you. If something appears unclear, please, do not hesitate :wink:

Thank you again for everything.
Lauranne

Hi Lauranne,

just a quick reply to the first part of your message: The AnyDrawPointCloud causing the error message is not needed at all, so it is all right to out comment this line since it is not working in your version.

The fix I send was indeed for the wrong cylinder. In the unscaled version of the body model, the teres minor wrapping cylinder is a bit thicker than the fixed one. As a quick fix you could just use the new one, otherwise feel free to change the construction on the teres minor cylinder using five points on the humerus (I took two joint centers for the direction and 3 other (muscle attachment) points that were already defined on the humerus which were close to the bone surface and the unscaled wrapping cylinder. Official fixes for these cylinders will probably be one of the next releases.

Best regards
Daniel

Hi Lauranne,

I have also looked at the model and the morphing. The morphing was very good, except one thing - the extrapolative behaviour. We lately use thin-plate and triharmonic RBF functions for the morphing, since they provide a little bit more stable behaviour for the extrapolated points. Another thing that I added was the linear term of the transform that is also improving the behaviour:
RBF/STLTransform = {PolynomDegree = 1;RBFDef.Type = RBF_Triharmonic;};

But all in all this is how the morphing was supposed to be done in my vision :slight_smile:

These fixes should make morphing a little bit more robust when it comes to the 5points cylinder fit. And as Daniel said you may want to play a little to make this cylinder perfect.

Best regards,
Pavel

Hi !
Thank you for your both answers !

Regarding the problem for the cylinder of the teres minor, as proposed before, I used the collum_hum cylinder. It appeared the most stable and reproducible with scale without changing to many parameters.

Pavel, I really appreciate your time for looking on my model ! I’m pretty happy to know that I did my scale as I should :wink: I’m pretty surprised in fact because in your tutorial I had the feeling that only a few points were needed ; it’s really not my case, espacially for scapula.

As you adviced, I changed the RBF and STL transform function and, you’re right, the results make more sense. However, I don’t sure to understand the whole concept for extrapolating points. Of course I read the tutoriel + reference manual but what is unclear for me is the way it’s performed in Anybody.

Maybe the next question is linked : I observed that when using multiquad extrapolation the joint is very dislocated and far from the “initial” position ; It’s less the case with the Triharmonic function. My question is to know if I can used this visual position as an indicator to know if the scale is well performed ? I mean, should I have the same position of the joint than without scaling (i.e. than when using AnyBody “bones” without scale) ?

Regards,
Lauranne

Hi Lauranne,

I tried to visualize the part with the extrapolative behaviour in the tutorial by adding the AnyDrawPointCloud object. This way you can see the deformation field and understand how it works. It basically means that all nodes inside of the surface are being interpolated, whereas the nodes outside of the surface are being extrapolated. And those that are being extrapolated were the problem.

I know that AnyDrawPointCloud fails in your version of AMS, but maybe you could try creating a Matlab script that writes out something similar using regular AnyRefNode rfn = {… AnyDrawNode a={…};};

The benefit is that you see how the scaling works.

And regarding the DrawMeasurements - we do not have anything specific regarding the upper body. What you can is to copy the file from the StandingModelScalingDisplay and adjust it to your needs by removing missing drawing. Or you could alternatively create your own objects by reusing the code:

  AnyFolder Head ={
    AnyRefFrame &refframe1 = HUMAN_MODEL.Trunk.SegmentsThorax.SkullSeg.ChinBonyTip;
    AnyRefFrame &refframe2 = HUMAN_MODEL.Trunk.SegmentsThorax.SkullSeg.TopOfHead;
    AnyRefFrameAxis DirAxis= y;
    AnyVec3 Offset = {0.02, 0, 0};
    AnyStringVar Text = "Head";
    AnyVec3 RGB = DRAW_SETTINGS.Line.RGB;
    AnyVar Thickness = DRAW_SETTINGS.Line.Thickness;
    
    #include "<ANYBODY_PATH_BODY>/ToolBox/DimensionArrowWithText/DimensionLines.any"
    
    HUMAN_MODEL.Trunk.SegmentsThorax.SkullSeg.ChinBonyTip ={
      AnyDrawNode DrawNode = 
      {
        RGB = {1, 0, 0};
        ScaleXYZ = 0.3*{0.025, 0.025, 0.025};
      };
    };
    
    HUMAN_MODEL.Trunk.SegmentsThorax.SkullSeg.TopOfHead ={
      AnyDrawNode DrawNode = 
      {
        RGB = {1, 0, 0};
        ScaleXYZ = 0.3*{0.025, 0.025, 0.025};
      };
    };
    
  };

Hope that helps,
Pavel

Hi Pavel,
Thank you for your advices to see the extrapolating behaviour. I’ll try it soon.

Regarding the DrawMeasurements : in fact I tried to follow the tutorial and to launch the StandingModelScalingDisplay.Main in the 6.0.1 version; however I was unable to conclude because of this error :
ERROR(SCR.SCN10) : D:/D…s/B…y/A…6/A…n/E…s/S…y/M…l/DrawExternalMeasures.any(329) : ‘<BM_LEG_PATH>/NodeForScalingExt.any’ : Path definition does not exist.

Do you know anything about this problem ?? How to know the pointeed folder by the variable <BM_LEG_PATH> ?

Then I used the version 5.3 with the AMMR 1.5, what worked fine. My objective was to understand how you build the points for the DrawMeasurement. What is unclear is where these points are defined/created ?? I made right clic > Locate in Anyscript and found the files “NodeForScallingExt” but they are “not loaded”… Could you help me to clarify it, to be able reproduce it in my shoulder model ?

Really, thank you !
Lauranne

Hi Lauranne,

Thank you very much, you have found a bug. BM_LEG_PATH was there in one of the earlier version of AMMRv1.6, but eventually was removed. Not sure whether that was intentional or not, but for now the code should look like:


#if BM_LEG_LEFT == CONST_LEG_MODEL_Leg
HUMAN_MODEL.Left.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/Leg/NodeForScalingExt.any"};
#endif
#if BM_LEG_LEFT == CONST_LEG_MODEL_TLEM
HUMAN_MODEL.Left.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/LegTLEM/NodeForScalingExt.any"};
#endif
#if BM_LEG_RIGHT == CONST_LEG_MODEL_Leg
HUMAN_MODEL.Right.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/Leg/NodeForScalingExt.any"};
#endif
#if BM_LEG_RIGHT == CONST_LEG_MODEL_TLEM
HUMAN_MODEL.Right.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/LegTLEM/NodeForScalingExt.any"};
#endif

I also had to make a small change in the beginning of the file to make it work:
#define HUMAN_MODEL Main.HumanModel.BodyModel

The nodes where created to imitate the external measurements landmarks on the human. They are included when we use scaling based on external measurements.

I hope this fix will help.

Regards,
Pavel

Hi Pavel;

In regards to this thread:

When we update the code you have mentioned in your last post as:


//HUMAN_MODEL.Right.Leg.Seg = {#include "<BM_LEG_PATH>/NodeForScalingExt.any"};
//HUMAN_MODEL.Left.Leg.Seg = {#include "<BM_LEG_PATH>/NodeForScalingExt.any"};
#if BM_LEG_LEFT == CONST_LEG_MODEL_Leg
HUMAN_MODEL.Left.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/Leg/NodeForScalingExt.any"};
#endif
#if BM_LEG_LEFT == CONST_LEG_MODEL_TLEM
HUMAN_MODEL.Left.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/LegTLEM/NodeForScalingExt.any"};
#endif
#if BM_LEG_RIGHT == CONST_LEG_MODEL_Leg
HUMAN_MODEL.Right.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/Leg/NodeForScalingExt.any"};
#endif
#if BM_LEG_RIGHT == CONST_LEG_MODEL_TLEM
HUMAN_MODEL.Right.Leg.Seg = {#include "<ANYBODY_PATH_BODY>/LegTLEM/NodeForScalingExt.any"};
#endif

we still got an error message regarding the missing reference node for


AnyRefFrame &refframe1 = HUMAN_MODEL.Trunk.SegmentsThorax.SkullSeg.ChinBonyTip;

I checked AMMR 1.3.1 and 1.5 in addition to 1.6.3 but all seems to be missing this landmark point. Can you provide this landmark point or refer to an older AMMR where it was alive?

I suspect this measurement of chin to topofhead does not affect any scaling, any thoughts?

Best…

Can

Hi Can,

I found one instance in AMMRv1.2


  AnyRefNode ChinBonyTip ={
    sRel = .Scale({0.10, -0.11, 0.0});
    ARel = RotMat(-0.04,z);
  };

And no, most likely it does not affect the scaling.

Regards,
Pavel