Download Bart Coppieters Automatic feature extraction of 3D anatomic data.

Document related concepts
Transcript
Automatic feature extraction of 3D anatomic data.
Bart Coppieters
Promotoren: prof. dr. ir. Benedict Verhegghe, prof. dr. Katharina D'Herde
Begeleiders: Germano Gomes, Peter Mortier
Scriptie ingediend tot het behalen van de academische graad van
Burgerlijk ingenieur in de computerwetenschappen
Vakgroep Mechanische constructie en productie
Voorzitter: prof. dr. ir. Joris Degrieck
Vakgroep Anatomie, embryologie, histologie en medische fysica
Voorzitter: prof. dr. Hubert Thierens
Faculteit Ingenieurswetenschappen
Academiejaar 2007-2008
Forewords
My special thanks go out to Germano Gomes. Without his appreciated guidance
throughout this academic year my work would not have been like it is up to date. In the
hours we spent together behind his desk many ideas critical for the success of my work
originated. Also I would like to thank my promoters for the chance they gave to make a
study about this subject.
Furthermore I would like to thank my parents, not only for this year, but for all the years
that I got the opportunity to study and to grow as a person.
At last I dedicate words of thankfulness to my girlfriend, Vanesa, and my friends who
were important to me for keeping me motivated and just for all the wonderful moments
the past few years.
Bart Coppieters, June 1st 2008
Toelating tot bruikleen
"De auteur geeft de toelating deze masterproef voor consultatie beschikbaar te stellen
en delen van de masterproef te kopiëren voor persoonlijk gebruik.
Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met
betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van
resultaten uit deze masterproef."
Permission for usage
"The author gives the permission to make this thesis available for consultation and to
copy parts of this thesis for personal use.
Any other use is subject to the limitations of copyright, particularly with regard to the
obligation to specify the source when quoting results from this thesis."
Bart Coppieters, June 1st 2008
2
Automatic feature extraction of 3D anatomic data.
Bart Coppieters
Scriptie ingediend tot het behalen van de academische graad van
Burgerlijk ingenieur in de computerwetenschappen
Academiejaar 2007-2008
Promotoren: prof. dr. ir. Benedict Verhegghe, prof. dr. Katharina D'Herde
Begeleiders: Germano Gomes, Peter Mortier
Vakgroep Mechanische constructie en productie
Voorzitter: prof. dr. ir. Joris Degrieck
Vakgroep Anatomie, embryologie, histologie en medische fysica
Voorzitter: prof. dr. Hubert Thierens
Faculteit Ingenieurswetenschappen
Summary
The objective of this work is the development of a tool with Matlab® with which virtual
palpation can be done in an automatic way. Virtual palpation comes down to locating
predefined features in 3D models of the human skeletal system. In this work we have
focused on the extraction of features of the upper limb bones: the humerus, the
scapula, the clavicle, the ulna and the radius. User interaction has to be limited to a
minimum in order to make the feature extraction an autonomic procedure.
Keywords
Matlab®, GUI, automatic feature extraction, anatomy
3
Table of contents
Chapter 1
Introduction............................................................................................. 1
Chapter 2 The anatomy of the upper limb bones .................................................. 4
2.1
Humerus .......................................................................................................... 5
2.1.1 Upper End...................................................................................................... 5
2.1.2 The Body or Shaft of the humerus ................................................................. 6
2.1.3 The Lower End .............................................................................................. 7
2.2
The Scapula .................................................................................................... 7
2.2.1 Surfaces......................................................................................................... 8
2.2.2 Borders .......................................................................................................... 8
2.2.3 Angles............................................................................................................ 9
2.3
Clavicle ............................................................................................................ 9
2.3.1 Lateral Third................................................................................................. 10
2.3.2 Medial Two-thirds......................................................................................... 10
2.4
Ulna ............................................................................................................... 11
2.4.1 The Upper End ............................................................................................ 11
2.4.2 The Body or Shaft ........................................................................................ 11
2.4.3 The Lower End ............................................................................................ 12
2.5
Radius ........................................................................................................... 12
2.5.1 The Upper End ............................................................................................ 12
2.5.2 The Body ..................................................................................................... 13
2.5.3 The Lower End ............................................................................................ 13
2.6
Features to be extracted................................................................................ 14
Chapter 3 The graphical user interface (GUI) ...................................................... 15
3.1
Step by step explanation of the use of the GUI ............................................. 16
3.1.1 Make the GUI visible.................................................................................. 16
3.1.2 Read in a 3D model of a bone ................................................................... 18
3.1.3 Do all the critical procedures for the selected bone ................................... 19
3.1.4 Feature visualization and curvature calculation ......................................... 21
3.1.5 Reset the GUI to its initial state.................................................................. 23
3.2 A comparison between Stl files and patch objects ........................................... 24
3.3 Bone-specific coordinate systems .................................................................... 26
3.3.1 Humerus .................................................................................................... 27
3.3.2 Scapula...................................................................................................... 28
3.3.3 Clavicle ...................................................................................................... 29
3.3.4 Ulna ........................................................................................................... 30
3.3.5 Radius........................................................................................................ 31
Chapter 4 The humerus ......................................................................................... 33
4.1
The orientation of the humerus...................................................................... 35
4.2
Extraction of the lateral and the medial epicondyle ....................................... 46
4.3
Extraction of the head of the humerus ........................................................... 47
4.4
Extraction of the greater tubercle................................................................... 53
4.5
4.6
4.7
4.8
4.9
Extraction of the lesser tubercle .................................................................... 57
Extraction of the trochlea ............................................................................... 60
Extraction of the capitulum ............................................................................ 63
Extraction of the topmost point of the humerus ............................................. 65
Extraction of the metaphyseal cylinder .......................................................... 65
Chapter 5 The scapula........................................................................................... 70
5.1
The orientation of the scapula ....................................................................... 71
5.2
Extraction of the inferior angle ....................................................................... 80
5.3
Extraction of the superior angle ..................................................................... 80
5.4
Extraction of the tip of the acromion .............................................................. 83
5.5
Extraction of the acromial angle .................................................................... 87
5.6
Extraction of the tip of the coracoid process .................................................. 91
5.7
Extraction of the root of the spine .................................................................. 94
5.8
Extraction of the glenoid cavity ...................................................................... 98
Chapter 6 The clavicle ......................................................................................... 102
6.1
The orientation of the clavicle...................................................................... 102
6.2
Extraction of the anterior sternoclavicular joint ............................................ 110
6.3
Extraction of the posterior acromioclavicular joint........................................ 111
Chapter 7 The ulna............................................................................................... 112
7.1
The orientation of the ulna ........................................................................... 113
7.2
Extraction of the apex of the olecranon ....................................................... 120
7.3
Extraction of the coronoid process .............................................................. 121
7.4
Extraction of the styloid process .................................................................. 123
7.5
Extraction of the ulnar head......................................................................... 123
Chapter 8 The radius ........................................................................................... 127
8.1
The orientation of the radius ........................................................................ 127
8.2
Extraction of the radial head ........................................................................ 135
8.3
Extraction of the radial head periphery ........................................................ 138
8.4
Extraction of the styloid process .................................................................. 140
Chapter 9 Results ................................................................................................ 142
9.1
Visualization ................................................................................................ 142
9.2
V-Palp.......................................................................................................... 148
9.3
Manual......................................................................................................... 149
9.4
Results......................................................................................................... 150
Chapter 10 Conclusion .......................................................................................... 155
Appendix A: Anatomical Nomenclature................................................................. 157
Appendix B: Matlab® code ..................................................................................... 158
B.1 The GUI and functions ................................................................................. 159
2
B.2
B.3
B.4
B.5
B.6
B.7
Humerus ..................................................................................................... 167
Scapula........................................................................................................ 183
Clavicle ........................................................................................................ 198
Ulna ............................................................................................................. 203
Radius ......................................................................................................... 210
General functions ......................................................................................... 218
Appendix C: The Stl format..................................................................................... 222
C.1 Format Specifications ...................................................................................... 222
C.2 Format Specifications ...................................................................................... 223
Appendix D: Curvature ............................................................................................ 225
D.1 Matlab implementation..................................................................................... 225
Bibliography ............................................................................................................. 235
3
Chapter 1
Introduction
Clinical studies and orthopedic operative actions produce a huge amount of medical
image content, such as x-rays, digital scans, ct scans, … Usually all these images are
stocked in very large databases which makes a scientific analysis of these images a
very time consuming task. For example, it would be difficult to carry out the
measurement of the length of the clavicle for classification purposes. First the image,
for example an x-ray, has to be retrieved from the database and subsequently a
manual measurement of the length has to be done. The fact the procedure is carried
out by a human person increases the probability of inter-observer errors throughout the
measuring. Therefore it should be made possible to carry out some analyses in an
automatic manner.
The above justified our search for an automatic way in discovering predefined
anatomical landmarks of the human body in medical images. With automatic is meant
that the whole procedure of getting those established points of the body, is done
without the interaction of a human person.
The search for landmarks on medical images is also referred to as virtual palpation [1].
It is used mainly to quantify individual morphologic parameters from medical imaging:
- Limb length
- Limb orientation
- Joint angle
- Distance between various skeletal locations.
In combination with the results of a manual palpation process, where the medical
images are replaced by the real human specimen, supplementary complex analyses
can be undertaken:
- Accurate modeling of joint kinematics during musculoskeletal analysis
- Precise alignment of orthopedic tools according to the individual anatomy of a patient.
1
With this said, a framework is sketched of which the real objective of our work will be a
part.
The idea is to design a tool in the programming environment of Matlab® with which
users can locate in an automatic manner the position of predefined features of a
determined set of bones.
As virtual palpation assumes the interaction of the healthcare professional with the
medical images to localize the wanted features, reproducibility of these extracted
positions is not a certainty. Another person working with the same images will probably
get other results although their intention is the same.
Our goal is to develop a tool that will operate as a black box and that will produce for a
given input bone always the same output.
The input are 3D bone models of:
-Humerus
-Scapula
-Clavicle
-Ulna
-Radius.
All these bones belong to the upper extremity of the human body. In Chapter 2 their
anatomical properties are briefly described.
With features we mean the representations of specific locations (landmark) of a bone.
For example if a structure of a bone must be extracted that has a shape like a sphere,
the feature associated with it would be the specification of the sphere, in this case the
sphere’s center and radius. In the end of Chapter 2 a list of all the extracted features for
each bone is given.
The tool has a simple front end graphical user interface (GUI) that will allow the user to
determine the bone and the feature of the bone he or she is interested in. In Chapter 3
the layout and the functionality of the GUI is described and explained.
2
Selecting the bone is the only user interaction that can be done as the algorithms that
run the extraction of the features, are carried out automatically without any help of the
user. There is no need to give in parameters or to select points onto the surface of the
3D model. Every single feature extraction will operate completely and successfully on
its own. Though the results are dependent on the quality of the input data.
Chapters 4 to 8 give for each bone an extensive explanation of the functions that were
used to estimate the desired features of it.
Chapter 9 gives a brief summary of the results that we achieved. Despite the absence
of an extensive amount of reference data, this concluding chapter will clearly
demonstrate the capabilities of the program.
In the final chapter critical remarks are given.
3
Chapter 2
The anatomy of the upper limb bones
In this chapter is briefly talked about the anatomical properties exhibited by each bone
that will be processed throughout the rest of this work. The following image will make
clear which bones will play a central role. These bones are, as can be seen on Figure
2.1, all located in the upper part of the human body.
3
2
1. Humerus
1
2. Scapula
3. Clavicle
4. Ulna
5. Radius
4
5
Figure 2.1
This chapter serves solely as an introduction to the anatomy for those readers who are
not familiar with it. It is not our intention to do an extensive study of the anatomy of the
bones of interest as this can be found in any anatomy reference book such as ([2], [3],
[4]). Each of the bones of Figure 2.1 will be explained from an anatomical point of view,
but only with respect to our work. The content of this chapter is based on [4].
At the end of the chapter, after the anatomy is more or less clear, a table will clarify
which features of which bones are being extracted.
4
In Appendix A the anatomy-specific terms that are used, are explained. These will be
used frequently, not only in this chapter but also in the chapters to come.
2.1
Humerus
The humerus is the longest and largest bone of the upper extremity. It fits between the
scapula and the clavicle above and the ulna and the radius below. It is divisible into a
body and two epiphysis, the upper and the lower end.
2.1.1 Upper End (Figure 2.2)
The upper end consists of a large rounded head (a). Furthermore it consists of two
eminences, the greater (d) and lesser (e) tubercles. These give attachment for shoulder
muscles.
Figure 2.2: Anterior aspect of left humerus, the upper end.
The head (a), hemispherical of shape, is directed upward, medialward, and a little
backward, and articulates with the glenoid cavity of the scapula. Its circumference is
termed the anatomical neck (b). Below the tubercles is another constriction, called the
surgical neck (c). The greater tubercle (d) is situated lateral to the head and lesser
tubercle (e). The lateral surface of the greater tubercle is convex, rough, and
continuous with the lateral surface of the body of the humerus.
The lesser tubercle (e), although smaller, is more prominent than the greater: it is
situated in front, and is directed medialward.
5
The tubercles are separated by a deep groove, the intertubercular groove (f).
2.1.2 The Body or Shaft of the humerus (Figure 2.3)
The body of the humerus can be seen as cylindrical in its upper half and below it has
less or more a prismatic shape. Therefore one can distinct three borders and three
surfaces.
Figure 2.3: Anterior (left) and posterior (right) aspect of left humerus.
The anterior border runs from the front of the greater tubercle to the coronoid fossa
below. About its center it forms the anterior boundary of the deltoid tuberosity (h).
The lateral border runs from the back part of the greater tubercle to the lateral
epicondyle (i). Its center is traversed by a broad but shallow oblique depression, the
radial sulcus (j).
The medial border runs from the lesser tubercle to the medial epicondyle (k).
6
2.1.3 The Lower End (Figure 2.4)
The lower end terminates below in a broad, articular surface, which is divided into two
parts by a slight ridge. Extending on either side are the lateral and medial epicondyles
(i and k).
The lateral portion of this surface consists of a smooth, rounded eminence, named the
capitulum (l) of the humerus. It is only present on the front part of the bone. This
elevation articulates with the head of the radius. Above the front part of the capitulum is
a slight depression, the radial fossa (m).
The medial portion of the articular surface is named the trochlea (n), and presents a
deep depression between two well-marked borders.
Figure 2.4: Lower end of left humerus. Anterior aspect (left) and posterior aspect (right).
Above the front part of the trochlea (n) is a small depression, the coronoid fossa (g),
which receives the coronoid process of the ulna during flexion of the forearm. Above
the back part of the trochlea (n) is a deep triangular depression, the olecranon fossa
(o), in which the summit of the olecranon of the ulna is received in extension of the
forearm. The epicondyles are continuous above with the supracondylar ridges (p =
lateral, q = medial).
2.2
The Scapula
The scapula forms the posterior part of the shoulder girdle. It is a flat, somewhat
triangular bone, with two surfaces, three borders, and three angles.
7
2.2.1 Surfaces
Because of its flat structure the scapula has two main surfaces: the costal or ventral
surface and the dorsal surface.
The costal surface (Figure 2.5, left) presents a broad concavity, the subscapular fossa
(a).
The dorsal surface (Figure 2.5, right) is arched from above downward and is subdivided
by a bony projection, the spine of the scapula (c), into the supraspinatus fossa (d) and
the infraspinatus fossa (e).
Figure 2.5: Left: Costal aspect of left scapula. Right : Dorsal aspect of left scapula.
The spine of the scapula gradually becomes more elevated until it runs into a forward
pointing hook called acromion (b). The acromion, on its own right, forms the top of the
shoulder. It overhangs the glenoid cavity (f). In the center of its medial border it
articulates with the acromial end of the clavicle.
2.2.2 Borders
The scapula has three borders: the superior border (A), the lateral border (B) and the
medial border (C).
8
2.2.3 Angles
There are also three angles: the superior angle (D), the inferior angle (E) and the lateral
angle(F). Situated on the lateral angle is the glenoid cavity (f). This is a shallow articular
surface which is directed lateralward and forward and articulates with the head of the
humerus. The part below is broader than the part above and its vertical diameter is the
longest. Below the glenoid cavity is the infraglenoid tuberosity (i) situated. At its summit
is a little elevation, the supraglenoid tuberosity (j).
Figure 2.6: Lateral aspect of left scapula.
The last significant structure associated with the scapula is the coracoid process (g). It
is a thick process attached by a broad base to the upper part of the neck of the scapula
(k)..
2.3
Clavicle
The clavicle is a long bone that connects the arm to the body. It is placed nearly
horizontally at the upper and anterior part of the thorax, immediately above the first rib.
It articulates on its medial end with the sternum, and laterally with the acromion of the
scapula.
9
It presents a double curvature, with the convexity being directed forward at the sternal
end (a), and the concavity at the acromial end (b). Its lateral third is flattened from
above downward, while its medial two-thirds is of a pyramidal form.
Figure 2.7: Superior aspect of left clavicle.
2.3.1 Lateral Third (Figure 2.7 and 2.8 at the right side)
The lateral third has two surfaces, an upper and a lower; and two borders, an anterior
and a posterior.
At the posterior border of its inferior surface is a rough eminence, the conoid tubercle
(c). From this tuberosity an oblique ridge, the trapezoid ridge (d), runs forward and
lateralward, and affords attachment to the trapezoid ligament.
Figure 2.8: Inferior aspect of left clavicle.
2.3.2 Medial Two-thirds (Figure 2.7 and 2.8 at the left side)
The medial two-thirds are made up by the prismatic portion of the bone, which is
curved in a convex manner in front and in a concave manner behind.
10
On the medial part of its inferior surface is a broad rough surface, the costal tuberosity
(e).
2.4
Ulna
The ulna is a long bone, prismatic in form, situated at the medial side of the forearm
between the humerus above and the hand below. It is therefore parallel with the radius.
It is divisible into a body and two end parts. Its upper end, of great thickness and
strength, forms a large part of the elbow-joint. The bone diminishes in size from above
downward. At its smaller lower end there is a connection to the hand by the wrist joint.
2.4.1 The Upper End (Figure 2.9)
The upper end presents two curved processes, the olecranon (a) and the coronoid
process (c). It has also two concave, articular cavities, the semilunar (b) and radial
notches (d).
Figure 2.9: Upper end of left ulna. Anterior aspect.
2.4.2 The Body or Shaft
The body at its upper part is prismatic in form; its central part is straight; its lower part is
rounded, smooth, and bent a little lateralward. It has three borders in the longitudinal
direction and thus 3 surfaces.
11
2.4.3 The Lower End (Figure 2.10)
The lower end of the ulna is small, and presents two eminences. The lateral and larger
is rounded and plays a role in articulation. It is termed the head of the ulna (e). The
medial, narrower and more projecting, is a non-articular eminence, termed the styloid
process (f). The styloid process descends a little lower than the head.
Figure 2.10: The left ulna. Antero-lateral aspect.
2.5
Radius
The radius is, just like the ulna, a bone present in the forearm. More specified it is
situated on the lateral side of the ulna. It has a body and two ends. Its upper end is
small, and forms only a small part of the elbow-joint. On the contrary, its lower end is
large, and forms the main part of the wrist-joint.
It is a long bone, prismatic in form and slightly curved longitudinally.
2.5.1 The Upper End (Figure 2.11)
The upper end presents a head, neck, and tuberosity. The head (a) is of a cylindrical
shape. On its upper surface is a shallow cup (b) for articulation with the capitulum of
the humerus. The head is supported on a round, smooth, and constricted portion called
the neck (c). Beneath the neck, on the medial side, is a prominent eminence, the radial
tuberosity (d).
12
Figure 2.11: Left radius. Anterior view of the upper end.
2.5.2 The Body (Figure 2.12)
The body is narrower above than below and slightly curved, so as to be convex
lateralward. It presents three borders and hence three surfaces.
Figure 2.12: Left radius: upper end, shaft and lower end.
2.5.3 The Lower End (Figure 2.13)
The lower end is large, of quadrilateral form, and has two articular surfaces: one below,
for the carpus (the cluster of bones in the hand between the radius and ulna and the
metacarpus), and another at the medial side, for the ulna. The carpal articular surface
is triangular of shape and is divided in two parts. The lateral, triangular (e), articulates
with the scaphoid bone (hand bone of the carpus). The medial, quadrilateral part (f)
articulates with the lunate bone (hand bone of carpus).
The articular surface for the ulna is called the ulnar notch of the radius (g). It articulates
with the head of the ulna.
13
This lower end of the bone has three non-articular surfaces: volar, dorsal, and lateral.
The lateral surface runs obliquely downward into a strong, conical projection, the styloid
process (h).
Figure 2.13: Left radius. Anterior view of the lower end.
2.6
Features to be extracted
The following table gives an overview of the main features to be extracted automatically
by the tool. The significance of each of these can be found in the papers under column
‘References’.
Bones
Features
Humerus Lateral epicondyle. Medial epicondyle. Head. Lesser tubercle.
References
Greater tubercle. Trochlea. Capitulum. Topmost point. Metaphyseal
cylinder.
Scapula
Inferior angle. Superior angle. Acromial Tip. Acromial angle.
Tip of coracoid process. Root of the spine. Glenoid cavity.
Clavicle
Ulna
Anterior sternoclavicular joint. Posterior acromioclavicular joint.
[1],[8],[9],[10],[11]
[1],[11]
Apex of the olecranon. Coronoid process. Styloid process.
Ulnar head.
Radius
[1],[5],[6],[7],[11]
Radial head. Radial head periphery. Styloid process.
[1],[11]
[1],[11]
14
Chapter 3
The graphical user interface (GUI)
A graphical user interface (GUI) is a graphical display that contains devices, or
components, that enable a user to perform interactive tasks. To perform these tasks,
the user of the GUI does not have to create a script or type commands at the command
line. Often, the user does not have to know the details of the task at hand.
In this chapter the developed Graphical User Interface (GUI) is described and
explained. Not only the layout is discussed, but also the functionality associated with
each component in the GUI will have its explanation.
The development environment used for making the GUI and all of its associated
functions is Matlab®. In Matlab® there is a specialized graphical user interface
development environment available that provides a set of tools for creating GUIs,
GUIDE. These tools simplify the process of laying out and programming GUIs.
First of all the layout of the GUI can be set by just populating it with GUI components
(such as buttons, panels, radio buttons,…). This population process is done in the
GUIDE layout editor and is based on clicking and dragging the needed component into
the layout area. Subsequently when you save your GUI layout, GUIDE automatically
generates a Matlab-file (M-file) that you can use to control how the GUI works. This Mfile provides code to initialize the GUI and contains a framework for the GUI callbacks;
the routines that execute in response to user-generated events such as a mouse click.
Using the standard Matlab-file editor, you can add code to the callbacks to perform the
functions you want.
Section 3.1 will go step by step through the use of the GUI as experienced by the user.
The readers that are interested in the Matlab® code that is responsible for the behavior
of the GUI are referred to Appendix B.1. In the appendix remarks are given to clarify
the code.
15
3.1
Step by step explanation of the use of the GUI
In this section we will give for each possibility to interact with the GUI the functional
consequences of this interaction. Every step will be accompanied with a screenshot of
the GUI on that given moment for clarification.
In the development process of the GUI, we took the ease of usability as a starting point.
Therefore the GUI is constructed in such a manner that it takes away the possibility of
making mistakes while working with it. Each step in interacting with the GUI will be selfexplanatory. This will be clear after reading this chapter.
3.1.1 Make the GUI visible
The origin of the visible GUI is the layout of the GUI. This is at all times available for
alteration in the GUIDE layout editor. In Figure 3.1 the eventual layout of our tool is
depicted in the GUIDE layout editor.
Figure 3.1 depicts a set of buttons, panes, radiobuttons, popupmenus and editable text.
These will be visible for the user dependent on his interactions with the GUI.
In order to work with the GUI, it has to be started up. This is done by running the M-file
that contains the underlying Matlab® code of the GUI. This file is originally created
when the GUI layout is saved for the first time.
Starting up this file will first carry out the initialization function that will define the initial
look and feel of the GUI that will be visualized. In this function parameters can be set,
components can be made invisible, files can be loaded… In Figure 3.1 it can be seen
that the components are distributed over the editor space on top of each other. If
beginning to work with the tool, the user must not see all these components, therefore
in our initialization function, all the components, except 1 button, are made invisible.
The first GUI visualization accessible for the user is depicted in Figure 3.2.
16
Figure 3.1: The layout of our GUI
Figure 3.2
17
3.1.2 Read in a 3D model of a bone
As seen in Figure 3.2 the only possible interaction is pushing the button ‘Read in 3D
bone model’. Clicking this button will execute the callback associated to it,
pushOpen_Callback. Basically this will launch a standard dialog box for retrieving the
files that correspond to 3D models of the bones. In Figure 3.3 the illustration is given.
Figure 3.3
We have worked with 3D models represented by binary Stl files.
An StL (“StereoLithography”) file is a triangular representation of a 3-dimensional
surface geometry. The surface is broken down logically into a series of small triangles
(facets). Each facet is described by a perpendicular direction and three points
representing the vertices (corners) of the triangle. More information about the Stl format
can be found in Appendix C.
After the user has picked an Stl file, it will be read in. The format to which the data in
the file will be transformed is a graphics object, patch, that is inherent to Matlab®. A
discussion about the difference between the Stl file and the patch object representation
is given in section 3.2. Important for now is that we have the representation of the 3D
model of a bone at our disposal. This information will be saved so it can be handed
18
over to other callbacks that will execute the feature extraction processes for the read in
bone. Subsequently a panel becomes visible. A panel is nothing more than a container
component to unite a set of components. This panel contains 5 radiobuttons that
correspond to the 5 bones that are studied. Figure 3.4 represents the current state of
the GUI.
Figure 3.4
In the continuation of this section we will work with an arbitrarily chosen 3D model of a
humerus. The subsequent actions taken and explanations given can be generalized to
the 3D models of the other bones (scapula, clavicle, radius, ulna).
3.1.3 Do all the critical procedures for the selected bone
The user must specify the bone of which he just has read in a 3D model. If the read 3D
model is a scapula, the user will have to click the radiobutton ‘Scapula’.
The callback corresponding to the radiobutton is the logical heart of the GUI. In this
routine all the processes responsible for extracting all the features of a given bone are
carried out.
The following flowchart gives the sequence of routines if a radiobutton associated with
a bone is selected.
19
Orient the
bone
Extract all the
bone’s
features
Visualize the bone
(only the bone not
the features)
In the following 5 chapters the functions responsible for the first 2 actions, orienting and
extracting, are discussed in detail. A chapter is dedicated to each bone because this is
where the most work and complexity is found.
The last visualization step of this callback is for each type of bone the same. The output
bone of the 2 previous actions is always a right sided one. This choice was made for
ease of locating the features. More information about this issue is given in the following
chapters that are dedicated to each processed type of bone.
If the input bone was a left sided one, we want it to be visualized as a left sided one.
Thus a reverse transformation from the right sided counterpart (as used in the
extraction procedures) to its original left side is done first. The transformation to do this
changing of sides is a standard mirror transformation with respect to the y-z plane.
The features that were extracted have also positions that are defined with respect to
the right bone. So in case of a left bone, the extracted features have to be mirrored in
the same way as the bone.
For now only the bone will be visualized, the features are visualized in a later step. This
visualization of the bone happens in a newly opened window which only contains an
axis for drawing the 3D model of the oriented bone.
Apart from the callback that is executed by clicking the radiobutton, the look of the GUI
will be changed. This will give the user options to interact again with the GUI to
complete his objective. Figure 3.5 gives the reached state of the GUI.
First of all the radiobuttons panel ‘Bones’ is removed from the GUI. By doing so, the
user can not click again on another radiobutton This would carry out the functional
processes associated with another bone type and hence it will produce faulty results.
Secondly 2 panels become visible: a panel with the extractable features of the selected
20
bone (Figure 3.5, a) and a panel that will give the user the opportunity to calculate the
curvature of the bone (Figure 3.5, b). The panel represented by a comes accompanied
with 2 panels that will hold the coordinates of the extracted features. In 3.3 will be
elaborated on the two types of coordinates.
b
c
a
e
d
Figure 3.5
On the right side of figure 3.5 the bone is showed. It is drawn in the normal Cartesian
reference system representing 3D space. Visualizing the bone includes implicitly also
showing the 3 blue arrows (Figure 3.5, c). They are calculated to form another, bonespecific reference system as defined in [11]. In section 3.3 the functions for forming
those reference systems are outlined and discussed.
The bone is now depicted in 2 reference systems, a global one, the Cartesian system,
and a local one, the bone-specific system. Therefore there are 2 panels to display the
position of the features in both reference systems. These panels are shown in Figure
3.5 as respectively d and e.
3.1.4 Feature visualization and curvature calculation
In the GUI as shown in Figure 3.5 the user can undertake two actions: selecting
features of the processed bone or calculate the bone’s curvature.
21
3.1.4.1 Feature visualization
All the features of the selected bone are contained in the feature panel (Figure 3.5, a).
When the user clicks a radiobutton associated with a feature, the feature will be
depicted onto the 3D model of the bone. Besides that, the coordinates of its position
are shown in d and e of Figure 3.5. If the feature consists of visualizing a geometrical
shape, all the parameters for drawing this geometric shape will be displayed in the
reference system panels. For example the feature ‘Center of head’ is represented by a
sphere and therefore its center and radius are given.
The user can select a random selection of features to be visualized together. It is also
possible to deselect a feature. This corresponds to deleting the visualization of the
feature from the 3D model of the bone. Figure 3.6 gives a possible current look for the
GUI.
Figure 3.6
3.1.4.2 Mean curvature calculation
This can be done by manipulating b in Figure 3.5. This panel contains a popupmenu
with which the user can specify with which neighborhood the mean curvature
calculation has to be done. Through the calculation each point of the 3D model gets a
value which represents its mean curvature. This is a measure of extrinsic curvature of a
22
surface. Regions of the model that exhibit convexity have negative mean curvature
values, concave regions will have positive values of mean curvature.
The outcome of this interaction is a second window which will hold the 3D model
depicted in function of the mean curvature information. Figure 3.7 illustrates this frame.
Figure 3.7
The algorithm to do the curvature calculation is outlined in [12]. Our Matlab®
implementation of the algorithm is outlined in Appendix D.
3.1.5 Reset the GUI to its initial state
Once the user has terminated his processing of a bone and he wants to start with a
new one, the GUI has to be reset to its initial state as in Figure 3.2. This can be
achieved in three ways.
Or you can push the button ‘Read in 3D model’, or you can close the window where the
3D model is depicted, or you can close the frame where the 3D model’s curvature is
shown (if this frame is visible).
23
3.2 A comparison between Stl files and patch objects
The starting point of all the processing is reading in an Stl file. This is done by the
following statement.
[x,y,z,n] = stlread(‘filename.stl’);
The Stl file, ‘filename.stl’ describes a triangular mesh. This is a 3D model constructed
by connected triangles.
The output of the function is a patch object defined by the matrices x, y and z. x, y and
z are 3-by-N matrices that together represent the patch object. Together with this patch
representation of the 3D model stlread outputs n, a 3-by-N matrix containing in its
columns the normalized normals to the facets (triangles) of the 3D model. This will be
of importance for the mean curvature calculation. But the emphasis lies for now on x, y
and z.
A patch object is a graphics object recognized by Matlab®. It is one or more polygons
defined by the coordinates of its vertices. In this case the polygons are triangles.
Therefore the 3 matrices have sizes 3-by-N, where N is the number of facets
(triangles). Thus each column of the 3 matrices represents a facet. For example: the
first column of matrix x represents the 3 x-coordinates of the 3 vertices of the facet
associated with the first column. The first column of matrix y holds the 3 y-coordinates
of the vertices of the same facet. And finally matrix z does the same, but for the zcoordinates. To make it more clear: if we make a new 3-by-3 matrix with as the first
column the m-th column of x, as the second column the m-th column of y and as the
third column the m-th column of z, we get all the coordinates of the 3 vertices of the mth facet of the model.
In Figure 3.9 an illustration is given to clarify the use of the 3 matrices x, y and z.
24
Matrix z
v2
z3
y3
v1
Matrix y
v3
x3
Matrix x
Figure 3.9: A random facet of which vertex v3 has coordinates x3, y3, z3.
The 3 matrices x, y and z will be given as input arguments to the Matlab® function
patch which will draw the 3D model in space.
As x, y and z are useful for drawing; they are not for processing because they are 3.
Therefore it is rewarding in some situations to transform the 3 matrices to one M-by-3
matrix, which will hold in each row the x-, y- and z-coordinates of one vertex of the
model. The technique to do this transformation is self-explanatory and is based on
matrix procedures.
An attentive reader will ask himself questions about the transformation of 3 3-by-N
matrices to 1 M-by-3 matrix. Why do we go from N to M, with M<N? This is due to the
fact that in the original matrices every vertex is represented several more times
because each vertex belongs theoretically to more than one facet. And each column
represents a facet in these matrices, so the same vertex will appear in several
columns. Part of the transformation to one matrix is discarding these ‘redundant’
vertices. Speaking of redundant vertices is theoretically incorrect. They do add
information to the data. Precisely because of the repeated occurrences of all vertices in
the representation of the patch object, it is possible to determine the triangles. This on
its turn holds information about which points are connected with which other points. So
indirectly it holds the connectivity information of the binary Stl file.
25
For a lot of procedures the connectivity is not needed and therefore we downscale the
3 matrices to 1 matrix. On the other hand, for other procedures, for example drawing
and the functions associated with calculating the curvature of the 3D models of the
bones, the connectivity is a requirement and therefore this downscaling must not be
done. In the functions you will therefore see switches from the 3 matrices representing
the patch object to the matrix or list of points. To summarize: they represent the same,
but serve other purposes.
In the end a 3D model of a bone can be represented by 2 structures: or 3 matrices
which will contain connectivity information or 1 matrix without this information.
The agreement for the rest of the work is: if we talk about the patch object defined by
the 3 matrices, we will talk about a patch object of vertices. This is the patch
representation of the 3D model.
On the other hand, if we talk about the simplified matrix, we will talk about a list of
(data)points. The 3D model is treated like a set of data in the this case. This will be
referred to as the list representation of the 3D model.
3.3 Bone-specific coordinate systems
In 3.1.3 we talked about the concept of a bone-specific coordinate system for each of
the 5 bones (humerus, scapula, clavicle, ulna and radius). Moreover we agree on using
the term ‘local reference system’. The definition for each dedicated coordinate system
is given in [11].
In this section we will illustrate each of these systems on top of the corresponding
bone, and we will explain the construction of them.
The coordinate systems are based on the positions of specified features and thus each
system will be different for each bone. Hence for example, 2 different clavicles have 2
different local coordinate systems. The features that are needed to define the
coordinate systems, will all be extracted by our tool.
The coordinate systems are calculated in our tool for the right sided bones that were
output of the orientation procedure, so whenever a left bone has to be visualized, the
26
local reference system has to be mirrored in the same way as the bone – with respect
to the y-z plane.
For the Matlab® code of the following functions the reader is referred to Appendix B.1.
3.3.1 Humerus
The local coordinate system associated with the humerus, (Oh, Xh, Yh, Zh), can be
defined once three features are available: the center of the head (Figure 3.10, left,
yellow), the lateral (Figure 3.10, left, red) and the medial epicondyle (Figure 3.10, left,
blue). Construction of the system is as follows.
Figure 3.10
- The origin, Oh, is coincident with the center of the head.
-Yh: the line connecting the center of the head and the midpoint between the two
epicondyles (Figure 3.10, left, purple), pointing to the center of the head.
-Xh: the line perpendicular to the plane formed by the center of the head and the two
epicondyles, pointing anteriorly.
-Zh: the line perpendicular to the two former defined axes, pointing laterally.
27
For finding directions perpendicular to a given plane it is sufficient to do the cross
product of two vectors defining the plane.
The execution of this coordinate system determination is done in function ashum
(Appendix B.1.2).
3.3.2 Scapula
The local coordinate system of the scapula (Os, Xs, Ys, Zs) is defined with: the
acromial angle(Figure 3.11, blue), the inferior angle (Figure 3.11, red) and the root of
the spine of the scapula (Figure 3.11, yellow). Construction of the system is as follows.
Figure 3.11
-The origin, Os, is coincident with the acromial angle.
-Zs: the line connecting the root of the spine with the acromial angle, pointing towards
the acromial angle.
-Xs: the line perpendicular to the plane formed by the acromial angle, the inferior angle
and the root of the spine, pointing anteriorly.
28
-Ys: the line perpendicular to the two former defined axes, pointing upward.
The routine of calculating this local coordinate system is done by the function asscap.
3.3.3 Clavicle
For the local coordinate system of the clavicle (Oc, Xc, Yc, Zc) as defined in [8] the 2nd
component of the local coordinate system of the thorax is needed [8]. As this axis is
unavailable a good approximation has to be chosen for the direction of Yt, the y-axis of
the thorax. The axis Yt can be approximated by the global z-axis Zglobal if the clavicle
is oriented like in the human body. The most anterior point of the sternoclavicular joint
(SC, Figure 3.12, blue) and the most posterior point of the acromioclavicular joint (AC,
Figure 3.12, red) are involved too in the construction of (Oc, Xc, Yc, Zc).
Figure 3.12
-The origin, Oc, is coincident with SC, the most anterior point of the sternoclavicular
joint (blue marker).
-Zc: the line connecting SC and AC, pointing to AC.
-Xc: the line perpendicular to Zc and Yt, pointing forward
-Yc: the line perpendicular to Xc and Zc, pointing upward.
29
The routine of calculating this local coordinate system is done by the function asclav.
3.3.4 Ulna
In [3] is not a definition given for a coordinate system for the ulna as a bone on its own.
A definition is given for the entire forearm. But for this definition features from both
bones of the forearm, ulna and radius, are needed. As only features of one bone will be
made available by our tool, we had to seek for a solution. This solution is delivered in
the shape of a newly designed coordinate system, in which only features of the ulna
are required.
The features are the apex of the olecranon (OL, Figure 3.13, red), the tip of the
coronoid process (COR, Figure 3.13, blue) and a point that will help in defining the
coordinate system. This is not contained in the list of features for the ulna. In Figure
3.13 this helping point is depicted as the yellow marker. We will call it AUX.
Figure 3.13
The coordinate system (Ou, Xu, Yu, Zu) is constructed as follows:
The origin, Ou, is the midpoint between COR and AUX.
30
Xu: the line connecting COR and AUX, pointing towards COR.
Yu: the line perpendicular to the plane defined by COR, OL and AUX, pointing laterally.
Zu: the line perpendicular to the former defined axis Xu and Yu, pointing anteriorly.
Constructing this coordinate system given the expected features happens in function
asulna. Extracting AUX happens in auxUlna. (appendix B.1.2)
3.3.5 Radius
For the radius the same problem is encountered. [3] doesn’t give a definition for the
local coordinate system of the radius based on only features of the radius. A new
definition is made. In this definition we need the center of the head of the radius (see
8.2 for a clear definition)(RH, Figure 3.14, blue), the styloid process (SP, Figure 3.14,
red) and a helping point. The helping point is the center of the ulnar notch (UN, Figure
3.14, yellow). UN is not extracted as a feature in the GUI. The code of this function
ulnarNotchRadius is found in Appendix B.1.2.
The coordinate system (Or, Xr, Yr, Zr):
The origin, Or, is UN.
Zr: the line connecting UN and RH, pointing towards UN
Xr:. the line perpendicular to the plane defined by UN, RH and SP, pointing
anteriorly.
Yr: the line perpendicular to the former defined axis Xr and Zr, pointing laterally.
Constructing this coordinate system given the required features happens in
function asradius.
31
Figure 3.14
32
Chapter 4
The humerus
In this chapter all the functional procedures associated with the humerus are described.
As seen in the second chapter about the anatomy there are 9 features to be extracted.
Each extracted feature corresponds to a specified function which will be invoked each
time the chosen feature has to be localized.
Further there is one function of considerable importance, the function responsible for
the orienting of the 3D model of the humerus. This function is carried out first in order to
have some sort of unambiguous reference orientation for further processing. The
outcome of the orientation procedure is generic for every type of humerus, independent
of the size of the Stl file representing the 3D model of the humerus, the side of the bone
(right or left), and most important the orientation and position of the original 3D model.
We arbitrarily defined the reference orientation to the orientation of the humerus if the
arm is in its neutral vertical position. If we talk about orientation in the rest of the work,
we mean a model’s orientation and its position to not repeat it every time.
In the following flowchart the sequence of actions for the processing of a read in 3D
model of a humerus is given.
33
Extract lateral epicondyle
Extract medial epicondyle
Extract head of humerus
Extract greater tubercle
Orient humerus
Extract lesser tubercle
Extract trochlea
Extract capitulum
Extract topmost point
Extract metaphyseal cylinder
All of these functions will be invoked as a result of a manipulation of the GUI. This is
already explained in the previous chapter about the GUI and its functionality. The main
component responsible for the execution of all of the functions involving the humerus is
the radiobutton ‘Humerus’ in the panel ‘Bones’. Once pushed the orientation is
executed and further all of the features are extracted. Than, choosing the radiobuttons
associated with a specific feature will only carry out the visualizing of the position of the
feature on the patch object representing the considered humerus.
In the continuation of this chapter (and in the other chapters dedicated to the other
processed bones of the human body (scapula, clavicle, ulna or radius)) first the
orientation function is described which will be followed by the description of the
functions responsible for the extraction of the features of interest. For each of these
functions a section is provided.
34
Each description will begin with a short explanation of the purpose of the function.
Figures will be given as a clarifying mean. The second part will show the followed
procedure in an algorithmic way. This will help in understanding the used algorithm in a
code-independent manner. Each step in the algorithm will be described and justified.
Each paragraph about a functional procedure of a bone will start with the definition of
the function as used in our code in Matlab®. It is important to stress the fact that the
name of the function is not an exact requirement. It is only the name we chose in
developing our tool and with this name it is easier to refer to this function throughout
the guiding text. The important information that is given by these statements is the type
and number of input and output arguments. The exact form of these arguments is
described to a greater extent in the code of the functions.
If talked about x-axis, y-axis or z-axis we mean the components of the global
coordinate system as defined in 3.3. In the accompanying figures this is made explicit
by talking about Xglobal, Yglobal and Zglobal. This will also hold for the following
chapters dedicated to the other bones.
The actual code in Matlab® accompanied with remarks is outlined in appendix B.2.
4.1
The orientation of the humerus
As stated before, this function is executed first. The Stl file of the bone will undergo
several transformations, i.e. linear translations and rotations in 3D space, in order to be
positioned upright onto the z-axis with its anterior face oriented towards the negative yaxis. Important to mention here is also the fact that a left bone is detected and
transformed into a right bone through taking its mirror image. This will be helpful in the
feature extraction processes, because doing so, only right bones have to be taken into
account. In the visualization processes that follow, the mirror image of an original left
bone will be mirrored once again to show the original left bone.
The result of all of these transformations is a uniformly oriented right bone. All of the
feature extraction functions will get this oriented bone as an input.
35
Figure 4.1 shows the position and orientation of the bone of the output.
Figure 4.1: Resulting orientation. Left: superior view as seen from the positive z-axis.
Right: Anterior view as seen from the negative y-axis.
Now that the purpose of the function is clear, the followed procedure is outlined
subsequently. The code in Matlab ® can be found in appendix B.2.1.
Reading chapter 3 makes clear that the only data of the bone we have are the 3
matrices x1, y1 and z1 that represent the patch object of the bone. Secondly we also
have the matrix n1, consisting of the normals to the facets of the 3D model. These four
matrices are the output arguments of the previous executed stlread function.
The statement that executes function orientHumerus is:
[x2, y2, z2, n2, e1, e2, lowest, side] = orientHumerus(x1, y1, z1, n1)
The output arguments given back are described in the following steps that make up the
orientation process of the humerus.
36
Step 1: Get a list of points
The first step in the procedure is to transform the 3 matrices (x1, y1 and z1) to one
matrix of all the points of the patch object. In paragraph 3.2 is justified this
transformation and is stated the agreement to talk about a list of points rather than a
matrix. Each row in the list holds x-, y- and z-coordinates of the position of the
corresponding point. Each point appears only once in the list. This list, say L, serves as
a starting point to the algorithm.
Step 2: Calculate the 2 extreme points along the length of the humerus
The humerus is a bone of a specific form; it can be seen as a long bone in a prominent
direction. The idea of the orientation function is to orient the humerus along the z-axis
with its long side. To do this we need firstly its principal axis (the long side) and select 2
points of this axis, a and b. Secondly if we can force these two points to lie on the zaxis, we will be sure that the 3D model of the humerus will be positioned around the zaxis. These two points that lie on the principal axis, are not points of the bone but are
projections of points of the 3D model. We arbitrarily chose a and b to represent the two
most extreme projections of points of the 3D model onto the principal axis.
It is not only important to know which are these points, but it is also necessary to know
which point is near the proximal end of the humerus (on its head) and which point is
near the distal end. This will be clarified next.
To get a and b a specific function is invoked: [a, b] = findRefP(L). This takes the list L
as input argument and delivers a and b as output arguments. a will be the most distal
point and b is the most proximal point (near the head of the humerus) on the principal
axis. Figure 4.2 shows these two points, the blue point represents a and the red point
represents b.
37
Figure 4.2
There are several steps performed in findRefP. First a principal component analysis on
the data in list L is carried out. This is done by a function predefined in Matlab®,
princomp, and gives back 2 matrices: COEFF and SCORE. COEFF is a 3-by-3 matrix,
each column containing coefficients for one principal component. The columns are in
order of decreasing component variance, thus the principal component, the one we
need, can be found in the first column of COEFF.
SCORE contains the principal component scores (projections); that is, the
representation of each point of L in the principal component space. This is an M-by-3
matrix, with M the number of points in L. The principal component space (coordinate
system) is constructed by the 3 base vectors in COEFF and its origin is the mean of all
the data points of L. The first column of SCORE gives for each point its score or
projection or coefficient on the principal component axis, the first column of COEFF.
The only thing to do now is calculating the minimum and the maximum of the first
column of SCORE, this will yield the two extreme projections on the principal axis. a is
now the point with the smallest score and b is the point with the biggest score.
38
Next thing to do is making sure which point is near the top and which to the bottom of
the humerus. To solve this problem, the specific geometry of the humerus offers the
solution. The top of the humerus consists of a head which approximates very closely to
a sphere, whereas the distal end of the humerus does not approximate at all to a
sphere. Therefore the tactic used is to select in a uniform manner a set of points near a
and also near b, say setA and setB. These two sets of points can now be given to a
function that calculates the best fit to a sphere. The set that yields the best result
through the sphere fitting is surely the one next to the top of the humerus. The fitting
procedure is based on the least squares fitting method.
So in the end we have determined a as the extreme point on the principal axis near the
bottom and b the extreme point near the top.
Step 3: Do a translation defined by point a
This is a standard procedure in which the point a, corresponding to the distal end of the
humerus, defines the translation and is translated to the origin (0, 0, 0) of the global
coordinate system. All the other points undergo the same translation. Figure 4.3 gives
the resulting orientation.
Figure 4.3
39
Step 4: Do a sequence of rotations to get the other point, b, onto the z-axis
Basically this step consists of 2 rotations, one rotation around the z-axis and one
rotation around the y-axis. The angles which to use in the two rotations can be found
very easily through simple trigonometric formulas.
As a result the point b, corresponding to the proximal end of the humerus, will lie on the
positive z-axis and the bone is oriented along the z-axis.
In the code we wrote it is possible that one rotation more is necessary. This possible
rotation is one over 180 degrees, because it is possible that the rotated top point b is
situated on the negative z-axis as result of the 2 rotations.
This is because the angles used in the first two rotations are smaller than 90 degrees.
So for example, if point b lies originally below the x-y plane, it will end up on the
negative z-axis. Figure 4.4 illustrates such a situation.
Figure 4.4
40
This consideration has to be made with every rotation throughout the extent of the
work. Therefore with every rotation where this situation is possible, counteracts must
be taken.
Step 5: Localize the two epicondyles on the distal end of the humerus
First of all, it is important to note that for now it is not necessary to know which the
lateral is and which the medial epicondyle is. This would be a huge task to discover in
this moment because we don’t know the orientation in the x-y plane, nor the side of the
bone. Just the coordinates of the two epicondyles in random sequence are needed.
For this extraction we made the function epicondyles: [e1 e2] = epicondyles(L). L is
the list of translated and rotated data points and e1 and e2 are two 1-by-3 arrays of the
positions of the coordinates of the two epicondyles.
The function does basically a principal component analysis of the lower 15 % of the
data points in L. We can talk about ‘lower’ now, because the bone is already oriented
along the z-axis in an upright position. Each point in this list of points has a score onto
the principal component axis. These scores and principal components are the output
arguments of the Matlab® function princomp like in Step 1. Because the epicondyles
are the two extreme points on this principal component axis, we have to find the points
with the smallest and biggest scores with respect to this axis. These will be the two
epicondyles which will be helpful in the following orientation.
The epicondyles already are localized. So carrying out the orientation of the humerus
implicitly carries out the feature extraction of the epicondyles.
Step 6: Determine which one is the lateral and which one is the medial
epicondyle
The determination of the real identity of the epicondyles is based on the specific
geometry of the distal end of the humerus. Through visualization of a number of bones
(the 13 3D models we worked with) it became clear that the medial epicondyle has a
smaller Euclidian distance to the lowest point of the bone (most distal point of trochlea),
than the lateral epicondyle. So a comparison between the point in L with the smallest zcoordinate and both epicondyles is sufficient to know the side of the epicondyles. The
41
medial epicondyle is named e1 and the lateral epicondyle is named e2. These two
variables e1 and e2 can be found amongst the output arguments of orientHumerus.
Figure 4.5 illustrates the logic of this step. The blue marker is the medial epicondyle,
the red one is the lateral epicondyle. The blue marker has a smaller distance to the
lowest point (yellow) than the red marker.
Figure 4.5
By now it is not yet clear whether the bone is a left one or a right one, but that doesn’t
matter.
Step 7: Do a rotation around the z-axis to get the medial epicondyle in the x-z
plane on the positive x-axis
This step only involves calculating the correct angle and rotating the whole bone over
this angle around the z-axis. It is possible that after this rotation the medial epicondyle
lies on the negative x-axis. This occurs when the medial epicondyle has an x-value that
42
is smaller than 0 before this rotation. In this case a supplementary rotation of 180
degrees around the z-axis is needed to get the medial epicondyle onto the positive xaxis. Figure 4.6 gives the current orientation as seen from a superior view (from the
positive z-axis). The medial epicondyle (blue) is situated in the x-z plane; its ycoordinate is 0.
Figure 4.6
Step 8: Determine whether it is a bone of the right or a bone of the left arm
Again this procedure is based on the observation of the humeri to our disposal. In all
cases the relative positions of the medial epicondyle and the lowest point (most distal
point of trochlea) give the solution. As the trochlea, as an articular surface, lies more
anteriorly than the medial epicondyle, it will determine the anterior aspect of the
humerus. With the medial epicondyle in its position as defined in step 7 we can make
the following conclusion. If the lowest point has a smaller y-value than the medial
epicondyle e1, which is 0, we can be sure that the bone belongs to a right arm. In the
opposite situation we conclude that the processed humerus belongs to a left arm.
In figure 4.7 with the positions of the medial epicondyle (blue) and the lowest point
(yellow) we can conclude that the bone is a right sided one. The y-coordinate of the
lowest point is smaller than the y-coordinate of the medial epicondyle
43
Step 9: In case of a bone of a left arm, transform it to a bone of right arm
Transformation to the ‘same’ humerus of the right arm happens through mirroring all of
the points of L regarding to the x-z plane because of the current orientation of the bone.
So every y-coefficient will get an opposite sign: alpha becomes –alpha for all points in
the second column of the list.
It is very important not to forget to give back the specification of the side of the bone as
an output argument of the function. This logical has the name side in the set of the
output arguments. If side equals 1, the processed bone is a left one. The specification
will be of use by the visualization of the bone and features where a left bone has to be
visualized as a left bone.
Figure 4.7: Medial view of the distal end of the humerus.
So as a result of the function the humerus is oriented in a uniform way along the z-axis
with its anterior face pointing towards the negative y-axis, and it is in all cases a
humerus of a real or an imaginary right arm.
As a finalizing remark for this paragraph it must be said that the output arguments, x2,
y2 and z2 are 3-by-m matrices that make up the oriented patch object of the bone. This
can be misleading because throughout the biggest part of the algorithm is spoken
44
about the list representation L rather than the patch representation of the 3D model of
the humerus. This is not an error. We chose to give the patch representation as an
output argument for subsequent use. That will be the visualization of the bone and this
can only be done in Matlab® with the definition of the patch object. This is explained in
3.2.
If one will examine the code in appendix B.2.1, he will see that the transformation
functions: translation and rotation will use patch representations as input and output
arguments. The reason is simple, if we would have used lists of points we would have
got problems to visualize the also become bone. It is namely impossible to go from a
list representation in a uniform way to its original patch representation, because we do
not know the connectivity of the vertices (points) and because a lot of points are
discarded in the primary process to go from the patch representation to the list of
points. Therefore these transformation functions work with the patch representations of
the 3D models.
45
4.2
Extraction of the lateral and the medial epicondyle
The extraction of the position of the two epicondyles of the humerus is already done in
the prior orientation process. So the whole procedure is outlined there in steps 5 and 6.
Basically it is divided in two parts. In a first part the localization of the two epicondyles
is done. After this step, it is not yet clear which epicondyle the medial and which
epicondyle the lateral is. This step is described in Step 5 of 4.1.
In the second part, described in Step 6 of 4.1, the side of each epicondyle is
determined. This is based on the comparison of the distances to the most distal part of
the trochlea.
In Figure 4.8 the two epicondyles produced by the extraction process are depicted. The
medial epicondyle is the blue one, the lateral epicondyle is the red one.
Figure 4.8: Anterior and slightly lateral view of a right humerus with both epicondyles
46
4.3
Extraction of the head of the humerus
The extraction of the head of the humerus aspires to visualize the real head of the
humerus as a perfect sphere. We use the term ‘real head’ to make sure the reader
knows it is the articulation surface that articulates with the glenoid cavity of the scapula.
Its articulating function in the human body justifies to a great extent the presumption
that this resembles a lot to a part of a sphere.
The extraction procedure outlined next involves fitting points of this articulation surface
to an entire sphere. This fitted sphere will be referred to as the head of the humerus.
Visually analyzing this part of the humerus makes clear that this sphere is situated
close to the principal axis of the humerus.
The function responsible for this extraction is named headHum.
[center radius] = headHum(L, e1, e2)
The two output arguments are the center of the head and its radius, the two
requirements to draw a sphere.
The input arguments are list L of the points of the oriented right bone, the medial
epicondyle e1 and the lateral epicondyle e2.
In figure 4.9 the purpose of the function becomes clear.
Figure 4.9: Left: anterior view of the proximal end of a right humerus . Right: the
same bone as the left image but with the visualization of the fitted sphere.
47
The procedure itself is based mainly on isolating a good selection of the points of the
3D model that are part of the articulation surface, and giving this set of points as input
to a function carrying out the fitting of these points to a sphere based on the least
squares fitting technique.
Step 1: Select the topmost part of the humerus
The first task is to select from the list of points L those points of the proximal end of the
humerus. We name this new list U. In a following step these points will be given to a
sphere fitting function in order to get a rough sphere approximation of all the points of
the proximal end.
This list U contains points with a z-value bigger than 87% of the total length of the
oriented humerus. The total length is defined as the difference between the point with
the biggest z-coordinate and the point with the smallest z-coordinate of the oriented 3D
model of the right humerus. The choice for 87% is a result of a try and error process
with the 13 available 3D models and yields the best results.
Figure 4.10 shows the list of points contained in U
Figure 4.10: The set of points U in red.
48
Step 2: Do a sphere fit of U
As a result this step gives the center and the radius of the rough sphere through the
fitting procedure. The center is called c_rough and its radius r_rough. The purpose of
these parameters is to help selecting the points of the articular surface of the head of
the humerus. In Figure 4.11 it is clear that this sphere does not approximate the
articular surface on the medial side (left side of the figure).
Figure 4.11: Superior view of the fitted rough sphere.
Step 3: Select the points of the articular surface of the head
The procedure is based on the findings in [13]. As already stated, the articulation
surface is like a cut off sphere. We call it the articular margin surface and we are
looking for points of this margin surface.
You can draw a perpendicular to this surface in the center point of it, say line P. We call
the center point of the margin surface (where P intersects with the surface),
pTheoretic. This point is surely needed, but also the points in his proximity. To select
those neighboring points we used line P to define planes perpendicular to it. If we draw
such a perpendicular plane on a distance dTheoretic away from p in the direction of
the inside of the head and take all the points that lie above this plane in the direction of
p, we get some points of the articular margin surface.
49
This would be an easy task if the user could interact with the bone and do the
drawings. This tool is trying to eliminate errors caused by user subjective input, so no
user input is allowed.
Thus the difficulty now is the specification of the critical parameters P and d. The
starting points for getting P are the two epicondyles e1 and e2, and the center and the
radius of the rough sphere, c_rough and r_rough.
First we calculate the line between the epicondyles, the transepicondylar. In [13] is
defined the retroversion angle. The retroversion angle is the angle between the
transepicondylar and P in the x-y plane (transverse plane). Not only it is defined in [13],
they also measured a number of 65 humeri of women and men of all ages and
detected the retroversion angle of them, concluding that this angle has a mean of 17.9
degrees. So if we have the vector that represents the direction of the transepicondylar
and rotate it in the x-y plane over an angle of 17.9 degrees we get a good
approximation of the direction of P in the x-y-plane.
In [13] is also defined the inclination angle. This is the angle between the shaft of the
humerus and P in the x-z-plane (frontal plane). A resembling study in [13] yields as the
mean of the inclination angle a value of 129.6 degrees. So we can rotate the vector that
represents the current direction of P in the x-y plane over an angle of (129.6 – 90)
degrees around the y-axis.
This will give us the vector that represents the final
direction of P. To define P as a line we need to agree on a point that would be a point
of P. Arbitrarily we have picked the center of the rough sphere, c_rough, because it is
relatively close to the eventual center of the real head.
So now we have the definition of P. It contains c_rough, the center of the rough
sphere, and p, the intersection of P with the rough sphere. The next thing is drawing
planes perpendicular to P in a certain point between c_rough and p, say on a
Euclidean distance of d away from p. We used as d 70% of the radius of the rough
sphere. This radius is nothing more than the Euclidean distance between c_rough and
p. The choice for this value of d is the result of a trial and error process. With this value
we got in all the processed humeri the best result.
50
Than use the plane at a distance of d from p perpendicular to P for making a list of
points. We select the points above this plane in the direction of p. This list of points is
named M. Figure 4.12 illustrates the concept.
Figure 4.12:
Above: The yellow marker is c_rough, the blue marker is p and the green one is a point on a distance d
of p in which we will draw the perpendicular planes to P, the blue line.
Left: Superior view. The red line is the transepicondylar. So the angle between the red and the blue line
is the retroversion angle. Right: Anterior view. The angle between the blue line and the shaft of the
humerus is the inclination angle.
Below: Left:The plane created, in blue. Right: The eventual points of M in red.
51
Step 4: Do a sphere fit of the points in M
Ultimately this list of points, that represent points of the articular margin surface, is
handed over to a function carrying out the fitting to a sphere of these points. This will
yield a sphere, defined by its center and its radius, which closely approximates the real
head of the humerus. These representations of the center and the head are the output
arguments of the function headHum that is mentioned in the start of this paragraph.
Figure 4.13 shows the calculated sphere on top of the 3D model of the oriented
humerus from a superior view. If we compare this with Figure 4.11, we see that the
articular surface (on the left side) is much better approximated.
Figure 4.13: Superior view of the fitted sphere that approximates the head of the humerus.
In the code this last step is carried out in an iterative manner. The center and radius of
the sphere, c_new and r_new, are now used in defining a new P and a new d in the
same manner as specifying the first definition of P and d. With these new parameters
we get a new list M by following the same selection procedure. This new list of points is
handed over to the sphere fitting function to become a new center and radius of the
newly calculated sphere which will be used to define a new P and d. This iterative
process is stopped when the distance between the previous and the new center of the
sphere is smaller than a predefined value. The optimum stop condition was found by
trial and error. It can’t be taken too small, because in this case the iteration will possibly
52
never stop. On the other hand it can’t be taken too big, because in this case the
approximation of the sphere won’t give the desired result.
4.4
Extraction of the greater tubercle
In this section the extraction of the position of the greater tubercle is described. The
greater tubercle is a large tuberosity located laterally on the proximal epiphysis.
Figure 4.14 shows in the black oval the location of the tubercle. The purpose is to
associate 1 point with this tubercle and extract that point. The definition of this point
that will represent the greater tubercle is given in [1].
Figure 4.14: Left: anterior view of the head of the right humerus. Right: lateral view.
The function responsible for this extraction in our tool is named greaterTubHum.
[greater] = greaterTubHum(L, cHead, rHead)
The output argument is the position of the greater tubercle onto the 3D model of the
oriented bone. The input arguments are list L of the points of the oriented bone, the
center of the head of the humerus, cHead, and the radius of the head of the humerus,
rHead. This means that this function must be executed after the extraction of the head
of the humerus, which is described in paragraph 4.3.
53
Briefly worded, greaterTubHum will look at all the points of the proximal end of the
humerus (the rough head) and calculate orthogonal distances of these points to the
sphere representing the head of the sphere. The point on the lateral side of the bone
with the biggest distance to this head is defined as the greater tubercle.
Step 1: Define a search space in which to look for the greater tubercle. This search
space is situated laterally and superiorly.
This is a very logical step. Basic anatomy and logic justifies to not consider all of the
points that make up the humerus as possible candidates for being the greater tubercle.
For example, while looking at a humerus it becomes very clear that it is not necessary
to take the distal half of the humerus into account to look for the greater tubercle
because it is situated in the proximal half.
The search space, say S, is thus a list of points which will contain the greater tubercle.
We defined our search space considering the uniform orientation of 4.1. The 3
coordinates (x_p, y_p, z_p) of each point of the 3D model are tested against 3 well
chosen conditions, 1 for each coordinate. In this way we can isolate a rectangular
space that is part of 3D space.
‘Well chosen’ has to be interpreted in the sense of ‘uniform applicable’. It must make
sense for all sizes of humeri. Therefore we can’t use absolute numbers in our
conditions. Conditions like ‘the x-value must be bigger than 100’ can be helpful for one
3D model of a humerus, but useless for another because it is for example 2 times
smaller than the former and thus will the stated condition produce other unwanted
points. This is why we will use statements as ‘the maximum of’ or ‘50% of the minimum
of’ in our conditions.
The above explanation must be generalized to all the situations in which we had to look
for a certain region of a 3D model.
The following conditions were used with respect to the current orientation of the 3D
model:
-The x-coordinate has to be smaller than 0 -> lateral aspect is targeted
54
-The y-coordinate must lie between 0.3 * max(all y-coordinates) and 0.3 * min(all
y-coordinates).
-The z-coordinate must be bigger than min(all z-coordinates) + (max(all zcoordinates) - min(all z-coordinates)) * 0.93 -> the upper end.
In the above conditions max(.) is the function that selects the maximum of its input and
min(.) the function that select the minimum of its input.
For a point to be allowed to enter the search space S all 3 conditions must hold.
Step 2: Discard those points from the search space that lie inside the sphere
that represents the head of the humerus
This step is based on the fact that the greater tubercle is situated for sure outside of the
sphere of the head.
For every point in S its Euclidean distance to the center of the head, cHead, is
calculated and compared with the radius of the head, rHead. If the distance to cHead
is smaller than rHead, the point lies into the sphere and is discarded from S.
55
Figure 4.15: The red markers represent the points of S. The head of the sphere is modeled by the
yellow sphere.
Figure 4.15 gives the final points in S.
Step 3: Calculate for each point in S the orthogonal distance to the sphere
representing the head of the humerus
Practically this is done by calculating for each point in S the Euclidean distance to
cHead and subtracting from this distance the radius rHead.
Step 4: Select the point in S with the biggest orthogonal distance to the sphere
This point is the greater tubercle. Figure 4.16 shows the position of the greater tubercle
on the 3D model.
56
Figure 4.16: A laterosuperior view of the right humerus. The blue dot represents the greater tubercle.
4.5
Extraction of the lesser tubercle
In this section the extraction of the position of the lesser tubercle is described. The
lesser tubercle is a small tuberosity located on the anterior aspect of the proximal
epiphysis.
Figure 4.17 shows in the black oval the location of the entire tubercle. The purpose is to
associate 1 point with this tubercle and extract that point. The definition of this point
that will represent the lesser tubercle is given in [1].
The function responsible for this extraction in our tool is named lesserTubHum.
[lesser] = lesserTubHum(L, cHead, rHead)
The output argument is the position of the lesser tubercle onto the 3D model of the
oriented right bone. The input arguments are list L of the points of the oriented right
bone, the center of the head of the humerus, cHead, and the radius of the head of the
57
humerus, rHead. This means that this function also has to be executed after the
extraction procedure of the head of the humerus, which is described in paragraph 4.3.
Figure 4.17: Left: Superior view of a right oriented humerus. Right: Lateral view of the same bone
The technique used to get the lesser tubercle is parallel to the technique used to get
the greater tubercle. A list of points outside of the sphere of the head on the anterior
side is made. All the orthogonal distances of these points to the sphere are calculated.
Ultimately the lesser tubercle is the point that has the biggest orthogonal distance.
By using this procedure we have tried to approach as accurately as possible the
definition of the virtual palpation of the lesser tubercle as explained in [1].
The following steps are completely the same as the respective steps of 4.4, only
some parameters are different.
Step 1: Define a search space in which to look for the greater tubercle.
The search space, say S, constructed here is the result of applying the following rules
to all of the points in L. Of course these rules make only sense in the current orientation
of the 3D model of the bone.
-The x-coordinate must lie between 0.3 * max(all x-coordinates) and 0.4 * min(all
x-coordinates).
-The y-coordinate must be smaller than 0 -> anterior aspect is targeted
58
-The z-coordinate must be bigger than min(all z-coordinates) + (max(all zcoordinates) -min(all z-coordinates)) * 0.90 -> the proximal end is targeted
For a point to be allowed to be added to the search space all 3 conditions must hold for
the coordinates of the point.
Step 2: Discard those points from the search space that lie inside the sphere
that represents the head of the humerus
For every point in S its Euclidean distance to the center of the head, cHead, is
calculated and compared with the radius of the head, rHead. If the distance to cHead
is smaller than rHead, the point lies into the sphere and is discarded from S.
Step 3: calculate for each point in S the orthogonal distance to the sphere
Practically this is done by calculating for each point in S the Euclidean distance to
cHead and subtracting from this distance the radius rHead.
Step 4: select the point in S with the biggest orthogonal distance to the sphere
This point is the lesser tubercle.
Figure 4.18 is an illustration of the critical parameters of the extraction procedure
together with the eventual position of the lesser tubercle.
59
Figure 4.18: The blue marker represents the position of the lesser tubercle. The red dots are the points
of the search space S. The yellow sphere is the representation of the head of the humerus.
4.6
Extraction of the trochlea
This procedure will determine the localization of the trochlea as a circle. In Chapter 2
the trochlea is described. It is a distally located articular surface that articulates with the
ulna.
Because of its shape the edge of the trochlea can be represented by a circle in the 3D
space. If we say extraction of the trochlea, we mean the extraction of its edge. A 3D
circle is specified by its center, its radius and its normal, which defines the orientation.
Figure 4.19 specifies the location of the trochlea onto a 3D model of an oriented right
humerus. The humerus is looked at from an anterior view.
The function responsible for this extraction in our tool is named trochHum.
[center, radius, normal] = trochHum(L, lowest, med_e)
The output arguments are the three parameters that define a 3D circle. The input
arguments are list L of the points of the oriented bone, the point of the humerus with
the smallest z-value, lowest, and the position of the medial epicondyle, med_e.
60
Figure 4.19
The method of working can be summarized as follows: a selection of well chosen
points is handed over to a function which will fit these points to a circle in 3D. This circle
can be seen as the representation of the trochlea.
Step 1: Make a list of points that are part of the trochlea
Because the trochlea is targeted it is very logical to select the points of the trochlea.
This wanted list is called fitL. Again some conditions must be met by the 3 coordinates
of the points in order to be found suitable for fitL.
It caught the eye that the most distal part of the trochlea is also the most distal part of
the entire humerus. Therefore this most distal point could be considered of being part
of the trochlea without exception. In our implementation this point is the input argument
lowest, but it could also be calculated very easily as being the point with the smallest
z-value in the current orientation of the 3D model. This point will help in defining the
conditions for selecting the points for fitL. The orientation of the bone will be the
second helping hand and finally we also use input argument, med_e, to do this job. All
the conditions are based on the study of the anatomy of the humerus and thorough
observation of the humerus in its oriented state.
-The x-coordinate has to lie in a very small interval around the x-value of
lowest. Arbitrarily we chose this interval to be of length 2 mm with lowest the
midpoint.
61
-The y-coordinate will not play a roll in the selection process.
-The z-coordinate has to be smaller than the z-coordinate of the medial
epicondyle, because for every humerus the trochlea is situated more distal than
the medial epicondyle.
If all the above conditions are fulfilled by the coordinates of a certain point, the point will
be added to fitL.
Step 2: Do the first fitting to a circle of the points in fitL
This step will yield the position of the center of the circle, its radius and the normal to its
plane.
Step 3: Calculate Euclidean distances between the recently calculated center
and the points of fitL
This step is the start of a refining phase. Step 2 gave a good approximation of the
circle, but in most cases outliers were present. These outliers had a negative effect on
the correctness of the position and orientation of the calculated circle. Therefore a
second fitting phase will take place with as input list fitL of which the outliers are
discarded.
Step 4: remove the outliers of fitL
When is a point an outlier? We use the mean, mu, and standard deviation, sigma, of
the set of distances of the points in fitL to the center of the circle of Step 2. With this
information an outlier is defined as a point smaller than mu – 3*sigma or bigger than
mu + 3 * sigma.
Step 5: Do the second fitting to a circle of the points of the reduced list fitL
This step will yield the final and sought center, radius and normal to the plane of the 3D
circle representing the trochlea.
Figure 4.20 illustrates the calculated circle (blue) together with the points with which the
circle was fitted (red).
62
Figure 4.20: Anterior and slightly medial view of the distal end of a 3D model of a right humerus
4.7
Extraction of the capitulum
The capitulum is a rounded eminence on the lateral side of the distal end of the
humerus. It articulates with the cup shaped depression on the head of the radius.
Therefore it can be approximated by a sphere. The subject of this paragraph will be the
algorithm used to extract the capitulum as an approximation of a sphere. This sphere
will be referred to as the capitulum. No definition about this feature is given in [1].
The function responsible for this extraction in our tool is named capitHum.
[center, radius] = capitHum(L, lat_e)
The output arguments are the two parameters that define the sphere.
The input arguments are list L of points of the oriented right humerus and the
specification of the lateral epicondyle, lat_e.
The method of working is parallel to that of the head of the humerus and that of the
trochlea: the right set of points is isolated and given as input to a function that will carry
out the least square fitting procedure to yield a sphere.
63
Step 1: Make a list of points that are part of the capitulum
The idea is to get a sufficient set of points of the capitulum in order to use them as input
for the fitting procedure. For a sphere fit at least 4 points are required. This list is called
fitL.
As in all the cases where we want to isolate a certain set of points, some conditions are
defined. The starting point is the orientation of the bone as performed in 4.1 together
with the knowledge of the lateral epicondyle, lat_e.
For the possible points of fitL the following conditions must be fulfilled
-The x-coordinate has to be smaller than the x-coordinate of the lateral
epicondyle divided by 2
-The z-coordinate must be smaller than the z-coordinate of the lateral
epicondyle.
As the capitulum lies a bit more anterior, fitL will with the above conditions also contain
points that do not constitute to the capitulum. For example the distal points of the
posterior part must not be involved in fitL. To sort them out we use a supplementary
selection procedure. All points in fitL are projected onto (0, -1, -1) to concede to the
requisite of the capitulum lying a bit more anterior, but also distal. The point with the
biggest projection, pFitL, is with certainty a point of the capitulum. We now will make a
new, more refined fitL, fitL2, that will contain the already mentioned point, pFitL,
together with the points on a well chosen distance to this point. This distance is set to
the distance between pFitL and lat_e divided by 4. This was the resulting configuration
of this distance through a trial and error process of the 13 3D models of the humerus.
Step 2: Do a sphere fit of the list fitL2
This step will produce the fitting of fitL2 to a sphere and hand over the center and the
radius of the sphere. These parameters are sufficient to draw the sphere. This is
illustrated in Figure 4.21.
64
Figure 4.21: The sphere representation of the capitulum in yellow. The points used in the sphere fitting
procedure, fitL2, in red.
4.8
Extraction of the topmost point of the humerus
The extraction of the topmost point of the humerus is logically nothing more than
determining the most proximal point of the humerus, i.e. the point on top of the head of
the humerus.
[top] = topHum(L)
The output argument is the position of the uppermost point. The input argument is the
list of points of the already oriented right humerus.
We will select the highest point, i.e. the point with the biggest z-value in the orientation
as calculated by the anteriorly executed function orientHumerus.
4.9
Extraction of the metaphyseal cylinder
The purpose of this procedure is to visualize the metaphysael cylinder; the cylinder
which best fits the shape of the upper humeral shaft. The exact definition of this feature
cannot be found in [1].
The function responsible for this extraction is named cylHum.
[radius under upper] = cylHum(L, cHead, rHead)
65
The three output arguments are the radius of the cylinder, the uppermost and the
undermost point on the axis of the calculated cylinder. Thus the three parameters that
define the calculated cylinder.
The input arguments are list L of the points of the oriented right humerus, the center of
the head of the humerus, cHead, and the radius of the head of the humerus, rHead.
This means that this function must be executed after the extraction of the head of the
humerus, which is described in paragraph 4.3.
.
The procedure itself is based mainly on isolating the part of the 3D model of the bone
defined as the metaphyseal cylinder. Because of the absence of a clear, unambiguous
definition, we decided to define two reproducible values and these will serve as an
upper and under boundary for the z-values of the points that represent the metaphyseal
cylinder. Next, the set of points that lie between the boundaries is given as input to a
function carrying out the fitting to a cylinder. This fitting process is based on the least
squares fitting technique.
Step 1: Define the under boundary for the z-coordinate
By examining a total of 13 3D models of humeri, it became clear that by looking a
humerus from an anterior view a curve can be observed about halfway of the bone on
its lateral side. Above this curve the lateral edge is more or less straight. This gave us
the idea to use the height of the position of the curve as the under boundary. This
choice has two reasons. First of all the shaft above this curve is straight and will
therefore yield better results if given to a cylinder fitting function. Secondly this
approach was taken in [13].
Implementing this idea was difficult. To locate a curve on a 3D model in space of
discrete data points is not a straightforward operation. We tried to use the mean
curvature calculation (2.1 and Appendix D) of the points of the entire bone and use this
information to locate the curve talked about. This approach was not successful
because the information given by the mean curvature calculation was insufficient to
determine the curve with certainty.
66
This brought us to another approach in which we modeled the anterior view by
projecting all the points of the 3D model onto the x-z plane. This 2 dimensional
representation of the bone shows the contour of the lateral side on the half of the
negative x-axis. There is not a way to easily locate the points on the edge because of
the discrete nature of the representation of the bone. So we looked to the points above
a certain z-value, and distributed all the points in intervals of length 8 with respect to
the z-value. Of each such interval we selected the points with the minimal x-value.
These points were collected in a list, say latSide2D. This list of 2-dimensional points
represents the contour of the lateral edge of the 3D model as seen from an anterior
view. This is illustrated in Figure 4.22.
Figure 4.22: The contour of the lateral edge of the right humerus as seen from an anterior view. The
vertical axis represents the z-axis.
The next phase is to locate the curve. This is done by comparing consecutive (with
respect to the z-value) points in the list latSide2D. When a descending-ascending
condition is met, the curve is detected. The height or z-value corresponding to the
curve is named under and is the undermost boundary we were looking for. In Figure
4.22 this boundary appears around a z-value of 178.
67
Step 2: Define the upper boundary for the z-coordinate
This step is less complex than the previous one. We want the cylinder to approximate
the shaft of the humerus. Logically the shaft ends proximally when the head begins.
This logic is sufficient for determining upper, the upper boundary for the z-coordinate.
We use the results of the extraction of the center of the head of the humerus. The
parameter upper is now defined as the z-value that is rHead smaller than the z-value
of the center of the head, cHead (4.3). In this manner we model the z-value of the
beginning of the head of the humerus and at the end of the shaft of the humerus. This
step is illustrated in Figure 4.23. The blue plane is drawed perpendicular to the z-axis in
the z-value as above stated. In our example, this is at a value of 278 ( = z-coordinate of
cHead (300) – rHead (22)).
Figure 4.23
Step 3: Fit the data between under and upper to a cylinder
We add to fitL those points which z-values that lie between under and upper. Than we
hand over the list fitL to a function that will fit these points to a cylinder. The outcome of
this process are the parameters to define the metaphyseal cylinder.
Figure 4.24 visualizes the oriented right humerus and the metaphyseal cylinder
associated with that humerus in green.
68
Figure 4.24: Anterior, medial view of the right humerus and the metaphyseal cylinder.
69
Chapter 5
The scapula
In this chapter all the functional procedures associated with the scapula are written
down and explained.
The table in the end of Chapter 2 shows that there are 7 features to extract. Each of
these feature extractions will be carried out by a corresponding function. For these
functions to execute without problems, first the bone has to be oriented in an
unambiguous way. Hence there is one more function to perform this orientation
function. The approach is completely parallel to that of the humerus.
Extract inferior angle
Extract superior angle
Extract acromial tip
Orient scapula
Extract acromial angle
Extract tip of coracoid process
Extract root of spine
Extract glenoid labrum
The connection with the GUI follows the same logic as used with the humerus. The
main component responsible for the execution of all of the functions involving the
scapula is the radio button ‘Scapula’ in the panel of the bones. Once pushed this button
first the orientation is executed and further on all of the features are extracted. The user
can now visualize these features on top of the patch object by manipulating the radio
buttons in the panel ‘Features scapula’ containing all the extracted features.
If talked about x-axis, y-axis or z-axis we mean the components of the global
coordinate system as defined in 3.3.
70
We had a total of 13 3D models of scapulas to our disposal to make and test the
functions outlined in this chapter.
This chapter will have the same structure as Chapter 4 and also the code in Matlab®
for every function is provided in Appendix B.3.
5.1
The orientation of the scapula
The idea is the same as for every orientation for every bone. We chose arbitrarily a
reference orientation, with which the feature extractions can be done in a uniform way.
After the necessary linear translations and rotations of the 3D model of the bone, its
side is detected and mirrored, if needed, to its right counterpart. For the subsequent
visualization of the bone and its features, all of this has to be mirrored again, with
respect to the same plane, in order to get the bone’s original side.
The intended final orientation can be seen in Figure 5.1 and 5.2. In this orientation the
bone of the right arm is aligned around the z-axis from above to below. Because of the
approximated triangular shape of the scapula, our aim is to get the plane of this
‘triangle’ to concede with the x-z plane. Ultimately the anterior aspect of the scapula will
be oriented towards the positive y-axis.
The function used to carry out this obligatory initial orientation is called orientScapula.
[x2, y2, z2, n2, ext1, ext2, side] = orientScapula(x1, y1, z1, n1)
The input and output arguments are almost the same as for the orientation function of
the humerus, orientHum of 4.1. The only difference is the presence of the two
variables ext1 and ext2. What those are is explained below.
Matrix n1 of the normals is also an input argument, because it has to undergo all the
same transformations to keep the normals consistent with the transformed facets of the
3D model. This is necessary to carry out the curvature calculation.
71
Figure 5.1
Left: Posterior view of the oriented right scapula. The bone is looked at from the negative y-axis.
Right: Lateral view of the oriented right scapula. The bone is looked at from the positive x-axis.
Figure 5.2
Superior view of the oriented right scapula. The bone is looked at from the positive z-axis.
72
Throughout the following steps we will orient the bone as given in Figure 5.3. As will be
noticed, this bone is a left sided one and its orientation in space is completely random.
Figure 5.3
Step 1: Make the list representation of the input 3D model
The list is called L.
Step 2: Define a translation based on the mean of L
This mean, meanL, is nothing more than the mean of the x-, y- and z-values of the
points in L. Once obtained meanL, a translation of all the points of L must take place.
The mean point coincides now with the origin of the global reference system. This is
showed in Figure 5.4. meanL is represented by the blue marker.
73
Step 3: Get for each point in L its norm, i.e. the Euclidean distance to the origin
and select the point with the biggest norm
The point with the biggest norm is for every regular scapula irrespective to its shape
and size the inferior angle. This is the conclusion of the observation and testing with
normal scapulas. In not one case we found an exception.
We call this point that has the maximum norm maxNorm. In Figure 5.4 this is
represented by the yellow marker.
Figure 5.4: meanX in blue. maxNorm in yellow.
Step 4: Do a sequence of rotations of the bone in order to get point maxNorm
to lie on z-axis
The sequence of rotations talked about is one rotation around the z-axis to get
maxNorm in the x-z plane, and one rotation around the y-axis to get maxNorm onto
the z-axis.
74
The purpose of this step is to get the scapula aligned along the z-axis. This step will
fulfill this purpose, but it is possible that the bone lies upside down now, like in Figure
5.5. Because the rotations only rotate around angles smaller then 90 degrees, this
occurs when maxNorm has originally a z-value that is bigger than zero.
As with all rotations, the normals in n1 have to be rotated too.
Figure 5.5: The 3D model of the scapula lies upside down with respect to the z-axis.
Step 5: Do subsequent transformations to get the so far oriented bone to stand in an
upright position in the space defined by the positive x-axis
The bone by now has a part above the x-y plane and also below this plane, and it is
possibly upside down oriented (like in Figure 5.5). The purpose of this step is to correct
the possible upside down position and to force the bone to lie above the x-y plane.
First a translation defined by maxNorm is executed, this is a translation in the direction
of the z-axis. The point maxNorm forms now the origin of 3D space.
75
If the bone lies upside down, like in Figure 5.6, a supplementary rotation of 180
degrees around the x- or the y-axis is needed. The 3D model of the bone after this
possible rotation has the correct up down orientation along the z-axis and all the points
have z-values bigger than 0. Figure 5.7 proves this.
Figure 5.6
Figure 5.7
Step 6: Make the triangular plane concede with the x-z plane of 3D space
This step only involves rotations around the z-axis, because the up down orientation
already is completed.
The logic of this step is based mainly on the specific shape of the scapula. First thing to
do is to make a list of all the points that lie above the half of the longitudinal length of
the scapula, that is along the z-axis. Thus with a z-value bigger than 50% this length.
This list of points, say upperL, is used as input data to a principal component analysis.
In Step 2 of 4.1 this procedure is explained extensively. The analysis will yield a
principal component axis for the data in upperL. Because of the specific shape of the
upper half of a regular scapula, this axis will have for each and every bone more or less
a same direction. It will go from the medial side upwards to the lateral side of the
scapula where it ends between the acromion and the coracoid process. Each point of
76
upperL has a score with respect to this principal component axis. The points of upperL
which have the maximal and minimal scores (projections), the extreme points, will be
selected and used throughout the extent of Step 6. These points are called ext1 and
ext2. In Figure 5.8 these points are drawn as respectively the blue and the red marker.
Figure 5.8
For now you can’t be sure which one lies on the lateral side and which one lies on the
medial side. A simple comparison of their z-values will solve this uncertainty as the
extreme point on the lateral side is always situated higher in space than the one on the
medial side. In Figure 5.8 the blue marker will represent the extreme point on the lateral
side because it has a bigger z-value than the medial extreme point in red.
The extreme point on the lateral side is named extLat and the extreme point on the
medial side receives the name extMed. Now a rotation around the z-axis is needed
which will force extLat into the x-z plane with an x-value that is bigger than 0. Possibly
a second rotation is needed if extLat has a negative x-value after the first rotation. As
always a rotation of 180 degrees gives the solution. Figure 5.9 shows that extLat (blue)
77
has a negative x-value in 5.10 this is compensated through a rotation over 180 degrees
around the z-axis.
Figure 5.9
Figure 5.10
As a reminder: the matrix of normals n1 must undergo all the same rotations for it will
be used in the curvature calculation.
Step 7: Determine whether it is a bone of the right or a bone of the left arm
This determination will be made possible by the current orientation of the bone as
shown in Figure 5.10 and by observing the medial border of the scapula in this
orientation. We isolate a small part of points above the medial extreme point, extMed,
the red marker in Figures 5.8-5.11. This set of points, say borderL, must contain for
sure all the points on the medial border above extMed. Because we know that the
medial border makes a curve towards the anterior side if we follow the border upwards,
we can determine the side of the bone by comparing the y-value of extMed with the yvalue of the point with the biggest z-value in borderL, the purple marker in Figure 5.11.
For a right scapula the y-value of extMed is smaller because the anterior aspect points
to the positive y-axis. So in the case the y-value of extMed is bigger, you can be sure it
will be a left scapula. In Figure 5.11 the latter situation takes place, so we can now be
sure about the left handed side of the 3D model we used to visualize the procedure.
78
Figure 5.11: extMed in red and the highest point of borderL in purple.
Step 8: In case of a scapula of a left arm, transform it to its right sided
counterpart
The procedure in this step is the same as in Step 9 of 4.1.
The specification of the side must be given back as output argument. It is called side
and it is a logical. If side equals 1, the processed bone is a left one. In the visualization
process it will be used to determine whether the bone should be mirrored before
visualization. Comparing Figure 5.11 with Figure 5.12 makes clear the mirroring has
taken place with respect to the x-z plane.
Figure 5.12
79
The intended orientation (and position) is reached and now this 3D model will be given
to the feature extraction functions. This can be in the form of a patch representation of
the oriented bone or as a list representation. This depends on the receiving function.
At last the finalizing remark on the end of 4.1 must also be taken into account here.
5.2
Extraction of the inferior angle
This procedure serves to localize the inferior angle. This is where the medial and the
lateral border meet each other.
As it would be a tedious task to find it in a random oriented bone, it is an easy
procedure in the oriented bone that we have at our disposal. It is nothing more than the
origin (0, 0, 0).
To keep things uniform we preferred to write a function for this feature too.
[infAng] = infAngleScap(L)
The output argument is the position of the inferior angle onto the oriented scapula. The
input argument is list L of the points of the oriented bone.
The function searches for the point in L with the smallest z-value and this is logically
the point in the origin. For a visualization the reader is referred to Figure 5.7.
The real logic for finding this inferior angle must be found in 5.1. There the inferior
angle can be found under the name maxNorm. In 5.1 maxNorm wasn’t associated to
the inferior angle yet to not confuse the reader.
The position of the inferior angle corresponds in all cases to the definition of the
position of the inferior angle in [1].
5.3
Extraction of the superior angle
Here we look for the superior angle of the scapula. This is the angle where the medial
and the superior border meet each other.
The function developed to do the extraction of the superior angle is called
supAngleScap.
80
[supAng] = supAngleScap(L, extMed, extLat)
The output argument is the position of the superior angle onto the oriented right
scapula. The input argument is list L of the points of the oriented 3D model together
with the two extreme points, extMed and extLat, as defined in 5.1.
The method uses the relative positions of the points to our disposal, these are extMed
and extLat. Through observation it becomes clear that the superior angle in its
neighborhood is the point with the biggest orthogonal distance to the line between
extMed and extLat. We take advantage of this finding to perform the feature analysis
of the superior angle.
Step 1: Define the search space in which to look for the superior angle
This type of procedure already is commented in Chapter 4.
The conditions to which the coordinates of each point in L are tested are:
-The x-coordinate has to be smaller than 0.6 * x-value of extMed -> targeting the
medial side
-The y-coordinate has to be bigger than 0 -> targeting the anterior aspect
-The z-coordinate must be bigger than max(all z-coordinates) * 0.5 -> targeting
the superior aspect
If for one point all these conditions are met, the point becomes a member of search
space S.
In this space, S, the superior angle is to be searched. Figure 5.13 shows the points of
this search space on top of the 3D model of the oriented scapula in yellow.
The specification of these conditions is based on observations of the 13 3D models of
oriented scapulas and pure logic.
81
Step 2: Calculate for each point in S the orthogonal distance to the line defined
by extMed and extLat
The result of this step is a list of orthogonal distances to the line between extMed and
extLat. In Figure 5.13 the line between extMed and extLat is showed as the blue line
between the two extreme points represented by blue dots, extMed and extLat.
Figure 5.13
Step 3: Select the point in S that has the biggest distance to the former defined
line
This point represents the position of the superior angle onto the processed scapula. In
Figure 5.13 on the right side, the position of the extracted superior angle is represented
by a red marker.
82
5.4
Extraction of the tip of the acromion
In [1] the commonly used technique for palpating this feature is defined. It is the most
lateral and anterior part of the tip of the acromion as seen from a superior view. Figure
5.14 clarifies.
The ‘tip of the acromion’ can have two meanings, or the feature we will extract or the
set of points representing the anterior ending part of the acromion, where it articulates
with the clavicle. In the following text these two will be used, but the difference will be
clear.
Figure 5.14: Superior view. The black circle situates the tip of the acromion.
In this paragraph the algorithm of the function responsible for localizing this feature is
described. The use of the function is as follows:
[acrTip] = acromialTipScap(x, y, z, n, extMed)
The output argument is the position of the tip of the acromion onto the oriented right
scapula, acrTip.
The input arguments are firstly the 3 matrices x, y, and z defining the 3D model of the
scapula as a patch object, and thus holding the connectivity information. Secondly n,
the matrix of the normals to the facets of the patch object of the scapula, is an input
argument. The last input argument is extMed, the position of the medial extreme point
as defined by the function orientScapula in 5.1.
83
The procedure can be summarized as isolating the acromion and subsequently
selecting the most lateral point of the tip (not the feature) of the acromion.
Step 1: Locate and isolate a part of the bone that with certainty contains the
acromion, this will be referred to as the search space S
We chose as boundaries for this part:
-the x-coordinates have to be bigger than 0.50 * max(all x-coordinates) ->
the lateral side.
-the z-coordinate has to be bigger than the z-coordinate of input argument
extMed. -> the points have to be localized higher than extMed.
The boundaries are chosen by trial and error on the 13 3D models in order to get with
certainty the part that contains the acromion.
The defined list of points is visualized in Figure 5.15 as the yellow points.
Figure 5.15: The list of points that contains the acromion. Of these points the neighbors are defined.
Step 2: Define for every vertex of S its neighboring vertices
The purpose of this step is its future use in Step 5. The result of this step is a list in
which every row holds the position of the point and all the positions of its neighbouring
points. The rows in this list can therefore be of different lengths because each vertex
doesn’t have the same number of neighbors. This list is called V.
84
As well we could have calculated the neighbors for every point of the 3D model, but this
calculation is very time consuming and therefore we preferred to do this only for that
part where the acromial tip with certainty resides.
Step 3: Select the most superior point of S
Practically this is the point of S with the biggest z-value. We call this point p. p is
in all cases a point of the acromion.
Step 4: Initialize an empty list and add p to it
We call this list Lacromion. We want to expand this list with the neighbors of p and
with the neighbors of the neighbors of p and so on. This will give us exactly the points
of the anterior part of the acromion because the starting point p is a point of the
acromion. We have to use this approach as result of the position of the acromion onto
the scapula. It is not possible to isolate the acromion just by defining boundaries and
making the points lie between those boundaries.
In the following step this iterative process of adding neighbors to Lacromion is
explained better.
Step 5: Cycle through Lacromion in an iterative manner and calculate of every
point in Lacromion its neighboring points and append them to Lacromion
This continuous adding of new points to Lacromion must stop at a certain point to not
include all the points of the bone to Lacromion. Hence a stop condition is defined: if a
new candidate point for Lacromion has a z-value smaller than 17/18 max(all zcoordinates), than stop extending the list. The choice for the value 17/18 in the stop
condition is the result of doing the trial and error technique for the 13 3D models. This
value gives the best result in obtaining the tip of the acromion. The difficulty of defining
this value was the varying steepness of the acromion, i.e. the angle between the
acromion and the x-y plane.
Once the stop condition is met, Lacromion is complete and will contain for sure the
most superior and anterior points of the acromion. Figure 5.16 gives the outcome of
this step, the set of red points
85
Figure 5.16
This seems a very complex way just to define the acromion, but with this technique you
can be sure of the result. We tried for example the following simple approach: take
those points that have a z-value bigger than the z-coordinate of extLat. It worked for
the majority of scapulas, but in some scapulas it introduced points outside of the
acromion to the list, because of the variance in acromion shapes.
With our method this uncertainty is avoided and it yields always the correct points for
the acromion.
Step 6: Look for the part of Lacromion that represents the anterior ending part of
the acromion and select of this anterior end the most lateral point.
First we refine Lacromion in such a manner only the points real close to the tip of the
acromion are chosen. This is done by looking for the most anterior points of
Lacromion. Hence we look in Lacromion for points with a big y-value. Of this refined
version of Lacromion we look for the most lateral point, hence the point with the
biggest x-coordinate.
86
The result of this step is the position of the feature we were looking for, the ‘tip of the
acromion’. The refined Lacromion (blue) together with the extracted feature (red
spherical marker) are shown in Figure 5.17.
Figure 5.17
5.5
Extraction of the acromial angle
In this paragraph the extraction of the acromial angle is outlined. The exact definition of
the position of this feature is given in [1]. It is the posterior angle between the spine of
the scapula and the acromion. Figure 5.18 shows the position of the acromial angle.
87
Figure 5.18: The black circle specifies the position of the acromial angle. The red circle the position of
the tip of the coracoid process.
The function to select the acromial angle:
[acrAngle] = acrAngleScap(x, y, z, n)
The output argument is the position of the acromial angle onto the oriented right
scapula, acrAngle.
The input arguments are firstly the 3 matrices x, y, and z defining the 3D model of the
scapula as a patch object, and thus holding the connectivity information. Secondly
there is n, the matrix of the normals to the facets of the patch object of the scapula.
The procedure comes down to isolating the set of points representing the rough angle
of the acromion and examining the mean curvature of all the points of this rough angle.
The point with the smallest mean curvature is selected as the acromial angle
subsequently.
Step 1: Define a search space in which to look for the acromial angle
This list is constructed by testing each point of the oriented right scapula to predefined
well chosen conditions.
88
-The x-coordinate has to be bigger than 0.5 * max(all x-coordinates). This is
in
other words the 25% most lateral part of the scapula.
-And at the same time the y-coordinate has to be smaller than 0.75 *
min(all y-coordinates). This means that we take into account only the
12.5% most posterior part of the bone.
The obtained space is called S.
Step 2: Calculate for each point in S its mean curvature and select the points
with the smallest mean curvatures
This step is carried out by handing over the patch representation of S to the function
calculateCurvature explained in Chapter 3 and outlined in Appendix D. This yields the
combination of each point with its associated mean curvature value. As explained in
Chapter 3 negative values of the curvature correspond to convex curvature and
positive values to concave curvatures. We are interested in the convex points in S, so
we select the 5% of points with the smallest associated mean curvatures. We call this
list Smin. Next we calculate of Smin its mean point, Smean. Figure 5.19 visualizes the
patch representation of S with on top of it in yellow the points of Smin representing the
5% of points with the smallest mean curvature values. As expected, the points of Smin
lie in the blue area which manifests convexity. This can be seen in the colorbar on the
right, where the blue color corresponds to negative values for the mean curvature.
Step 3: Calculate the point of Smin with the smallest distance to Smean
Smean is probably not a point of the list Smin and thus of the model of the bone. To
end up with a point of the Smin we select that point with the smallest distance to the
above calculated mean point, Smean. This point is the acromial angle as shown in
Figure 5.20.
89
Figure 5.19: The representation of the angle together wit the mean curvature information.
Figure 5.20
90
It might be odd not to specify that point with the minimal mean curvature value as the
acromial angle. However during the testing phase this point was seldom in the
proximity of the wanted position. The points of Smin were distributed in the
neighborhood of the acromial angle. That is why we decided to take the mean of Smin.
5.6
Extraction of the tip of the coracoid process
In this paragraph the extraction of the tip of the coracoid process is described. The
exact definition of the position of this feature is given in [1]. It is the very tip of the
coracoid process. The red circle in Figure 5.18 marks the lateral end of the coracoid
process where the feature resides as the most lateral point.
The use of the function carrying out this feature extraction is:
[corTip] = corTipScap(x, y, z, n, extMed)
The output argument is the position of the tip of the coracoid process onto the oriented
right scapula.
The input arguments are firstly the 3 matrices x, y, and z defining the 3D model of the
scapula as a patch object, and thus holding the connectivity information. Secondly
there is n, the matrix of the normals to the facets of 3D model of the scapula.
The procedure can be summarized as isolating the entire tip of the coracoid process
and subsequently selecting the most lateral point of this tip.
Step 1: Locate and isolate a part of the bone that with certainty contains the
coracoid process, this will be referred to as the search space S
The purpose of this step is to save time in Step 2.
We specify S by testing all of the points of the scapula to well chosen conditions. S
must contain all of the points of the coracoid process. Hence these conditions are:
-The x-coordinate has to be part of the 25% most lateral part
-The y-coordinate has to be bigger than 0
If all these conditions are fulfilled by the coordinates of a point, the point will be added
to S.
91
Step 2: Calculate for every point of S its neighboring points
This step will yield for every point of S a list of its neighboring points. All this information
is stocked in V. This will be used in Step 3.
Now the purpose of Step 1 becomes clear. As the neighbor calculating process is a
time consuming procedure and as the neighbor information is only needed for the
roughly approximated coracoid process, we decided to hand over only a selected part
of the bone to the neighbor calculating function.
Step 3: Select the most anterior point of S
This point is denominated p and this is without exception a point of the coracoid
process.
Step 4: Initialize an empty list, Lcoracoid, and add p to it
The purpose of Lcoracoid is to populate it with points belonging to the real coracoid
process. If in the end we would depict this list, it will represent the coracoid process.
In the following steps we will try to get all the points of the coracoid process by starting
with p, a certain point of the coracoid process, and including every neighbor of p to
Lcoracoid.
Of all these points in Lcoracoid we include also their neighbors to Lcoracoid. We
will repeat this including of neighbors until a certain condition is met.
This seems a very complex way to just define the coracoid process, but with this
technique you can be sure of the correctness of the result, irrespective to the shape of
the processed scapula.
92
Step 5: Do the iterative process explained in the previous step until the stop
condition is met
The stop condition is defined by a trial and error process. Ultimately the stop condition
used in our code leads to the involvement of the correct points to Lcoracoid, without
adding too many points to it.
The stop condition is: if a new candidate point has an y-value smaller than 5/8 of the
max(all y-coordinates of S), than stop extending the list. This comes down to the fact
that we have reached more or less the base of the coracoid process.
By now we have isolated the coracoid process, and its points belong to the list
Lcoracoid.
In Figure 5.21 S is represented by the yellow points and Lcoracoid by the red points.
We see clearly the refining process that S underwent.
Figure 5.21
93
Step 6: Look for the most lateral part of the coracoid process and select the
midpoint of it
In this step of the algorithm all the points of Lcoracoid are sorted with a descending xcoordinate value, from big x-value to small x-value.
Of this list only the fifth with biggest x-values will stay for further processing. This will be
more or less the lateral end surface of the coracoid process and is called,
LcoracoidTip. The points of LcoracoidTip are represented by the blue markers in
Figure 5.22.
Figure 5.22
Subsequently the mean of all the points of LcoracoidTip is calculated. This mean is
probably not a point of the list LcoracoidTip and thus of the 3D model of the bone. To
end with a point of the bone we calculate the point with the smallest distance to the
above calculated mean point. This point is the tip of the coracoid process, the feature
we were looking for. Examining Figure 5.22, this is represented by the red marker.
5.7
Extraction of the root of the spine
In this paragraph the extraction of the root of the scapula spine is described. The exact
definition of the position of this feature is given in [1]. The root is located next to the
medial edge of the scapula. Because of its triangular shape and the fact that we will
94
only extract one position, the root of the spine is defined as the most lateral apex of this
triangle
The use of the function carrying out this feature extraction is:
[trigSpin] = trigSpinScap(x, y, z, n, extMed)
The output argument is the position of the root of the spine onto the oriented right
scapula.
The input arguments are firstly the 3 matrices x, y, and z defining the 3D model of the
scapula as a patch object, and thus holding the connectivity information. Secondly
there is n, the matrix of the normals to the facets of the patch representation of the
scapula. And as last input argument there is extMed, the medial extreme point defined
in the function orientScapula, in 5.1.
To summarize, the technique used comes down to isolating the right part of the
oriented right scapula, calculating the mean curvature of the points of this region and,
based on this curvature, selecting in a unified way the root of the spine.
Step 1: Locate and isolate a region of the bone that with certainty contains the
root of the spine, this will be referred to as the search space S
Again this step involves defining boundary conditions and testing each point of the
bone to them. Only the points that fulfill the conditions will be added to S.
The purpose of this step is to speed up the curvature calculating procedure of
step 2.
Step 2: Calculate for each point of S the mean curvature
The result of this step is a list of points and its associated list of mean curvatures. We
are interested in the small mean curvatures, because we want to detect convexity.
Thus only 5% of S with the smallest mean curvatures is conserved after this step. We
call this thinned out list Smin and it will contain with certainty the root of the spine
because it is a convex curved feature. In Figure 5.23 this list of points, Smin, is
depicted in yellow.
95
Figure 5.23
Step 3: Calculate the Euclidean distances of each point in Smin to the mean of Smin
This mean point is called SminMean. The root of the spine will be located close to this
point, because it lies by definition in a region that exhibits a lot of convex curvature.
This means that most of the points of Smin are located in this region and hence the
mean of Smin.
The list of distances is named d.
Step 4: Select only the points of Smin with small distances to SminMean
as possible candidates for the searched feature
For this step we calculate the mean of d, dmean, and we take only into account those
points of Smin with a smaller distance to SminMean than dmean. The also become
list is referred to as Smin2.
A zoom version of Figure 5.23 yields Figure 5.24,
SminMean is the purple sphere and the blue dots are the points of Smin2 .
96
Figure 5.24
This step excludes the possibility of picking a point outside the region of the root of the
spine as the root of the spine.
Step 5: Select the most medial point of Smin2
This point will be the root of the spine.
Observing Figure 5.24 makes clear this point is the most medial blue point, i.e. the
point on the left (because we are looking at the posterior surface of a right scapula).
This last step is based on observation of the set Smin2 throughout the testing process
of the function with each model of the 13 scapula. And this step is justified because we
are looking for the base of the spine and this is the most medial point of the spine. The
spine holds points that exhibit convexity and therefore are contained in Smin2. So if we
just picked the point with the biggest convexity, this would have a great probability of
being a point of the spine. And we are not looking for a point of the spine, but for its
root.
In Figure 5.25 the comparison between SminMean in purple and the extracted root of
the spine in red, is made.
97
Figure 5.25
5.8
Extraction of the glenoid cavity
With ‘extraction of the glenoid cavity’ is defined the representation of the undermost
half of the points on the edge of the glenoid cavity by a 3D circle. In this section the
algorithm of doing this extraction is described. This feature is not defined in [1].
[glenoidC glenoidR glenoidN] = glenoidScap(x, y, z, n, corTip)
The output arguments are the 3 parameters that are needed to define a 3D circle in
space. Those are the center, the radius and the normal to the plane of the 3D circle.
The input arguments are firstly the 3 matrices x, y, and z defining the oriented 3D
model of a scapula as a patch object, and thus holding the connectivity information.
Secondly there is n, the matrix of the normals to the facets of the patch representation
of the scapula. The last input argument is the representation of the position of the tip of
the coracoid process as extracted in 5.6.
98
The followed procedure consists of two least square fittings to a 3D circle. The first is
given an input list of points that roughly approximates a part of the points of the glenoid
cavity. The second fitting phase will work with a refined list of points that is defined with
the help of the results of the first fitting phase. This second input list of points will
contain for a regular, well formed scapula only points of the undermost part of the
glenoid cavity.
Step 1: Locate and isolate the points of the bone that will be given as input
arguments to a function that will carry out the first fitting to a 3D circle
In this step we will start with a big region of the bone that for sure contains the glenoid
cavity. Step by step points will be discarded from this region and ultimately a list of
points that roughly approximate the points of the glenoid cavity will survive.
The first difficulty is to locate in a uniform manner the position of a point of the glenoid
cavity. This is countered by taking all the points of the lateral side of the scapula and
calculating for each point the distance to the tip of the coracoid process. The list of
distances is called d. If you look to a scapula (that is oriented by the procedure in 5.1)
from above (from the direction of the positive z-axis) you will see that the coracoid
process is the part where the biggest y-values reside. Below this, if you follow the yaxis, there is a gap before reaching the glenoid cavity. This finding can also be seen in
d (if sorted from small to big). First you have a part of small distances that vary very
little. These distances are corresponding to points of the coracoid process. Somewhere
in d there will be an obvious gap between two distances. This is the manifestation of
the gap between the coracoid process and the glenoid cavity. So the biggest distance
of the two elements of d defining the gap will be associated to a point of the glenoid
cavity. Following this technique gives back unambiguously a correct point of the glenoid
cavity.
Step 2: Preparing the input list for the first fitting phase
Once we have the point, say gPoint, we will use this to isolate a part of the glenoid
cavity. For this selected part, say fitL, we will calculate the mean curvature in each
point. Because the glenoid labrum is a convex ridge, we than use only the 20% of
99
points of fitL with the smallest mean curvatures. This list of points, say fitL1, is refined
once again and than given as input to the least square fitting function. In Figure 5.26
the points of fitL1 are plotted in red.
Step 3: Do the fitting of fitL1 to a 3D circle
This will produce the center, the radius and the normal to the plane of the fitted 3D
circle. If we plot the 3D circle onto the scapula and we also depict the points in fitL1,
we see that a reasonable amount of points lies significant far away of the calculated
circle and hence does not belong to the undermost part of the glenoid cavity. This
means they had a negative influence on the result of the fitting procedure. That’s why
we do a second fitting phase with a list of points from which the polluting outliers are
removed. The technique of removing these outliers is described in Step 4 of 4.6 about
extracting the edge of the trochlea of the humerus. Another condition is that the points
must lie under the calculated center of the 3D circle.
This improved list is called fitL2.
Step 4: Do the fitting of fitL2 to a 3D circle
This will produce the center, the radius and the normal to the plane of the fitted 3D
circle representing the undermost part of the glenoid cavity.
Figure 5.26 illustrates the critical parameters used in the procedure. The big red marker
represents gPoint. The red dots are the points contained in fitL1. The blue dots are the
points of fitL2 that are used to fit the eventual 3D circle that represents the glenoid
cavity. The circle is drawed in blue.
100
Figure 5.26
101
Chapter 6
The clavicle
In this chapter the functional processes with respect to the clavicle are explained.
These processes are: the function responsible for the unambiguous orientation, and
two extraction functions.
Orient clavicle
Extract most anterior
point on the
sternoclavicular joint
surface
Extract most posterior
point on the
acromioclavicular joint
surface
The rest of this chapter is constructed in the same manner as the 2 previous chapters.
The functions, corresponding to the procedures as stated in the flowchart, are
described one by one starting with the description of the orientation procedure. The
exact method of working can be found in the end of the introduction of Chapter 4.
Throughout the developing and testing process of the 3 functions we had at our
disposal a total of 13 3D models of clavicles represented by binary Stl files. This was
an even mix of right and left clavicles.
In appendix B.4 you can find the code as written in Matlab®.
6.1 The orientation of the clavicle
We chose arbitrarily a reference orientation, with which the feature extractions can be
done in a uniform way. After the necessary translations and rotations of the bone, its
side (left or right) is detected and mirrored, if needed, to its right counterpart. This to
102
facilitate the developing of the subsequent extraction functions as they only have to
take into account right bones.
For subsequent visualization purposes, this artificial right clavicle has to be mirrored
again to its original left state.
The chosen orientation depicts the right sided clavicle in its position like in the human
body. Its prominent length is aligned along the x-axis. Its real superior surface points
towards the positive z-axis. So the ‘plane’ of the clavicle lies more or less in the x-y
plane. The anterior aspect is oriented towards the negative y-axis. As a result of all this
the medial end will lie onto the positive x-axis.
In Figure 6.1 this reference orientation is clarified.
Figure 6.1
Above: Superior view of the oriented right clavicle. The bone is looked at from the positive z-axis.
Middle: Anterior view of the oriented right clavicle. The bone is looked at from the negative y-axis.
Below: Lateral view of the oriented right clavicle. The bone is looked at from the negative x-axis.
103
The function used is called orientClavicle.
[x2, y2, z2, n2, side] = orientClavicle(x1, y1, z1, n1)
The input and output arguments are almost the same as for the orientation function of
the humerus and the scapula. The only difference is the absence of supplementary
output arguments for future use. Side will specify in the end whether the processed
bone was a right or a left one.
Matrix n1 of the normals is also an input argument, because it has to undergo all the
same transformations to keep the normals consistent with the facets of the patch
object.
Figure 6.2 Complete random orientation of a left clavicle
In Figure 6.2 the orientation is given of a 3D model that we will use in the following
steps to illustrate the orientation to the above stated reference orientation. The 3D
model is of a left clavicle and is situated completely random in 3D space.
Step 1: Define the prominent direction in the oriented clavicle
This is executed by a principal component analysis as explained in previous chapters.
The result of this analysis is the principal component axis and the two extreme points
on it, ext1 and ext2. By now it is not yet clear which extreme point is situated on the
proximal (medial) end and which on the distal (lateral) end.
The patch object representation is now also transformed in a list of points, L.
104
Step 2: Define a translation based on the mean of L
This mean, meanL, is nothing more than the mean of the x-, y- and z-values of the
points in L. Once obtained meanL, a translation of all the points of L must take place.
The mean point coincides now with the origin of the global coordinate system.
Figure 6.3
In Figure 6.3 the two extremes, ext1 and ext2, are drawed in yellow and meanL is
represented by the blue marker. The translation is already carried out, because meanL
coincides with the origin of the coordinate system.
Step 3: Do a sequence of rotations of the bone in order to get point ext2 to lie
onto the positive x-axis
The sequence of rotations talked about is one rotation around the z-axis to get ext2 in
the x-z plane, and one rotation around the y-axis to get ext2 onto the positive x-axis.
The choice of ext2 rather than for ext1 is arbitrary.
The resulting orientation of this step is shown in Figure 6.4. As can be noticed, ext2
corresponded to the lateral end of the clavicle, because its position is situated on the
positive x-axis by now.
105
Figure 6.4 View from the negative y-axis.
The only purpose of this step is to get the principal axis of the clavicle aligned with the
x-axis. Nothing more can be said about the orientation by now.
The rotations have to be carried out to n1 too.
Step 4: Do a rotation around the x-axis in order to get the ‘plane’ of the clavicle
to lie in the x-y plane
If we talk about the ‘plane’ of the clavicle we reference to the flattened part of the
clavicle in the middle part of the bone. Through observation of 13 3D models of
clavicles, we picked the middle 40 % of the bone in its longest dimension, i.e. along the
x-axis. This part, represented by M, exhibits this flattened structure. If we rotate M
around the x-axis in intervals of beta degrees, and calculate for each outcome position
the distance between the maximal y-value and the minimal y-value, we can decide over
which angle M has to be rotated to get it in the x-y plane. This angle, say alpha, will be
determined by the biggest y-distance. Use alpha to carry out the rotation around the xaxis of the entire bone. Figure 6.5 visualizes the outcome position of this step.
Figure 6.5
106
Step 5: Determine which end is the medial end and get it onto the positive x-axis
The logic behind this step originates again from the observation of the 13 clavicles we
worked with. It was obvious that in the orientation we now have reached, the lateral
part of the middle part M has a bigger y-distance (maximum y-value – minimal y-value).
So we compare the two y-distances of the two parts (points of M with positive x-values
and points of M with negative x-values) of M and we denominate the part with the
smallest y-distance as being the medial part. If this part is the one of the negative xaxis, a rotation around the z-axis of 180 degrees is needed.
In Figure 6.5 it can be seen that the medial part lies onto the negative x-axis, so a
rotation will be needed. The outcome of this rotation is depicted below in Figure 6.6.
Figure 6.6
Step 6: Look for the curve in the lateral part
The clavicle exhibits an S-shape, if we look to it from a superior view, like e.g. in Figure
6.6. So it has also two curves. One curve in the medial part and one curve in the lateral
part. We will focus in this step on the lateral part. The curve can lie in the half with
positive y-values or in the other half, with negative y-values. Purpose of this step is just
determining where the curve is situated. This is done by comparing the maximal and
minimal y-value of the middle part of the lateral half (x-coordinate smaller than 0).
The logical which will hold this information is latCurv. In step 8 its purpose will be clear.
If latCurv equals 1, the curve lies in the positive y-space. If 0, the curve lies in the
negative y-space. (respectively above and below the x-z plane with respect to
ascending y values).
The situation in Figure 6.6 will yield 1 for latCurv, because the curve is positioned
above the x-z plane.
107
Step 7: Determine whether the superior surface points upwards
It comes down to detecting the conoid tubercle. This tubercle lies on the inferior surface
of the clavicle. So if we can detect (more or less) this tubercle and compare its z-value
with the mean z-value, meanZ, of the set of points amongst we looked for the conoid
tubercle, we can say whether the inferior surface points upwards or downwards. It
points downwards if the tubercle has a smaller z-value than meanZ. If the inferior
surface points downwards, by logic the superior surface points upwards.
The logical that specifies whether the superior surface points upwards is called natural.
This name refers to the natural position of the clavicle, that is with its superior surface
pointing upwards. Its purpose will be explained in the next step.
Figure 6.7 shows for our example the approximation of the conoid tubercle in green.
The set of points in which we looked for the conoid tubercle are plotted in purple.
Figure 6.7
As will be clear, the approximation of the conoid tubercle drawed in the above figure
has a bigger z-coordinate than the mean of all the points in which we looked for the
conoid tubercle. These points are depicted in purple.
Conclusion: natural equals 0.
108
Step 8: Determine the side of the clavicle and do the necessary transformations
to get the orientation as wanted
We use the two decision makers of Steps 6 and 7, latCurv and natural, to be sure of
the side of the processed bone and to finalize the orientation.
We have 2 logicals, that can take on two values so if we combine them we have a total
of 4 different combinations.
1 latCurv==1 AND natural==1
The curve in the lateral part lies in the part of the positive y-axis. And the bone
has its natural up down orientation. So we can decide that the bone is a right
one and it is oriented well.
2 latCurv==1 AND natural==0
The curve in the lateral part lies in the part of the positive y-axis. And the bone’s
superior surface points downwards. So we can conclude that the bone is a left
one. The only thing to do now is to mirror the entire bone with respect to the x-y
plane. By this operation we get a right bone and the up down orientation
becomes correct.
3 latCurv==0 AND natural==1
The curve in the lateral part lies in the part of the negative y-axis. And the bone
has its natural up down orientation. So we can decide that the bone is a left one.
While the up down orientation is good, the only thing to do is to mirror the bone
with respect to the x-z plane. We get a right sided bone, and the curve in the
lateral part will be situated in its correct position.
4 latCurv==0 AND natural==0
The curve in the lateral part lies in the part of the negative y-axis. And the bone’s
up down orientation is incorrect. So we can decide that the bone is a right one
and it’s superior surface is faulty oriented. The only thing to do now is to execute
109
a rotation around the x-axis of 180 degrees to get it in its correct place. Mirroring
is useless because it already is a right bone.
The orientation is ready now.
The parameters latCurv and natural for the example are respectively 1 and 0. So as
the ultimate transformation the operation of alternative 2 has to be carried out. The
outcome orientation will be the intended one like in Figure 5.1.
At last the finalizing remark on the end of 4.1 must also be taken into account here.
6.2
Extraction of the anterior sternoclavicular joint
This feature is the midpoint on the anterior edge of the sternoclavicular joint surface.
We will refer to this feature as the sternoclavicular joint. It will be localized as defined in
[1].
The function sternClav will execute the process of locating the mentioned feature.
[sternClav] = sternClav(L)
The output argument is the position of the point we defined as the sternoclavicular joint.
The input argument L is the list of the points of the entire oriented right clavicle.
The orientation of the bone as done in 3.1 will make this task straightforward as
isolating the medial end of the clavicle and selecting in this set of points the most
anterior one.
This is carried out by selecting the points with an x-value that is bigger than 95% the
maximal x-value in the current orientation, and searching in this selection the point with
the smallest y-value. The last step because the anterior aspect of the oriented right
clavicle points without exception towards the negative y-axis.
In Figure 6.8 this feature is represented by the blue marker.
110
6.3
Extraction of the posterior acromioclavicular joint
This feature is the most posterior point on the acromioclavicular joint surface; the
surface of the clavicle that will articulate with the acromion of the scapula laterally. The
feature will be localized as defined in [1].
We will refer to this feature as the acromioclavicular joint.
This feature extraction is executed by:
[acrClav] = acrClav(L)
The output argument is the position of the point we defined as the acromioclavicular
joint. The input argument L is the list of the points of the entire oriented right clavicle.
This extraction will come down to selecting the most lateral point in the current
orientation of the bone. This is in other words the point with the smallest x-value of all
the points of the 3D model of the clavicle.
The feature is depicted in Figure 6.8 as the red marker.
Figure 6.8: Anterior and slightly lateral view of the oriented right clavicle. In blue the sternoclavicular
joint. In red the acromioclavicular joint.
111
Chapter 7
The ulna
The ulna is located on the medial aspect of the forearm of the human body.
In this chapter the functions associated with the ulna are described and commented. As
with the other bones, the first function that has to be executed is the function that will
carry out the orientation of the ulna. Subsequently this uniform orientation will help in
extracting the features that were mentioned in the end of Chapter 2. The following
flowchart gives the sequence of events when extracting features of the ulna.
Extract apex of the olecranon
Extract coronoid process
Orient ulna
Extract styloid process
Extract head of the ulna
The rest of this chapter is constructed in the same manner as the 3 previous chapters.
The functions, corresponding to the procedures as stated in the flowchart, are
described one by one starting with the description of the orientation procedure. The
exact method of working can be found in the end of the introduction of Chapter 4.
We had a total of 6 3D models of ulnas at our disposal to make and test the functions
outlined in this chapter.
The code can be found in Appendix B.5.
112
7.1
The orientation of the ulna
The idea is the same as for every orientation for every bone. We chose arbitrarily a
reference orientation, with which the feature extractions can be done in a uniform way.
After the necessary translations and rotations of the bone, its side is detected and
mirrored, if it is a leftsided bone, to its right counterpart. For the subsequent
visualization of the bone and its features, all of this has to be mirrored again, with
respect to the same plane, in order to get the bone’s original side.
The intended final orientation can be seen in Figure 7.1 and 7.2. This is the orientation
of the bone resembling to its orientation if the forearm (to which the ulna belongs) is
held in its neutral position in the human body. In this orientation the proximal end is
situated higher than the distal end.
More concretely, the ulna of the right arm is aligned around the z-axis from above to
below and the anterior aspect of the bone points towards the negative y-axis
Figure 7.1
Superior view of the oriented right ulna. The bone is looked at from the positive z-axis.
113
Figure 7.2
Left: Anterior view of the oriented right ulna. The bone is looked at from the negative y-axis.
Right: Lateral view of the oriented right ulna. The bone is looked at from the negative x-axis.
The function used is called orientUlna.
[x2, y2, z2, n2, side] = orientUlna(x1, y1, z1, n1)
As output arguments it will return the patch representation of the oriented right ulna (x2,
y2 and z2), the matrix n2 of normals to the facets of the oriented 3D model and the
logical operator side, which holds the specification of the side of the bone (left if side
== 1 or right if side == 0).
The input arguments are the patch representation (x1, y1 and z1) and the matrix of the
normals (n1) of the unoriented 3D model of an ulna that serves as input for the
orientation process.
114
Step 1: Define the principal component axis of the 3D model
The eventual purpose of this step will be the aligning of the bone around the z-axis. As
the ulna is a long bone it has a long shape between its proximal and distal end and we
will use this property throughout this step.
We will determine the best line (axis) around which the data, representing the 3D
model, is distributed. This is done by executing a principal component analysis of the
data of the bone. We call this principal axis Princ. Because of its long shape, logically
Princ will lie along the long side of the ulna. In future steps we do transformations in
order to get this line to fall together with the z-axis.
The specification of Princ is done by the specification of one point of it and the
direction of it. A point that always lies on the principal component axis is the mean of all
the points of the data. The direction of Princ is given back by the function carrying out
the principal component analysis. In 4.1 this function, princomp is described. So now
we have the parameters that specify Princ. With this information we can define the
projection of every point of the data onto Princ. If we want Princ to coincide with the zaxis, it is sufficient to get two distinct points of Princ to lie on the z-axis. Arbitrarily we
picked the two exteme projections of the data onto Princ to do this aligning.
We now have the two extreme points of the principal component axis, ext1 and ext2.
Figure 7.3 shows the unoriented bone together with Princ in blue and ext1 and ext2
both in yellow.
Figure 7.3
115
On this moment we don’t know where the extreme points are situated with respect to
the bone. Does ext1 lies on the distal end or on the proximal end?
Figure 7.4
Step 2: Do a linear translation defined by ext1
This step forces ext1 to be the origin of 3D space and the entire bone undergoes the
same translation. As a result ext1 yet will be a point of the z-axis. We can see in Figure
7.4 the outcome of the translation.
Step 3: Force ext2 onto the z-axis
After this step the principal component axis Princ lies aligned with the z-axis, because
ext1 and ext2 are now points of the z-axis. See Figure 7.5.
This step is carried out by rotating the 3D model first around the z-axis and
subsequently around the y-axis. One rotation more around the x-axis or y-axis is
possible to get the bone to lie above the x-y plane. For more comments on this issue
we refer the reader to 4.1, Step 4 where these sequence of rotations is commented.
116
Figure 7.5
Step 4: Determine the right up-down orientation of the ulna
The purpose of this step is making the proximal end of the ulna to lie above the distal
end.
As a result of step 3, all the points of the model lie above the x-y plane. We now make
use of the specific shape of a regular ulna. The proximal end is a broader and bigger
part than the distal end, i.e. the maximum distance of a point to the z-axis is bigger in
the proximal half than in the distal half. With this information we can determine which
extreme point lies on the proximal end and which on the distal end.
If the maximal distance to the z-axis is bigger in the half near ext1 (the lowest extreme
point), we can conclude that the bone is oriented upside down along the z-axis. In this
case we rotate the entire bone over 180 degrees around the y-axis (or the x-axis).
Figure 7.6 illustrates the idea. Left we see the projection onto the x-y plane of the
points of the uppermost half (near ext2) of the bone depicted in Figure 7.5. Right is
shown the projection of the points of the undermost half (near ext1). It is obvious that
117
the biggest x-y distance (the red points in Figure 7.6) can be found in the left image and
thus the half corresponding to it will be detected as being the most proximal half, which
is the correct conclusion for our example.
Figure 7.6: Left: Projection of the uppermost half of the bone onto the x-y plane.
Right: Projection of the undermost half of the bone onto the x-y plane.
If as a consequence of this rotation the bone lies below the x-y plane, we do a
translation in the direction of the z-axis as to force the bone to lie above the x-y plane
again. We are now sure which extreme point is near the broad proximal end and which
near the thin distal end.
The bone is now oriented along the positive z-axis in its correct up down orientation.
In our example bone as seen in Figure 7.5 the up down orientation already is a fact so
no supplementary transformations were needed here.
Step 5: Make the ulna's anterior aspect to point to the negative y-axis
To complete this task we made use of the shape of the upper proximal part of the ulna.
Through observation of the proximal ends of the 6 models it became clear that the
biggest distance between opposing points (with respect to the origin of the 3D space)
could be found in the direction defined by the coronoid process and the apex of the
olecranon. We used this information to determine the correct angle over which to rotate
118
the 3D model around the z-axis in order to get the anterior aspect of the ulna to point
towards the negative z-axis. The technique used to perform this is the same technique
as used in Step 4 of 6.1.
In the end the direction in which the y-distance (maximal y-coordinate – minimal ycoordinate) is the biggest (more or less the direction defined by the apex of the
olecranon and the coronoid process) will be aligned with the y-axis. In this moment it is
possible that the anterior aspect points to the positive y-axis for the same reason as
with previous rotations – we only do rotations with angles smaller than 90 degrees. If
this situation occurs, a supplementary rotation over 180 degrees around the z-axis is
needed. The outcome orientation is that of Figure 7.7.
Figure 7.7: Anterior view from the negative y-axis.
119
Step 6: Determine whether it is a bone of the right or a bone of the left arm
The bone is oriented as wanted, but we are not yet sure upon the side of the bone. To
solve this, we base ourselves upon the geometry of the distal half of the ulna. The
lowest point of the 3D model of an ulna in the current orientation (we will see in 7.4 this
is the styloid process) is always pointing a bit medialwards. For a left bone medialwards
in the current orientation means towards the negative x-axis. So if the lowest point has
an x-coordinate smaller than 0, the input bone is a left sided ulna. This is the case in
Figure 7.7 where the lowest point represented by the purple marker has an xcoordinate smaller than 0.
If a left sided bone detected, all the points of the 3D model will be mirrored with respect
to the y-z plane and the output argument, side, is set to 1.
This mirror process yields for the example bone its right counterpart oriented like
intended. This outcome orientation is depicted in Figure 7.1 and 7.2.
7.2
Extraction of the apex of the olecranon
The purpose of this procedure is to visualize the apex of the olecranon. The olecranon
is the large tuberosity located at the posterior aspect of the proximal end of the ulna.
The apex of this tuberosity is the point that has to be extracted. We will extract the
position of this point as defined in [1].
The function responsible for this extraction is named olecranonUlna.
[olecUlna] = olecranonUlna(L)
The output argument is the position of the apex of the olecranon. The input argument L
is the list representation of the oriented right ulna.
The idea is simple once the ulna is oriented like we described in 7.1. In this orientation
the apex of the ulna is the most posterior (biggest y-value) point of the proximal end of
the ulna.
120
Step 1: Define the upper part of the ulna in which to look for the apex of the
olecranon
Through examining the 6 3D models of the ulna, we defined the upper part as the part
lying above a z-value defined by 97% of the total length (along the z-axis) of the ulna.
This value yielded the best result in all 6 cases. We call this list of points upperL.
Figure 7.8: Left: The entire bone with the points of search space upperL plotted in purple. Right: the
most posterior point of this search space, the apex of the olecranon, in red.
Step 2: Select the most posterior point of upperL
This point will be the apex of the olecranon. It is the point in upperL with the biggest ycoordinate.
The procedure is illustrated in Figure 7.8.
7.3
Extraction of the coronoid process
The coronoid process of the ulna is like the previous feature situated in the most
proximal part of the ulna. It is the horizontal part that points anteriorly. We will extract
the most anterior point on the coronoid process as defined in [1] and this feature will be
referred to as the coronoid process.
The function coronoidUlna will carry out this extraction.
[corUlna] = coronoidUlna(L)
121
The output argument is the position of the coronoid process onto the oriented right 3D
model of an ulna. The input argument L is the list representation of the oriented right
ulna.
Because the coronoid process is the most anterior part of the proximal end of the ulna,
it is sufficient to select the most anterior point of the entire ulna. In the orientation of the
bone as described in 7.1 the anterior aspect points to the negative y-axis, therefore the
most anterior point is represented by the point with the smallest y-value. See Figure
7.9, where it is very clear this statement holds. In all 6 cases of the 3D models we have
studied, this conclusion could be made.
Figure 7.9
122
7.4
Extraction of the styloid process
The styloid process is a small tuberosity on the distal end of the ulna. The point that we
will look for is the very tip of this tuberosity. The tip can be seen as the representation
of the entire styloid process and hence the extracted tip will be referred to as the styloid
process.
The function styloidUlna will execute the process of locating the styloid process.
[stylUlna] = styloidUlna(L)
The output argument is the position of the point we defined as the styloid process, the
tip. The input argument L is the list representation of the oriented right ulna.
In [1] the palpation of the styloid process results in localizing not the tip of the styloid
process, but a point along the medial edge of the styloid process, just above the tip.
This point is chosen because it is impossible to palpate the real tip as it is hidden by the
tendon of a muscle (extensor carpi ulnaris) and therefore not reachable.
We, on the other hand, do have the possibility to localize the very tip of the styloid
process. In the current orientation of the ulna, this tip is the most distal point of the ulna.
Consequently it is sufficient to select the point with the smallest z-value of L.
In Figure 7.7 the styloid process is represented by the purple marker.
7.5
Extraction of the ulnar head
As stated in Chapter 2, the ulnar head is a rounded eminence on the lateral aspect of
the distal end of the ulna. We will extract the ulnar head as a sphere and give back the
center and the radius of the sphere.
The function headUlna will carry out this feature extraction procedure.
[center radius] = headUlna(L)
center and radius are the parameters that specify the extracted sphere. L is the list
representation of all the points of the 3D model of the oriented right ulna.
123
Firstly a region of points is isolated. This set of points, that corresponds to a set
belonging to the ulnar head, will be given as input to a function that will do the fitting of
these points to a sphere. This fitting process is based upon the least squares fitting
technique.
Step 1: Define the undermost part of the 3D model in which to look for points of
the ulnar head
This step comes down to selecting those points lying in the undermost 5% of the ulna
with respect to the z-axis. We call this list underL. The points of underL are depicted in
Figure 7.10 in yellow.
Figure 7.10
Step 2: Make an ultimate list of points that will be handed over to the fitting
procedure
The purpose of this step is selecting only points belonging to the ulnar head. For this to
happen we make use of the position of the ulnar head relative to the undermost part of
124
the ulna. Because it is a surface for articulation with the radius, the ulnar head will lie
on the lateral side of the distal end and it is directed anteriorly. For the 3D model that
we use in our extraction functions (the outcome of 7.1) this means that the points of the
ulnar head are situated in the direction of the negative x-axis and the negative y-axis.
Now we will take a point in the center of underL, cent, and we will define a particular
vector in it. This vector can be interpreted as the representation of a plane; the plane
perpendicular to the vector. So we have created a plane perpendicular to the vector in
cent. But what is the vector of which we talked? This vector is (-1, -1, 0) and thus the
vertical plane defined by it can be used to select the most lateral and anterior points of
underL by taking the points of underL lying on the latero-anterior side of the plane.
This refined list of points is called fitL (Figure 7.11, right, the blue dots).
This procedure is clarified in Figure 7.11.
Step 3: Fit the points of fitL to a sphere
The points of fitL are given to a function that does the fitting to a sphere of these
points. This sphere will represent the ulnar head. Figure 7.12 shows the ulna with the
sphere approximation of the ulnar head in red.
125
Figure 7.11: Left: an inferior view (from the negative z-axis) with in purple the point cent. Right: a slightly
inferior view with the plane (purple) drawed through cent perpendicular to the vector (-1,-1,0). We will
only take into account the points on the latero-anterior (left) side of it, the list fitL, plotted in blue.
Figure 7.12
126
Chapter 8
The radius
The radius is located on the lateral aspect of the forearm. In this chapter all of the
functions corresponding to the radius are explained and illustrated. The general method
of working applied in the previous chapters of the other bones is utilized once again to
extract features of the radius. Firstly the 3D model that is read in will be oriented and
subsequently this orientation will help in extracting the features relevant to the radius.
The features to extract are listed in the end of Chapter 2. The following flow chart
shows the sequence of the carried out procedures.
Extract the radial head
Orient radius
Extract the radial head periphery
Extract styloid process
The rest of this chapter is constructed in the same manner as the 4 previous chapters.
The functions, corresponding to the procedures as stated in the flowchart, are
described one by one starting with the description of the orientation procedure. The
exact method of working can be found in the beginning of Chapter 4.
Throughout the writing and testing of the code many ideas originated from the
observation of 6 random 3D models of regular radii.
The code can be found in Appendix B.6.
8.1
The orientation of the radius
The idea is the same as for every orientation for every bone. We chose arbitrarily a
reference orientation, with which the feature extractions can be done in a uniform way.
After the necessary translations and rotations of the bone, its side is detected and
mirrored, if it is a leftsided bone, to its right counterpart. For the subsequent
127
visualization of the bone and its features, all of this has to be mirrored again, with
respect to the same plane, in order to get the bone’s original side.
The intended final orientation can be seen in Figure 8.1 and 8.2. This is the orientation
and positioning of the bone resembling to its orientation if the forearm (to which the
radius belongs) is held in its neutral position in the human body. In this orientation the
proximal end is situated higher than the distal end.
More concretely, the ulna of the right arm is aligned around the z-axis from above
downwards and the anterior aspect of the bone points towards the negative y-axis.
Figure 8.1 Superior view of the oriented right radius. The bone is looked at from the positive z-axis.
The function used is called orientRadius.
[x2, y2, z2, n2, side] = orientRadius(x1, y1, z1, n1)
As output arguments it will deliver the patch representation of the oriented right radius
(x2, y2 and z2), the matrix n2 of normals of the facets of the oriented bone and the
logical operator side, which holds the specification of the side of the bone (left if side
== 1 or right if side == 0).
The input arguments are the patch representation (x1, y1 and z1) and the matrix of the
normals (n1) of the unoriented 3D model that serves as input for the orientation
process.
128
Figure 8.2
Left: Anterior view of the oriented right radius. The bone is looked at from the negative y-axis.
Right: Lateral view of the oriented right radius. The bone is looked at from the negative x-axis.
The first 4 steps of the algorithm are completely the same as the first 4 steps in
orienting the ulna. For more information on these, the reader is referred to 7.1.
Step 1: Define the principal component axis of the 3D model
We get two extreme points on the principal axis of the data, ext1 and ext2.
Step 2: Do a linear translation defined by ext1
Figure 8.3 shows the result of the 2 first steps. The principal axis is depicted in blue
and the two extreme points are yellow. One of the extreme points is positioned in the
origin of the global coordinate system.
129
Figure 8.3
Step 3: Force ext2 onto the z-axis
Figure 8.4 illustrates that with the two extreme points on the z-axis, the principal axis is
aligned along the z-axis. The bone is oriented upside down in this example.
130
Figure 8.4
Step 4: Determine the right up-down orientation of the radius
This step exhibits the same logic as in Step 4 of 7.1, but the parameters are different
now. Whereas with the ulna the proximal end is broader and bigger than the distal end,
the proximal end of the radius is less broad and smaller than the distal end. So we alter
the decision making process of doing the 180 degree rotation around the y-axis (or xaxis) as follows. If the maximal distance to the z-axis is smaller in the half near ext1
(the lowest extreme point), we can conclude that the bone is oriented upside down
along the z-axis. As a consequence the bone has to be rotated over 180 degrees in
order to get its up down orientation as in the forearm of a neutrally positioned arm.
131
Figure 8.5 Left: Projection of the undermost half of the bone onto the x-y plane.
Right: Projection of the uppermost half of the bone onto the x-y plane.
Figure 8.5 makes clear the norm of the left image is smaller than that of the right
image, therefore it can be decided that the narrow part, the head of the radius, lies in
the undermost part. As a result the bone has to be rotated 180 degrees over the x-axis
or over the y-axis.
Figure 8.6
132
The bone is now oriented along the positive z-axis in its correct up down orientation.
This is confirmed in Figure 8.6.
Step 5: Determine the side of the radius, left or right
This step makes use of the relative positioning of the lowest point of the radius in the
current orientation, lowest, to the point representing the radial tuberosity, radTub. We
utilize these points because they are unambiguously detectable and therefore in every
3D model of any given radius easily and correctly reproducible.
Firstly lowest is forced into the x-z plane on the negative x-axis. This is done by
rotation around the z-axis. Than radTub is located in the current position of the radius.
This is done by looking for the point with the biggest orthogonal distance to the z-axis in
the proximal 25% of the bone.
In this last reached orientation the radial tuberosity of a radius of the right arm will have
a negative y-value. If the y-value of radTub is positive, the processed bone is a left
one. Once detected a leftsided radius, a mirror operation will take place to transform
the left bone into its right counterpart.
Figure 8.7
133
In our example (Figure 8.7) the radial tuberosity in yellow and the lowest point in purple
decide that we have processed a left bone. This will be mirrored with respect to the x-z
plane to become its right counterpart.
Step 6: Let the radial tuberosity point medialwards
Medialwards for a rightsided bone means in the direction of the positive x-axis (if the
anterior aspect points to the negative y-axis like in our orientation).
The task consists of rotating the bone around the z-axis until the radial tuberosity,
radTub, lies in the x-z plane on the half of the positive x-axis. If this orientation is
reached, the objective of the orientation procedure orientRadius is met. This is shown
in Figure 8.8.
Figure 8.8
134
8.2
Extraction of the radial head
Extraction of the radial head comes down to fitting a sphere to the points of the cup
shaped depression on top of the radial head. This is where the radius articulates with
the capitulum of the humerus.
The function that carries out the fitting of the above defined sphere takes on the
following form:
[center radius] = headRadius(L)
The output arguments are the position of the center and the radius of the fitted sphere.
The input argument is the list of the points of the oriented right radius (the list
representation of the output of orientRadius).
The procedure comes down to locating and isolating the set of points that belongs to
this cup shaped form and handing over this list to a function that carries out the least
squares fitting procedure to a sphere.
Step 1: Locate the center of the cup on the radial head
This point, sPoint, will be the first point to add to the list of points that eventually will be
given to the fitting function.
As the radial head is not exactly centered around the z-axis, we can not select the point
of the bone with the biggest z-value as origin. Thus we will define the principal
component axis of the superior 20% of the radius and we will select the extreme point
with the biggest z-value as origin. Following this method gives certainty about the
correct position of sPoint. See Figure 8.9, in red the points of which the blue principal
component axis is calculated. The yellow marker represents sPoint.
135
Figure 8.9
Step 2: Calculate the distances to sPoint of the top 5% of the bone, upperL.
This is a preparation step for the actual fitting phase of step 3. Purpose is to select the
correct points to give to the fitting procedure. The correct points would be those points
of the upwards facing cup of the radial head.
The term ‘distance’ of the title is meant to be the distance between the points of the
upper 5% and sPoint that are all projected onto the x-y plane. We take in other words
the x-y distance into account. This is the same technique as in 8.1. We took this
decision because with this method the definition of the percentage top part is more
robust and not that decisive. We could have taken without having problems instead of
5% a percentage of 10%. This becomes clear by reasoning on the x-y distance. Saying
that the x-y distance to a point, say test, must be smaller than a certain value v is
nothing more than selecting the points that lie inside the cylinder drawn around the zaxis with a radius of v. If we work with conditions on the distances to sPoint of the
points of upperL, this method will be easier to work with. This will become clear in step
3.
136
Step 3: Define the list of data that will be fitted to the sphere
This list will be named fitL. This is the list of data points that have a x-y distance to
sPoint that is smaller than 40 % the maximal x-y distance. These points will with
certainty all be part of the upwards facing cup of the radial head because of the use of
the x-y distance. The choice for 40% is the result of the testing of the function with the 6
radii.
Figure 8.10 gives an illustration. The blue dots are the projections of the points of
upperL onto the x-y plane. The green dot is the projection with the biggest x-y distance
and the red dots are the projections of the point that will be involved into the fitting to a
sphere, fitL. Those points have an x-y distance smaller or equal to 0.4 * the maximal xy distance, in green.
If we had used the Euclidean distance, it would have been difficult to specify a good
value for the percentage of the max(distances to sPoint). In the writing and testing of
the function, points of the radial head periphery were included into fitX. This had a
negative influence on the fitting to the correct sphere.
Figure 8.10
137
Step 4: Do the fitting of the data in fitL to the sphere
fitL is given to a function carrying out the fitting to a sphere, thus returning the center
and the radius of the sphere. This sphere is illustrated in Figure 8.11.
Figure 8.11
8.3
Extraction of the radial head periphery
In this chapter the fitting of a cylinder to the points of the periphery of the radial head is
done. It is a tight ridge that resembles more or less to a cylinder.
The function that does this extraction:
[radius under upper] = cylRadius(L)
The three output arguments are the radius of the cylinder, the uppermost and the
undermost point on the axis of the calculated cylinder.
The input argument is the list of the points of the oriented right radius (the list
representation of the output of orientRadius).
138
The procedure comes down to locating and isolating the set of points that belongs to
this periphery and handing over this list to a function that carries out the least squares
fitting procedure to a cylinder.
Step 1: Locate the position of the uppermost point of the cylinder
This step is exactly the same as the second step in 8.2. We call the located point,
upper. This will be given as an output argument, but it will also be used in the next
steps. See Figure 8.9.
Step 2: Calculate the distances to upper of the top 5% of the bone, upperL.
See the second step of 8.2.
The correct points in this extraction procedure would be those points of the periphery of
the radial head. So we have to define a condition with respect to the x-y distance that
will yield these points.
Step 3: Define the list of data that will be fitted to the cylinder.
We call this list fitL. This is the list of data points that have an x-y distance to upper that
is bigger than 80% the maximal x-y distance. These points will with certainty all be part
of the periphery of the radial head because of the use of the x-y distance. See Figure
8.12 for our example.
The above choice for 80% is the result of the testing of the function with the 6 radii.
Figure 8.12 Left: The points of fitL marked in red. Right: The eventual fitted cylinder marked in green.
139
Step 4: Do the fitting of the data in fitL to the cylinder
fitL is given to a function carrying out the fitting to a cylinder. This function will give
back the radius, the upper- and the undermost point on the axis of the fitted cylinder.
With these three parameters we are able to visualize the cylinder in the subsequent
visualizing procedures.
8.4
Extraction of the styloid process
The styloid process of the radius is a tuberosity that lies on the lateral side of the distal
end of the radius. The point that we will look for is the very tip of this tuberosity. This
point will serve as a representation of the entire tuberosity and will therefore be referred
to as the styloid process.
The function that does this extraction:
[stylRad] = styloidRadius(L)
The output argument is the position of the styloid process. The input argument is the
list representation of the already oriented right radius.
As in the extraction of the styloid process of the ulna we are looking for the most distal
point of the entire bone. As the list L represents the already oriented bone, it is
sufficient to select the point with the smallest z-value of L. This will be the (tip of the)
styloid process of the radius. Figure 8.13 illustrates the position of this feature as the
red marker.
140
Figure 8.13
141
Chapter 9
Results
This chapter serves to quantify the quality of our automatic feature extraction
processes.
The problem in doing so is that we do not have data that can serve as reference data to
the features we have extracted for all the bones we worked with. And thus it is very
difficult to validate the obtained data to a reference set for every processed bone.
Although there is not an exact way of validating our functions, we used 3 ways that do
this validation process in a heuristic manner.
9.1
Visualization
The first validating process is to judge the positions of the extracted features by looking
at the resulting position and deciding whether it is the good position for a certain
feature. This rudimental technique can not be considered as a scientific significant
validation process, but it does give an indication of the correctness of the results.
In all cases, with good modeled bones the results were acceptable to good. We have to
emphasis that the result is to a great extent dependent on the quality of the input 3D
models because we designed our functions for anatomically perfect bones. Any
abnormality in a 3D model of a given bone can produce faulty output because the
functions only work with the information given by the geometry of the 3D models.
The following figures will visualize for each bone type the extracted features. The bone
models are those that were made available with the V-Palp software tool (see 9.2).
142
Figure 9.1: Left: anterior view of the humerus (from the negative y-axis). Right: medial view of the
humerus (from the positive x-axis)
Figure 9.2: Superior view of the humerus (from the positive z-axis)
143
Figure 9.3: Left: posterior view of the scapula (from the negative y-axis). Right: medial view of the
scapula (from the positive x-axis)
Figure 9.4: Superior view of the scapula (from the positive z-axis)
144
Figure 9.5: Anterior view of the clavicle (from the negative y-axis)
Figure 9.6: Superior view of the scapula (from the positive z-axis)
145
Figure 9.7: Left: anterior view of the ulna (from the negative y-axis). Right: medial view of the ulna (from
the positive x-axis)
Figure 9.8: Superior view of the ulna (from the positive z-axis)
146
Figure 9.9: Left: anterior view of the radius (from the negative y-axis). Right: medial view of the radius
(from the positive x-axis)
Figure 9.10: Superior view of the radius (from the positive z-axis)
147
9.2
V-Palp
On top of this heuristic validation we can work with the bones and the data of the
positions
of
the
features
of
the
open
source
software
tool
V-Palp
[14].
The Virtual Palpation software (V-Palp) is a software tool that allows users to be trained
and evaluated on virtual palpation. That is: 3D models of all bones of the human body
can be read in and the user can locate the desired landmarks/features by clicking onto
the 3D model. Hence it is the virtual counterpart of manual palpation. It is developed as
an addition to [1]. Figure 9.1 gives a screenshot of the GUI of V-Palp.
Figure 9.11
The tool comes with an example for all the open source 3D models of bones of the
body. This is the exact same set of bones we used to visualize all our feature extraction
procedures. For each bone of this set the positions of the landmarks are predefined by
the developer of the tool and this data can be exported.
This is of interest for our work as we worked with the exact same bones. The exported
data is given for the unoriented bones. So if we do the same transformations to the
exported landmarks/features as we did to the bones in the orientation procedures, we
get the positions of the exported landmark data in our reference orientations of the
bones and we can compare these positions with the positions we obtained.
148
This procedure is only applicable to those features we extracted that coincide with
features processed by V-Palp.
For each of the 5 processed bones –humerus, scapula, clavicle, ulna and radius- we
will export the features in common with our extracted features and do the necessary
transformations to their coordinates representing their positions. These will be
compared to the positions we extracted.
In 9.4 the tables give the results for each feature of each bone. If this validation
technique is used for a particular feature, ‘V-Palp’ will be written under the name of the
feature.
In the second column come the positions as defined in V-Palp and in the third column
come our extractions. The fourth column gives the Euclidean distance between both to
give an indication about the correctness of our extractions.
9.3
Manual
Some of the features we extracted, such as the head of the humerus (4.2), the
capitulum of the humerus (4.5),…, are not localized in V-Palp and therefore can not be
compared. For those features we did a manual feature extraction.
These features all involve fittings to geometric shapes like spheres, cylinders and 3D
circles. For each feature we can manually pick the points that need to be given to a
fitting function and carry out the fitting. This approach is the same as we did in our
extraction functions, with that difference that in our functions the lists of points to feed
the fitting functions are created automatically.
In 9.4 the tables give the results for each feature of each bone. If this validation
technique is used for a particular feature, ‘manual’ will be written under the name of the
feature.
In the second column come the results as produced by the manual extraction and in
the third column come the results from the automatic extraction. The fourth column will
show the difference between the results of the manual and automatic extractions.
149
In case of a sphere fit, the center of the sphere and the radius will be given.
In case of a cylinder fit, the radius and the direction of the axis of the cylinder will be
given. The directions of the axes are normalized vectors. The difference will be
expressed as the angles between the vectors representing the axes of the cylinders.
In case of a 3D circle fit, the center, the radius and the vector perpendicular to the
plane of the circle will be given. The difference associated with the normals to the
planes will be expressed in terms of angles between these normals.
9.4
Results
The following tables give for each bone the results. If suitable, remarks will be given.
If coordinates are given, they have to be interpreted with respect to the global
coordinate system with its origin in (0,0,0). If distances are given, like the radius of a
sphere or the difference between two points, they have to be interpreted as millimeters.
With difference in direction is meant the angle between the two vectors representing
the directions.
9.4.1 Humerus
Features
Validation
Automatic
-2.2582
-4.3559
-25.8914
-25.9081
V-Palp
296.9482
299.1959
Greater Tubercle
-24.9819
-25.0982
0.0552
-4.5262
V-Palp
305.3458
304.1876
Lateral Epicondyle
-32.1017
-32.4460
-2.7128
-2.2030
17.2785
20.2653
31.1213
31.7946
-0.8724
-0.0000
Lesser Tubercle
V-Palp
Medial Epicondyle
Difference
3.0745
4.7269
3.0495
2.9217
V-Palp
150
14.8967
17.6026
Head of humerus
2.3406
2.0054
(Center, radius)
0.5335
-0.1745
301.0679
300.5293
21.8237
22.8569
10.0722
10.0257
-10.4533
-10.5142
11.8674
11.8680
12.1677
12.1996
0.9996
0.9995
-0.0089
-0.0168
-0.0259
-0.0264
Manual (Sphere)
Trochlea
0.9506
1.0332
0.0766
(Center, radius,
normal)
Manual (3D circle)
0.0319
0.4495 (degrees)
-20.6330
-22.5090
Capitulum
-5.8665
-8.9644
(Center, radius)
19.2525
17.2886
15.1082
11.5859
3.5223
10.7287
11.0881
0.3594
-0.0541
-0.0276
-0.0516
-0.0286
0.9972
0.9992
4.1199
Manual (Sphere)
Metaphyseal cylinder
(Radius, direction of
axis)
Manual (Cylinder)
2.0147 (degrees)
151
9.4.2 Scapula
Features
Validation
Automatic
1.1015
0
-3.2008
0
0.1328
0
-53.7605
-54.9436
28.8638
29.3861
135.7329
134.6012
41.9559
39.3312
-30.6843
-31.8560
167.5981
163.8888
45.6540
47.6807
5.7046
3.0465
188.0629
187.3309
43.1938
44.2023
38.4333
34.7641
V-Palp
162.2173
163.8670
Root of Spine
-43.1816
-42.5345
-6.7305
-7.5384
107.4537
106.7814
Glenoid Cavity
38.4301
37.4870
(Center, radius,
5.9228
5.9540
139.7882
139.5040
14.8018
15.1726
0.6806
0.6087
-0.0423
-0.0272
0.7314
0.7929
Inferior Angle
V-Palp
Superior Angle
V-Palp
Acromial Angle
V-Palp
Acromial Tip
V-Palp
Coracoid Tip
V-Palp
normal)
Manual (3D circle)
Difference
3.3876
1.7185
4.6927
3.4219
4.1475
1.2343
0.9855
0.3708
5.4910 (degrees)
152
9.4.3 Clavicle
Features
Validation
Automatic
Acromioclavicular Joint
-78.5317
-80.2292
-6.2244
-1.9944
7.4391
2.3198
Anterior
76.2687
76.0900
Sternoclavicular joint
-3.6506
-3.9573
V-Palp
2.5206
-1.1762
Features
Validation
Automatic
Apex of the olecranon
9.7669
3.7962
6.1198
5.4900
262.0236
261.8528
-2.0444
1.4098
-23.3083
-24.4162
240.6457
238.0006
5.8533
5.4375
-0.1225
0.2449
V-Palp
3.3154
0.0000
Ulnar head
-1.0597
-0.2380
(Center, radius)
-7.3269
-7.8344
10.9629
12.6702
8.8194
9.4121
V-Palp
Difference
6.8544
3.7138
9.4.4 Ulna
V-Palp
Coronoid process
V-Palp
Styloid process
Difference
6.0062
4.4895
3.3615
1.9615
Manual (Sphere)
0.5927
Remark: the difference corresponding to the styloid process is due to the different
definitions of its position. See 7.4.
153
9.4.5 Radius
Features
Validation
Automatic
-11.1126
-6.2518
-4.2371
-5.8852
V-Palp
6.2712
0.0000
Radial head
-2.8305
-0.3822
(Center, radius)
-0.5337
1.4061
255.4313
256.8239
10.2944
11.1395
0.8451
9.6693
9.6922
0.0229
Styloid process
Difference
8.1038
3.4201
Manual (Sphere)
Radial periphery
(Radius, direction of
axis)
0.0032
Manual (Cylinder)
0.0530
0.9985
0.0049
0.0699
0.9975
1.2384 (degrees)
Remark: the difference corresponding to the styloid process is due to the different
definitions of its position. See 8.4.
As a general remark for the manual validation technique it must be said that it is
subjective in its own right. The manual selection of the points can not be the only
correct selection of the points, because there is not such thing as the correct selection
of points. Therefore the differences between the information of the manual validation
and the information of the automatic feature extraction can not be seen as exact
differences. It gives only an indication that the automatic feature processing yields good
results or very bad results.
154
Chapter 10 Conclusion
The objective of doing the automatic extraction of the predefined features of the given
bones is met. All features can be extracted and visualized in a correct manner on top of
the 3D models of the bones.
Although the general task is done, there are some points that have to be looked at in
the future.
First of all, if the input 3D bone models are of bad quality, the functions will not perform
as expected. Requirement for a successful performance are good defined 3D bone
models. This issue will always constrain the usefulness of our tool.
A very good model can also open the door for implementing new extraction techniques.
For example, with a better 3D model, the curvature calculation will yield better usable
results which on their turn can be exploited to define new extraction techniques. In this
way it could be made possible to segment the bone in its most prominent parts.
Another point of discussion is the absence of clear, well defined, unified definitions of
the positions of the features. [1] tries to present a solution but yet the given definitions
are not very exact in such a manner that only one predefined point can be the wanted
feature. On top of this arises the question whether we have to take into account
specified positions for a feature or a region of points. For example, the greater tubercle
of the humerus is extracted as one point. But strictly spoken, the greater tubercle is an
entire bony eminence on the proximal part of the humerus. Shouldn’t the feature
‘greater tubercle’ be defined as a representation of all the points that make up this
tubercle? This is certainly an issue to be studied in subsequent implementations of
automatic feature extractions.
Chapter 9 has given a summary of the validation techniques at hand. It was obvious
that this validation is subjective. First of all using with V-Palp, we only have one set of
bones at our disposal and secondly the manual process is dependent on the manual
selection of the points, which will not yield exact correct results. A possible approach
155
for validating can be done by combining the results of a virtual palpation process by an
expert with the results of the automatic feature palpation by our tool. If this can be done
with a large number of bones of a great variety, and the statistical analysis yields that
there is an accordance between the two sets of extracted features, the conclusion can
be made that the automatic feature extraction, as worked out here, is a reliable process
that can carry out the task on its own.
156
Appendix A: Anatomical Nomenclature
Listed below are general anatomical terms and their meanings that will help understand
those parts of the work that deal with the anatomical side.
Anatomical Terms
Medial
Lateral
Proximal
Distal
Inferior
Superior
Anterior
Posterior
Dorsal
Ventral
Direction
Towards the midline of the body
Away from the midline of the body
Towards a reference point (the joint)
Away from a reference point (the joint)
Lower or below
Upper or above
Towards the front
Towards the back
Posterior
Anterior
Medical professionals often refer to sections of the body in terms of anatomical planes
(flat surfaces). These planes are imaginary lines – vertical or horizontal – drawn
through an upright body. The terms are used to describe and localize a specific body
part.
Coronal Plane or Frontal Plane
Sagittal Plane or Lateral Plane
Axial Plane or Transverse Plane
157
Appendix B Matlab® code
First it will be suitable to give some general remarks involving the code.
1. In many occasions we used the Matlab® function find. This function is used to select a part
of an array or a matrix that fulfills a certain condition.
For example: ind = find(q > 0). q is an array of integers. find will return as ind an array of
indices that will refer to the positions in q where the element is bigger than 0. So if q is [1, 0, -1,
10], the function will return as ind [1, 4].
2. The transformations, linear translations and rotations, are executed on the patch
representation of the 3D model. This is done not to lose the connectivity information they hold.
It is possible to do the transformations on the list representation of the 3D model, but there is
not a unified way to go from a list representation to the patch representation. This method of
working will become clear in the orientation functions.
After the transformation of the patch representation you have to make sure the list presentation
is up to date with the patch representation if you want to do processings with the list
representation. In this manner at all times there are two consistent representations of a 3D
model, the patch and the list representation.
3. We have used several functions that we downloaded from the Matlab file exchange centre. If
this is the case, this will be specified in the code. The code of these downloaded functions is
not contained in this Appendix.
4. The rotations used in the orientation functions of the 5 bone types must also be performed
on the matrix of the normals to the facets of the 3D model. In this manner the normals keep
being consistent with the rotated facets of the 3D model.
5. In the fitting functions we tried to make the number of input points smaller than a given
number. This because the functions responsible of carrying out the fittings are very sensitive to
the size of the input lists of points. This is done by passing by a constant number of points of
the input lists in order to get the size of the inputl list smaller or equal to a given number.
158
6. The code is rendered to black and white. If you open it in Matlab® colors make all more
clear. Lines that are preceded by ‘%’ represent in code comments.
B.1 The GUI and functions
B.1.1 Gui.m
We decided to not print the M-file associated with the GUI as a whole, because it takes in 80
pages. As a compensation we will print some parts.
The opening function:
% --- Executes just before Gui is made visible.
function Gui_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject
handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles
structure with handles and user data (see GUIDATA)
% varargin
command line arguments to Gui (see VARARGIN)
%manipulation of the components of the GUI
set(handles.pushOpen,'Visible','on');
set(handles.panelBones,'Visible','off');
set(handles.panelHum,'Visible','off');
set(handles.panelScap,'Visible','off');
set(handles.panelClav,'Visible','off');
set(handles.panelUlna,'Visible','off');
set(handles.panelRad,'Visible','off');
set(handles.textLocal,'Visible','off');
set(handles.textGlobal,'Visible','off');
set(handles.panelHumCoord,'Visible','off');
set(handles.panelScapCoord,'Visible','off');
set(handles.panelClavCoord,'Visible','off');
set(handles.panelUlnaCoord,'Visible','off');
set(handles.panelRadCoord,'Visible','off');
set(handles.panelHumCoord2,'Visible','off');
set(handles.panelScapCoord2,'Visible','off');
set(handles.panelClavCoord2,'Visible','off');
set(handles.panelUlnaCoord2,'Visible','off');
set(handles.panelRadCoord2,'Visible','off');
set(handles.panelCurv,'Visible','off');
% Choose default command line output for Gui
159
handles.output = hObject;
% Update handles structure
A part of the function associated with the push button ‘Read in 3D model’. The other part will
carry out manipulation of the GUI -> make all components invisible.
…
%open a standard dialog box to select an Stl file
[filename, pathname] = uigetfile({'*.stl','binary stl files';'*.*','all
files'},'Choose your file');
if isequal(filename,0)
disp('Read in operation Cancelled');
else
%reading in the Stl file in a patch representation of the 3D model
%MATLAB FILE EXCHANGE CENTRE
[x,y,z,n] = stlread2(filename);
%stocking for further use
handles.x = x;
handles.y = y;
handles.z = z;
handles.n = n;
handles.X = unique([x(:) y(:) z(:)],'rows');
%make the panel 'Bones' invisible
set(handles.panelBones,'Visible','on');
end
…
The variable handles is a structure where one can stock variables to hand over to other
callbacks. Every component of the GUI is contained in this structure, so each component is
reachable throughout the entire M-file corresponding to the GUI.
The following function is the callback of the radiobutton that says ‘Humerus’. The callbacks of
the other radiobuttons in the panel ‘Bones’ are similar to this one.
% --- Executes on button press in radioHum.
function radioHum_Callback(hObject, eventdata, handles)
% hObject
handle to radioHum (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles
structure with handles and user data (see GUIDATA)
% Hint: get(hObject,'Value') returns toggle state of radioHum
%the next part is executed as the radiobutton 'Humerus' is toggled on.
if get(hObject,'Value')==get(hObject,'Max')
x = handles.x; y = handles.y; z = handles.z; n = handles.n;
%orientation of the humerus
[x, y, z, n, handles.e1, handles.e2, handles.lowest, side] = ...
orientHumerus(x,y,z,n);
%switch to the list representation of the read in 3D model
X = unique([x(:) y(:) z(:)],'rows');
160
%extraction of the head of the humerus
[handles.c handles.r_head] = headHum(X, handles.e1, handles.e2);
%extraction of the greater tubercle
[handles.greater] = greaterTubHum(X, handles.c, handles.r_head);
%extraction of the lesser tubercle
[handles.lesser] = lesserTubHum(X, handles.c, handles.r_head);
%extraction of the trochlea
[handles.cTroch, handles.rTroch, handles.normal] = ...
trochHum(X, handles.lowest, handles.e1);
%extraction of the capitulum
[handles.cCap handles.rCap] = capitHum(X, handles.e2);
%extraction of the metaphyseal cylinder
[handles.radiusCylHum, handles.underHum, handles.upperHum] = ...
cylHum(X, handles.c, handles.r_head);
%extraction of the topmost point
[handles.topHum] = topHum(X);
handles.x
handles.y
handles.z
handles.n
=
=
=
=
x;
y;
z;
n;
%necessary to do the final transformation to the base proposed in [8]
[handles.XDir handles.YDir handles.ZDir] = ...
ashum(handles.c,handles.e1,handles.e2);
GH = handles.c;
if side == 1 %if it is a left bone
hFig1 = figure(1);
set(hFig1,'DeleteFcn',{@closeProcedure, handles});
set(hFig1,'Name','3D model')
figPos = get(hFig1,'Position');
set(hFig1,'Position',[660,161,figPos(3),532]);
light('Position',[1,1,300],'Style','infinite');
hp = patch(-x,y,z,'w','EdgeAlpha',0,'FaceAlpha',0.8);axis equal;axis
tight; grid on;
% mirroring
handles.c(1) = -handles.c(1);
handles.e1(1) = -handles.e1(1);
handles.e2(1) = -handles.e2(1);
handles.greater(1) = -handles.greater(1);
handles.lesser(1) = -handles.lesser(1);
handles.cTroch(1) = -handles.cTroch(1);
handles.normal(1) = -handles.normal(1);
handles.cCap(1) = -handles.cCap(1);
handles.topHum(1) = -handles.topHum(1);
handles.underHum(1) = -handles.underHum(1);
handles.upperHum(1) = -handles.upperHum(1);
handles.XDir(1) = -handles.XDir(1);
handles.YDir(1) = -handles.YDir(1);
161
handles.ZDir(1) = -handles.ZDir(1);
GH(1) = -GH(1);
else
hFig1 = figure(1);
set(hFig1,'Name','3D model')
set(hFig1,'DeleteFcn',{@closeProcedure, handles});
figPos = get(hFig1,'Position');
set(hFig1,'Position',[660,161,figPos(3),532]);
light('Position',[1,1,300],'Style','infinite');
hp = patch(x,y,z,'w','EdgeAlpha',0,'FaceAlpha',0.8);axis equal;axis
tight; grid on;
end
%drawing of the arrows making up the local coordinate system
hold on
xlabel('Xglobal')
ylabel('Yglobal')
zlabel('Zglobal')
endpoints = [GH + 2 * handles.r_head * handles.XDir;...
GH + 2 * handles.r_head * handles.YDir;GH + 2 * handles.r_head ...
* handles.ZDir];
arrow3([GH;GH;GH],endpoints, 'b', .5,1,.5)
text(GH(1), GH(2),GH(3)- 10,'\bfGH')
text(endpoints(1,1),endpoints(1,2),endpoints(1,3),'\bfXh','color','b')
text(endpoints(2,1),endpoints(2,2),endpoints(2,3),'\bfYh','color','b')
text(endpoints(3,1),endpoints(3,2),endpoints(3,3),'\bfZh','color','b')
set(hp, 'EdgeColor','none')
axis equal; axis tight; axis auto
hold off
%To calculate the definition of the global coordinate system in terms
%of the new coordinate system.
handles.Transf = ...
[handles.XDir; handles.YDir; handles.ZDir]'\[1 0 0;0 1 0;0 0 1];
%Manipulate the GUI
set(handles.panelBones,'Visible','off');
set(handles.panelHum,'Visible','on');
set(handles.panelHumCoord,'Visible','on');
set(handles.panelHumCoord2,'Visible','on');
set(handles.panelScap,'Visible','off');
set(handles.panelClav,'Visible','off');
set(handles.panelUlna,'Visible','off');
set(handles.panelRad,'Visible','off');
set(handles.textLocal,'Visible','on');
162
set(handles.textGlobal,'Visible','on');
set(handles.panelCurv,'Visible','on');
end
handles.output = hObject;
guidata(hObject, handles);
….
The following function is the callback of the radiobutton that says ‘Capitulum’. The callbacks of
the other radiobuttons in the panel ‘Features humerus’ are similar to this one.
function radioHumCap_Callback(hObject, eventdata, handles)
% hObject
handle to radioHumCent (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles
structure with handles and user data (see GUIDATA)
% Hint: get(hObject,'Value') returns toggle state of radioHumCent
%The center and the radius of the sphere estimation of the capitulum. Those
%were calculated in the callback associated with the humerus.
cCap = handles.cCap;
rCap = handles.rCap;
%if the radiobutton toggled on
if get(hObject,'Value')==get(hObject,'Max')
figure(1)
hold on
%the drawing
%drawSphere -> Matlab file exchange centre.
%used to draw a sphere with a given center and a given radius.
handles.hCapit = drawSphere(cCap(1),cCap(2),cCap(3), rCap, ...
'FaceColor','r','EdgeAlpha',0,'FaceAlpha',1);
%calculating the coordinates in the local coordinate system.
c_coord = handles.Transf*handles.c';
cap_coord = handles.Transf*cCap' - c_coord;
%manipulation of the textfields referring to the local coordinate
%system
set(handles.textcaphumx,'String',num2str(cap_coord(1),'%11.4f'));
set(handles.textcaphumy,'String',num2str(cap_coord(2),'%11.4f'));
set(handles.textcaphumz,'String',num2str(cap_coord(3),'%11.4f'));
set(handles.textcaprad,'String',num2str(rCap,'%11.4f'));
%manipulation of the textfields referring to the global coordinate
%system
set(handles.textcaphumx2,'String',num2str(cCap(1),'%11.4f'));
set(handles.textcaphumy2,'String',num2str(cCap(2),'%11.4f'));
set(handles.textcaphumz2,'String',num2str(cCap(3),'%11.4f'));
set(handles.textcaprad2,'String',num2str(rCap,'%11.4f'));
163
%if the radiobutton toggled off
else
figure(1)
%the deletion of the drawing of the sphere
delete(handles.hCapit);
%manipulation of the textfields referring to the local coordinate
%system
set(handles.textcaphumx,'String','');
set(handles.textcaphumy,'String','');
set(handles.textcaphumz,'String','');
set(handles.textcaprad,'String','');
%manipulation of the textfields referring to the global coordinate
%system
set(handles.textcaphumx2,'String','');
set(handles.textcaphumy2,'String','');
set(handles.textcaphumz2,'String','');
set(handles.textcaprad2,'String','');
end
handles.output = hObject;
guidata(hObject, handles);
The following code is associated with the popupmenu where you can define the neighborhood
with which to calculate the mean curvature.
% --- Executes on selection change in popupCurv.
function popupCurv_Callback(hObject, eventdata, handles)
% hObject
handle to popupCurv (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles
structure with handles and user data (see GUIDATA)
% Hints: contents = get(hObject,'String') returns popupCurv contents as cell
array
%
contents{get(hObject,'Value')} returns selected item from popupCurv
% --- Executes during object creation, after setting all properties.
%get the value chosen in the popupmenu -> neighborhood
contents = get(hObject,'String');
neighborhood = str2num(contents{get(hObject,'Value')});
%calculate the mean curvature -> appendix D
handles.cfinal =
calculateCurvature(handles.x,handles.y,handles.z,handles.n,neighborhood);
%open a second window
hFig2 = figure(2);
set(hFig2,'Name','Curvature information')
set(hFig2,'DeleteFcn',{@closeProcedure, handles});
%visualization of the 3D model as a function of the curvature info.
hpc = patch(handles.x, handles.y, handles.z,
handles.cfinal,'FaceColor','flat');axis equal; axis tight;
164
set(hpc, 'Edgecolor','none');
%visualization of the colorbar
colorbar
B.1.2 The functions responsible for drawing the local coordinate systems
Like in the previous paragraph we will not show each function for each bone type to save
space. The method is the same, only the variables are different.
3.3 gives for each bone type the construction of its local coordinate system.
The next part of code corresponds to the humerus (arbitrarily chosen).
function [xh yh zh] = ashum(GH,EM,EL)
%ASHUM CALCULATES THE 3 COMPONENTS THAT SPECIFY THE LOCAL COORDINATE SYSTEM
%FOR THE HUMERUS
%
%OUTPUT:
% xh is a 1-by-3 array of coordinates of the first component of the local
% coordinate system
%
% yh is a 1-by-3 array of coordinates of the second component of the local
% coordinate system
%
% zh is a 1-by-3 array of coordinates of the third component of the local
% coordinate system
%
%INPUT:
% GH is a 1-by-3 array of the coordinates of the center of the head of the
% oriented right humerus.
%
% EM is a 1-by-3 array of the coordinates of the medial epicondyle of the
% oriented right humerus humerus.
%
% EL is a 1-by-3 array of the coordinates of the lateral epicondyle of the
% oriented right humerus.
%
--------%
%
author : Bart Coppieters
%
%
%Calculation of the midpoint between the epicondyles
H_mid=(EM+EL)/2;
%Definition of axis yh, the 2nd component of the local coordinate system.
yh = (GH-H_mid) / norm(GH-H_mid);
%Definition of axis xh, the 1st component of the local coordinate system.
xh = cross(yh,EL-EM); xh = xh/norm(xh);
%Definition of axis zh, the 3rd component of the local coordinate system.
zh = cross(xh,yh);
The helping point for the ulna coordinate system construction.
165
function [auxUlna] = auxUlna(X)
%AUXULNA CALCULATES THE POSITION OF MOST ANTERIOR POINT OF THE OLECRANON.
%
%OUTPUT:
%
%
auxUlna is a 1-by-3 array of the coordinates of the most anterior
%
point of the olecranon of an oriented right ulna.
%
%INPUT:
%
%
X is a m-by-3 array of the coordinates of the m datapoints that
%
constitute to the right oriented ulna.
%
--------%
%
author : Bart Coppieters
%the most proximal 5% of the bone with respect to the length of it.
upperX = X( find( X(:,3) > min(X(:,3)) + ...
0.95 * (max(X(:,3)) - min(X(:,3))) ),:);
%auxUlna is the point of upperX with the smallest y-value.
auxUlna = upperX( find( upperX(:,2) == min(upperX(:,2))),:);
The helping point for the radius coordinate system construction.
function [notchRad] = ulnarNotchRadius(X)
%ULNARNOTCHRADIUS CALCULATES THE POSITION OF THE CENTER OF THE ULNAR NOTCH
%OF THE ORIENTED RIGHT RADIUS.
%OUTPUT:
%
%
notchRad is a 1-by-3 array of the coordinates of center of the ulnar
%
notch of the oriented right radius.
%
%INPUT:
%
%
X is a m-by-3 array of the coordinates of the m datapoints that
%
constitute the right oriented radius.
%
--------%
%
author : Bart Coppieters
underXposy = X( find( X(:,3) < min(X(:,3)) + ...
0.1 * (max(X(:,3)) - min(X(:,3))) & X(:,2) > 0),:);
underXnegy = X( find( X(:,3) < min(X(:,3)) + ...
0.1 * (max(X(:,3)) - min(X(:,3))) & X(:,2) < 0),:);
notchM = underXposy( find( underXposy(:,1) == max(underXposy(:,1))),:);
notchA = underXnegy( find( underXnegy(:,1) == max(underXnegy(:,1))),:);
notchRad = (notchM + notchA)/2;
166
B.2 Humerus
The functions associated with the humerus.
B.2.1 orientHumerus.m
function [x, y, z, n, e1, e2, lowest, side] = orientHumerus(x,y,z,n)
%ORIENTHUMERUS WILL ORIENT A 3D-MODEL OF A HUMERUS FOR FURTHER PROCESSING,
%I.E. FEATURE EXTRACTION.
%
%OUTPUT:
%
x, y and z are 3-by-N matrices that together form the oriented patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the oriented patch object.
%
%
e1 is a 1-by-3 array of the coordinates of the medial epicondyle.
%
%
e2 is a 1-by-3 array of the coordinates of the lateral epicondyle.
%
%
lowest is a 1-by-3 array of the coordinates of point with the smallest
%
z-value. Therefore this is the lowest point of the 3D model.
%
%
side is a scalar that serves as a logical to state whether it is a left
%
(side == 1) or a right (side == 0) bone.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the original patch object.
%
%
%
%
%
%
%
%
%
X
with N the number of facets of the 3D bone model.
--------author : Bart Coppieters
Step 1
the list representation of the input patch representation of the entire
humerus.
= unique([x(:) y(:) z(:)],'rows');
% Step 2
[a b] = findRefP(X); %selfwritten function. Look there for more info.
% Step 3
%Translation
[x,y,z,bb] = translation(x,y,z,a,b); %selfwritten function.
% Does a translation so that the point a will go to the point (0,0,0).
167
a = [0 0 0];
% Step 4
%The following lines are written to do a sequence of rotations so to
%rotate point bb on to the z-axis. This will result in the fact that the
%line ab will coincide with the z-axis.
% First rotation
hoekz = -atan(bb(2)/bb(1)); %angle over which to rotate around the z-axis.
[x,y,z, rotz] = rotation_Z_axe(x,y,z,hoekz); %selfwritten function.
n = rotz * n; %important to get n corresponding to the rotated patch
% representation
bb = rotz * bb'; %rotated version of bb.
% Second rotation
hoeky = -atan(bb(1)/bb(3)); %angle
[x, y, z, roty] = rotation_Y_axe(x, y, z, hoeky);
n = roty * n;
bb = roty * bb;
if bb(3) < 0 %if the point that corresponds to the head of the humerus is
%below the z=0 plane, i.e. z-coordinate < 0, then rotate around the
%X-axis for 180 degrees.
[x,y,z,rotx] = rotation_X_axe(x,y,z,pi);
%Does a rotation around the x-axis of 180 degrees.
n = rotx * n;
end
%list representation of the current orientied humerus.
X = unique([x(:) y(:) z(:)],'rows');
% Step 5
%selfwritten function. To calculate the positions of the 2 epicondyles of
%the distal part of the humerus.
[e1 e2] = epicondylesHum(X);
% Step 6
%The following 3 lines look for the distances between the epicondyles and
%the lowest (where the z-coordinate is the smallest) point of the bone. The
%epicondyle the closest to this lowest point is also on the medial side of
%the bone.
%calculate lowest point of the bone
lowest = X(find(X(:,3) == min(X(:,3))),:);
n1_1 = norm(e1 - lowest); %the distance (norm) between e1 and lowest
n2_1 = norm(e2 - lowest); %the distance (norm) between e2 and lowest
% Step 7
%In the following code we will rotate the whole bone around the z-axis so
%that the medial epicondyle will lie on the positive part of the x-axis.
%This regardless to the fact whether it is a right or a left bone.
rot_z2 = 1; % definition of a rotation matrix for further purpose.
if (n1_1 < n2_1) % if this condition holds, e1 is the medial epicondyle
hoekz = -atan(e1(2)/e1(1)); %use e1 to get the necessary rotation-angle.
% The rotation
168
[x,y,z,rot_z1] = rotation_Z_axe(x,y,z,hoekz);
n = rot_z1 * n;
e = rot_z1 * e1';
if e(1) < 0 %If its x-coordinate is negative, rotate around the z-axis
%over an angle of pi rad.
[x,y,z,rot_z2] = rotation_Z_axe(x,y,z,pi);
n = rot_z2 * n;
end
else %in this alternative e2 is the medial epicondyle, the following
%procedure is the same as above for e1
hoekz=-atan(e2(2)/e2(1));
[x,y,z,rot_z1] = rotation_Z_axe(x,y,z,hoekz);
n = rot_z1 * n;
e = rot_z1 * e2';
if e(1) < 0
[x,y,z,rot_z2] = rotation_Z_axe(x,y,z,pi);
n = rot_z2 * n;
end
% this is to rename the medial epicondyle e1 and the lateral e2. A
% question of uniformity.
epi = e2;
e2 = e1;
e1 = epi;
end
%The following rotations use the created rotation matrices to rotate points
%that will be visualized in the plot of the bone, i.e. e1(medial
%epicondyle), e2(lateral epicondyle) and the lowest point of the bone.
e1 = (rot_z2 * rot_z1 * e1')';
e2 = (rot_z2 * rot_z1 * e2')';
lowest = (rot_z2 * rot_z1 * lowest')';
%The following lines will decide upon the fact that the bone is of the
%right or the left arm.
vector = cross([e1(1) e1(2) 0],[lowest(1) lowest(2) 0]);
if vector(3)<0
side = 0; %side = right side.
else
side = 1; %side = left side.
y = -y;
e1(2) = -e1(2);
e2(2) = -e2(2);
lowest(2) = -lowest(2);
n(2,:) = -n(2,:);
end
169
B.2.2 headHum.m
function [c r] = headHum(X, e1, e2)
%HEADHUM CALCULATES THE POSITION OF THE CENTER OF THE HEAD OF THE HUMERUS
%AND ITS RADIUS.
%
%OUTPUT:
%
c is a 1-by-3 array of the coordinates of the center of the head.
%
%
r (scalar) is the radius of the fitted head of the humerus.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the right oriented humerus.
%
%
e1 and e2 are 1-by-3 array's of the coordinates of respectively the
%
lateral and the medial epicondyle. (as defined by orientHumerus)
%
%
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% Define the uppermost proximal part of the humerus
max_z = max(X(:,3));
min_z = min(X(:,3));
searchX_rough = X(find(X(:,3) > 0.87 * (max_z - min_z) + min_z), :);
meanX = mean(searchX_rough);
% Step 2
% Do a fitting to sphere of the list searchX_rough.
% The method to restrict the length of the input list for the fitting
% function to 2000 is to pass over in a controlled, uniform way a fixed
% amount of points in the original list searchX_rough. The number of points
% to pass over is calculated and given by int_rough.
int_rough = ceil(length(searchX_rough)/2000);
searchX_rough = searchX_rough(1:int_rough:end,:);
%MATLAB FILE EXCHANGE CENTRE
%It takes a list of points and some
%initialization parameters as input and produces the center and the radius
%of the sphere that is the result of the least squares fitting method
%executed to the input list of points, searchX_rough. More info is found in
%the function itself.
[x0n, rn] = lssphere(searchX_rough, meanX', 20, 0.1, 0.1);
c_rough = x0n'; %rough center of the head
r_rough = rn; %rough radius of the head
% Step 3
170
% In the following we will select the points needed in a second least
% squares fitting for the fitting of the real head of the humerus.
%Definition of the transepicondylar
transepis = e1 - e2;
transepis = transepis/norm(transepis);
%Definition of dir, the direction of the line P.
%rotated 2 times, one time around the y-axis and
%to respectively present the inclination and the
%for the angles are slightly different from [13]
rot_z = rotation_Z_axe(deg2rad(18));
rot_y = rotation_Y_axe(deg2rad(-30));
dir = (rot_z* rot_y * transepis')';
The transepicondylar is
one time around the z-axis
retroversion. The values
to optimalize the result.
%the orthogonal direction to the plane that will cut the head
%to select input points for the second call to lssphere.
dir = dir/norm(dir);
% Step 4 (and part of step 3)
% iterative process of finding the center.
c_old = c_rough;
r_old = r_rough;
flag = 1;
count = 0;
while flag == 1;
% threshold is the point in 3D that is at a distance of 30% the old
% radius away from the old center of the head in the direction of
% dirvect.
threshold = c_old + 0.30 * r_old * dir;
% in the following will be seen at the points above (in the direction
% of dir) of the plane, these will be used as input for lssphere.
%Create vectors for each point in searchX_rough with start point
%threshold and ending point that particular point that is considered.
pCent = repmat(threshold, [length(searchX_rough),1]);
V = searchX_rough - pCent;
searchX_fine = []; %initialize empty list
for i = 1:size(V,1)
proj = dot(V(i,:), dir);
if proj > 0
%if this condition holds, the angle between dir drawn in
%threshold and the vector associated with a point of
%searchX_rough is smaller than 90 degrees, therefore the point
%lies on the same side of dir drawn in threshold and thus the
%point lies above the defined plane in threshold
searchX_fine = [searchX_fine; searchX_rough(i,:)];
end
end
% The method to restrict the length of the input list for the fitting
% function to 2000 is to pass over in a controlled, uniform way a fixed
% amount of points in the original list searchX_fine. The number of
171
% points to pass over is calculated and given by int_fine.
int_fine = ceil(length(searchX_fine)/2000);
searchX_fine = searchX_fine(1:int_fine:length(searchX_fine),:);
%MATLAB FILE EXCHANGE CENTRE
%the function doing the fitting to sphere of the points in searchX_fine.
[x0n2, rn2] = lssphere(searchX_fine, x0n, rn, 0.1, 0.1);
c_new = x0n2'; %the real center
r_new = rn2; %the real radius
diff_new = norm(c_new - c_old);
%Check whether the newly defined center has a distance to the old
%center of more than 0.25, if this holds do another fitting process.
if diff_new > 0.25 && count < 30
flag = 1;
c_old = c_new;
r_old = r_new;
count = count + 1;
else
flag = 0;
end
end
c = c_new; %the real center
r = r_new; %the real radius
B.2.3 epicondylesHum.m
function [e1 e2] = epicondylesHum(X)
%EPICONDYLES GIVES BACK THE 2 EPICONDYLES OF A HUMERUS ORIENTED ALONG THE
%POSITIVE Z-AXIS
%
%OUTPUT:
%
e1 and e2 are 1-by-3 array's of the coordinates of the epicondyles.
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m points that constitute
%
the humerus.
%
%
--------%
%
author : Bart Coppieters
%
%
max_z = max(X(:,3)); % highest point of oriented humerus
min_z = min(X(:,3)); % lowest point of oriented humerus
threshold = 0.15 * (max_z - min_z) + min_z;
% a value of z-coordinate that will be the upper boundary for the points to
% involve in the following step.
172
searchX = X(find(X(:,3) < threshold), :); %points below 'threshold'
[coeff, score] = princomp(searchX); %principal component analysis
e1 = searchX(find(min(score(:,1)) == score(:,1)),:); % the point with the
% smallest score (projection) on the principal axis of the data ('searchX')
e2 = searchX(find(max(score(:,1)) == score(:,1)),:); % the point with the
% biggest score (projection) on the principal axis of the data ('searchX')
B.2.4 greaterTubHum.m
function [greater] = greaterTubHum(X, c, r)
%GREATERTUBHUM CALCULATES THE POSITION OF THE GREATER TUBERCLE OF THE
%ORIENTED HUMERUS.
%
%OUTPUT:
%
greater is a 1-by-3 array of the coordinates of the greater tubercle
%
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute oriented right humerus.
%
%
c is a 1-by-3 array of the coordinates of the center of the real
%
head of the humerus (output of headHum.m)
%
%
r represents the radius of the real head of the humerus (output of
%
headHum.m)
%
--------%
%
author : Bart Coppieters
% Step 1: define a searchspace for the greater tubercle.
max_z = max(X(:,3));
min_z = min(X(:,3));
max_y = max(X(:,2));
min_y = min(X(:,2));
searchX = X(find( (X(:,1) < 0) & (X(:,2) < max_y*0.3 ) & ...
(X(:,2) > min_y*0.3) & (X(:,3) > 0.93 * (max_z - min_z) + min_z) ), :);
%Step 2
%select out of the list of points searchX those points with a distance
%to the middlepoint of the real head of the humerus that is bigger than
%the radius of this head. Make a new list of these points and name it
%list1.
list1 = []; %initialize empty list
for k=1:length(searchX)
if norm(searchX(k,:) - c) > r
list1 = [list1; searchX(k,:)];
end
end
%Step 3
%construct a list of dimension (length(list1), 1) with for each point of
173
%'list1' the orthogonal distance of this point to the sphere representing
%the real head.
list2 = []; %initialize empty list
for k=1:length(list1)
distance = norm(list1(k,:) - c) - r;
%calculates the orthogonal distance of a point lying outside of the
%sphere to the sphere.
list2 = [list2; distance];
end
%Step 4
%to get
%to the
greater
%of the
the greater tubercle: look at the point with the biggest distance
sphere.
= list1(find(list2(:,1) == max(list2(:,1))), :); %the coordinates
point with the biggest distance to the sphere.
B.2.5 lesserTubHum
function [lesser] = lesserTubHum(X, c, r)
%LESSERTUBHUM CALCULATES THE POSITION OF THE LESSER TUBERCLE OF THE
%ORIENTED RIGHT HUMERUS.
%
%OUTPUT:
%
lesser is a 1-by-3 array of the coordinates of the greater tubercle
%
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute humerus.
%
%
c is a 1-by-3 array of the coordinates of the center of the real
%
head of the humerus (output of headHum.m)
%
%
r represents the radius of the real head of the humerus (output of
%
headHum.m)
%
%
%
--------%
%
author : Bart Coppieters
%Step 1
% define a searchspace for the lesser tubercle.
max_z = max(X(:,3));
min_z = min(X(:,3));
max_x = max(X(:,1));
min_x = min(X(:,1));
searchX = X(find( (X(:,1) < max_x * 0.3) & (X(:,1) > min_x * 0.4 ) & ...
(X(:,2) < 0) & (X(:,3) > 0.90 * (max_z - min_z) + min_z) ), :);
%Step 2
%select out of the list of points searchX those points with a distance
%to the middlepoint of the real head of the humerus that is bigger than
174
%the radius of this head. Make a new list of these points and name it
%list1.
list1 = []; %initialize empty list
for k=1:length(searchX)
if norm(searchX(k,:) - c) > r
list1 = [list1; searchX(k,:)];
end
end
%Step 3
%construct a list of dimension (length(list1), 1) with for each point of
%'list1' the orthogonal distance of this point to the sphere representing
%the real head.
list2 = []; %initialize empty list
for k=1:length(list1)
distance = norm(list1(k,:) - c) - r;
%calculates the orthogonal distance of a point lying outside of the
%sphere to the sphere.
list2 = [list2; distance];
end
%Step 4
%to get the greater tubercle: look at the point with the biggest distance
%to the sphere.
lesser = list1(find(list2(:,1) == max(list2(:,1))), :); %the coordinates of
%the point with the biggest distance to the sphere.
B.2.6 trochHum.m
function [c,radius,normal] = trochHum(X, lowest, med_e)
%TROCHHUM DEFINES THE 3D CIRCLE APPROXIMATING THE TROCHLEA OF THE ORIENTED
%RIGHT HUMERUS.
%
%OUTPUT:
%
c is a 1-by-3 array of the coordinates of the center of the 3D circle
%
representing the trochlea
%
%
radius represents the radius of the calculated 3D circle
%
%
normal is a 1-by-3 array that represents the vector perpendicular to
%
the plane of the 3D circle
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the humerus.
%
%
lowest is a 1-by-3 array of the coordinates of the most distal point of
%
the humerus. (output of orientHumerus.m)
%
%
med_e is a 1-by-3 array of the coordinates of the medial epicondyle
%
(output of orientHumerus.m)
%
--------%
%
author : Bart Coppieters
175
%Step 1
%Construct a searchspace of points to hand over to a function carrying out
%the fitting of these points to the searched 3D circle.
searchX = [];
for i = 1:length(X)
if (X(i,3) < med_e(3) ) && (X(i,1) > lowest(1) - 1) && (X(i,1) <...
lowest(1) + 1)
searchX = [searchX; X(i,:)];
end
end
%Step 2
%Do the first fitting process.
%Initializations of the input arguments for the fitting function
%ls3dcircle.
x0 = lowest;
x0(3) = med_e(3)/2;
r0 = x0(3)/2;
a0 = [1 0 0];
tolp = 0.1;
tolg = 0.1;
%MATLAB FILE EXCHANGE CENTRE
%It takes a list of points and some
%initialization parameters as input and produces the center, the radius and
%the normal of the 3D circle that is the result of the least squares
%fitting method of the input list of points.
[x0n, an, rn] = ls3dcircle(searchX, x0', a0', r0, tolp, tolg);
c = x0n';
radius = rn;
normal = an';
%Step 3
%Compute the euclidean distance between every point of searchX and the
%center of the circle of the first fitting process.
d_searchX_c = sqrt(sum((searchX - repmat(c,length(searchX),1)).^2,2));
%Step 4
%Remove the initial outliers of the list searchX.
%Select only those points of SearchX that met certain conditions involving
%the standard deviation of the set of distances.
mu = mean(d_searchX_c);
sigma = std(d_searchX_c);
ind = [];
for i = 1:length(searchX)
if d_searchX_c(i) > radius - 3*sigma && d_searchX_c(i) < ...
radius + 3*sigma && searchX(i,3) < c(3)
ind = [ind; i];
end
end
searchX = searchX(ind,:);
%Step 5
176
%Second fitting process.
%Use the reduced list searchX as the input list to the function carrying
%out the fitting to a 3D circle, ls3dcircle.
x0 = mean(searchX);
a0 = [1 0 0];
tolp = 0.1;
tolg = 0.1;
%MATLAB FILE EXCHANGE CENTRE
[x0n, an, rn] = ls3dcircle(searchX, x0', a0', r0, tolp, tolg);
c = x0n';
radius = rn;
normal = an';
B.2.7 capitHum.m
function [c r] = capitHum(X, lat_e)
%CAPITHUM DEFINES THE SPHERE THAT APPROXIMATES THE CAPITULUM OF THE
%ORIENTED RIGHT HUMERUS.
%
%OUTPUT:
%
c is a 1-by-3 array of the coordinates of the center of the sphere
%
representing the approximated capitulum.
%
%
r represents the radius of the calculated sphere representing the
%
approximated capitulum
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the humerus.
%
%
lat_e is a 1-by-3 array of the coordinates of the lateral epicondyle
%
(output of orientHumerus.m)
%
--------%
%
author : Bart Coppieters
%Step 1
%Construct a searchspace of points to hand over to a function carrying out
%the fitting of this points to the searched sphere.
X = X(find(X(:,1) < lat_e(1)/2 & X(:,3) < lat_e(3)),:);%initial selection
%refinement of the initial selection
proj = zeros(length(X),1);
for i = 1:length(X)
proj(i) = dot(X(i,:), [0; -1; -1]);
end
pFit = X(find(proj == max(proj)),:); %the point with the biggest
%projection value
%Pick only those points that lie a small distance away from p_low. This
%small distance is defined relatively to the size of the bone.
177
fitX = [];
for i = 1:length(X)
if norm(pFit - X(i,:)) < norm(pFit - lat_e)/4
fitX = [fitX; X(i,:)];
end
end
%Step 2
%Do the fitting process.
%Make sure the input list for lssphere is smaller than or equal to 1000.
int_fit = ceil(length(fitX)/1000);
fitX = fitX(1:int_fit:end,:);
%MATLAB FILE EXCHANGE CENTRE
%It takes a list of points and some
%initialization parameters as input and produces the center and the radius
%of the sphere that is the result of the least squares fitting method
%of the input list of points.
[x0n, rn] = lssphere(fitX, mean(fitX)', 10, 0.1, 0.1);
c = x0n';
r = rn;
B.2.8 topHum.m
function
[top] = topHum(X)
%TOPHUM CALCULATES THE POSITION OF THE TOPMOST POINT OF THE ORIENTED
%HUMERUS
%
%OUTPUT:
%
top is a 1-by-3 array of the coordinates of the uppermost point on
%
the 3D model of the oriented humerus.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented humerus.
%
--------%
%
author : Bart Coppieters
%
%
top = X(find(X(:,3) == max(X(:,3))),:);
B.2.9 cylHum.m
function [radius, underP, upperP] = cylHum(X, cHead, rHead)
%CYLHUM CALCULATES THE RADIUS, THE UNDERMOST AND THE UPPERMOST POINT THAT
%DEFINE THE METAPHYSEAL CYLINDER
%
%OUTPUT:
%
radius represents the radius of the cylinder.
%
178
%
underP is a 1-by-3 array of the coordinates of the undermost point on
%
the axis of the determined cylinder
%
%
upperP is a 1-by-3 array of the coordinates of the uppermost point on
%
the axis of the determined cylinder
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented right humerus.
%
%
cHead is a 1-by-3 array of the coordinates of the center of the real
%
head of the humerus. (output of headHum.m)
%
%
rHead represents the radius of the real head of the humerus (output of
%
headHum.m)
%
--------%
%
author : Bart Coppieters
%
%Step 1
%Define the under boundary for z-values.
%look to the bone in the coronal plane, i.e. the x-z-plane. Thus setting
%each y coordinate to 0.
points_in_y_plane = [X(:,1) , zeros(length(X),1), X(:,3)];
%conserve only those points of the lateral half of the bone.
points_in_y_plane = points_in_y_plane(find(points_in_y_plane(:,1) < 0),:);
meanX = mean(X);
%discard the distal end of the list points_in_y_plane.
points_in_y_plane = points_in_y_plane(find(points_in_y_plane(:,3) >...
meanX(3)*0.9),:);
%Sort these points with respect to ascending z-value.
points_in_y_plane = sortrows(points_in_y_plane,3);
%In the following step we will look at the points of points_in_y_plane that
%have a z-value between begin and eind. We will distribute the points in
%function of their z-value in intervals of length 4 starting from begin.
%Of each interval we take that point with the biggest negative
%x-offset(smallest x-value). This will give us the contour of the lateral
%edge in the x-z plane.
begin = floor(meanX(3)*0.9);
eind = floor(max(points_in_y_plane(:,3)));
list_of_max = [];
for k = begin:8:eind
list_temp = [];
for j = 1:length(points_in_y_plane)
if (points_in_y_plane(j,3) >= k) && (points_in_y_plane(j,3)...
< k + 8)
list_temp = [list_temp; points_in_y_plane(j,:)];
%the set of points in an interval of length 8.
end
end
maxi = min(list_temp);
list_of_max = [list_of_max;k maxi]; %list of minimal x-offsets
179
end
%We had to use this technique, because the 3D model is not a continuum of
%points.
%move a window of size 4 over the list and look when the 4 values of the
%window meet a descending_ascending condition. If this condicion is met ->
%curve of shaft -> under boundary for the z-values
for i = 1:length(list_of_max) - 3
values = zeros(1, 4);
values(1) = list_of_max(i, 2);
values(2) = list_of_max(i + 1, 2);
values(3) = list_of_max(i + 2, 2);
values(4) = list_of_max(i + 3, 2);
if (values(1) > values(2)) && (values(2) > values(3)) && ...
(values(3) < values(4))
under = list_of_max(i+2, 1); %the under boundary value
break
end
end
%Step 2
%Define the upper boundary for z-values.
upper = cHead(3) - rHead; %the upper boundary value
%Step 3
%The fitting to a cylinder.
%The points that will be fitted to a cylinder have a z-value between under
%and upper.
fitX = X(find((X(:,3) > under) & (X(:,3) < upper)),:);
%The following function, lscylinder, is downloaded from the Matlab file
% exchange centre on the official Matlab site. It takes a list of points
% (fitX) and some initialization parameters as input and produces the
% midpoint on the axis, the direction and the radius of the fitted
% cylinder.
%initializations for lscylinder
x0 = [0 0 under/2+upper/2]';
a0 = [0 0 1]';
%MATLAB FILE EXCHANGE CENTRE
[x0n, an, rn] = lscylinder(fitX, x0, a0, abs(list_of_max(1,2)), 0.1, 0.1);
%The axis of the fitted cylinder is defined by its midpoint x0n and its
%direction, a0. The radius of the cylinder is rn.
radius = rn;
% To force underP, an output argument, on the axis of the fitted cylinder.
% We can construct the undermost point on the axis of the fitted cylinder
% with a z-value of under, the under boundary for z-values.
180
maal1 = (under - x0n(3))/an(3);
underP = (x0n + maal1 * an)';
% To force upperP, an output argument, on the axis of the fitted cylinder.
% We can construct the uppermost point on the axis of the fitted cylinder
% with a z-value of upper, the upper boundary for z-values.
maal2 = (upper - x0n(3))/an(3);
upperP = (x0n + maal2 * an)';
B.2.10 findRefP.m
function [under, upper] = findRefP(X)
%FINDREFP GIVES BACK THE 2 EXTREME POINTS ALONG THE
%PRINCIPAL AXIS OF THE HUMERUS
%
%OUTPUT:
%
under is a 1-by-3 array with the coordinates of the undermost point
%
upper is a 1-by-3 array with the coordinates of the uppermost point
%INPUT:
%
X is a m-by-3 array of the coordinates of the m datapoints.
%
%
--------%
%
author : Bart Coppieters
%
%
%Predefined function of the Matlab-library to carry out the principal
%component analysis of the data points of the bone, thus X.
%coeff will give the 3 principal components, score will give
%the coordinates of each point in X with respect to the base formed by the
%3 principal components.
[coeff,score] = princomp(X);
meanX = mean(X,1);
dirVect = coeff(:,1); %The principal component axis of the data.
a = min(score(:,1)); %The smallest coordinate (projection) on the dirVect
b = max(score(:,1)); %The biggest coordinate (projection) on the dirVect
% a and b are the 2 extreme points but in the case of the humerus I want a
% to be the distal end and b to be the proximal end. Therefore I see which
% part is the closest to a sphere, and this will be the proximal end.
indices_a = find(score(:,1)< a + 0.05 * (b-a));
indices_b = find(score(:,1)> b - 0.05 * (b-a));
a_list = X(indices_a,:);
b_list = X(indices_b,:);
sizeA = length(a_list);
sizeB = length(b_list);
181
%calculate the intervals so the inputs for the lssphere-functions
%have reasonable lengths with a maximum of 1000.
int_a = ceil(sizeA/1000);
int_b = ceil(sizeB/1000);
mean_a = mean(a_list);
mean_b = mean(b_list);
%lssphere is a predefined function to approximate a sphere given a bunch of
%datapoints using the 'least square fitting'-algorithm.
[x0n_a, rn_a, d_a] = lssphere(a_list(1:int_a:end,:), mean_a', 10, 1, 1);
[x0n_b, rn_b, d_b] = lssphere(b_list(1:int_b:end,:), mean_b', 10, 1, 1);
normA = norm(d_a);
normB = norm(d_b);
%definition of the points under and upper making use of dirVect and meanX.
if normA>normB
under = min(score(:,1))*dirVect' + meanX;
upper = max(score(:,1))*dirVect' + meanX;
else
under = max(score(:,1))*dirVect' + meanX;
upper = min(score(:,1))*dirVect' + meanX;
end
182
B.3
Scapula
B.3.1 orientScapula.m
function [x, y, z, n, extLat, extMed, side] = orientScapula(x,y,z,n)
%ORIENTSCAPULA WILL ORIENT A 3D-MODEL OF A SCAPULA FOR FURTHER PROCESSING,
%I.E. FEATURE EXTRACTION.
%
%OUTPUT:
%
x, y and z are 3-by-N matrices that together form the oriented patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the oriented patch object.
%
%
ext1 is a 1-by-3 array of the coordinates of the medial extreme point
%
of the superior part of the scapula. This point is used in subsequent
%
functions.
%
%
ext2 is a 1-by-3 array of the coordinates of the lateral extreme point
%
of the scapula. This point is used in subsequent
%
functions.
%
%
side is a scalar that serves as a logical to state whether it is a left
%
(side == 1) or a right (side == 0) bone.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the original patch object.
%
%
with N the number of facets of the 3D model
%
--------%
%
author : Bart Coppieters
%
%Step 1
% The list representation of the 3D model.
X = unique([x(:) y(:) z(:)],'rows');
%Step 2
%The mean of X will define a translation in such a manner that meanX is put
%in the origin (0,0,0).
%Do this translation for the whole bone
meanX = mean(X);
[x,y,z,zero] = translation(x,y,z,meanX,meanX);
X = unique([x(:) y(:) z(:)],'rows');
%Step 3
183
%Calculate for each point of X the euclidean distance to meanX, thus
%(0,0,0), and stock this together with the point in the length(X)-by-4
%matrix normX.
normX = zeros(length(X),4);
for i = 1:length(X)
normX(i,1:3) = X(i,:);
normX(i,4) = norm(X(i,:));
end
%Sorted list of points and corresponding norms.
%The norms are in descending order.
normX = sortrows(normX,-4);
%point with biggest euclidean distance to meanX
maxNorm = normX(1,1:3);
%Step 4
%Do a sequence of rotations of the bone in order to get point maxNorm to
%lie on the positive z-axis.
%A first rotation around the z-axis to force maxNorm into the x-z plane.
%angle over which to rotate around the z-axis
hoekz = -atan(maxNorm(2)/maxNorm(1));
[x,y,z, rotz] = rotation_Z_axe(x,y,z,hoekz);
n = rotz * n;
maxNorm = (rotz * maxNorm')';
%A second rotation around the y-axis to force maxNorm onto the z-axis.
%angle over which to rotate around the y-axis.
hoeky = -atan(maxNorm(1)/maxNorm(3));
[x,y,z, roty] = rotation_Y_axe(x,y,z,hoeky);
n = roty*n;
%rotated version of maxNorm.
maxNorm = (roty * maxNorm')' ;
%Step 5
%Do subsequent transformations to get the already oriented bone in the
%z>0-space, i.e. above the x-y plane.
%A first translation defined by maxNorm.
[x,y,z,o] = translation(x,y,z,maxNorm,maxNorm);
X = unique([x(:) y(:) z(:)],'rows');
%We do a 180 degrees-rotation if the the scapula lies upside down.
%This means that maxNorm has the highest z-value, thus 0.
if max(X(:,3)) <= 0
[x, y, z, rotx] = rotation_X_axe(x, y, z, pi);
n = rotx * n;
end
% List representation of the currently oriented bone.
184
X = unique([x(:) y(:) z(:)],'rows');
%Step 6
%Getting the triangular plane of the scapula to concede with the x-z plane.
%By now the bone is oriented along the z-axis.
%'upperX' will consist of the points that lie in the uppermost half of the
%the so far oriented 3D model of the scapula.
upperX = X(find(X(:,3)> 0.5*(max(X(:,3))-min(X(:,3)))),:);
%We do a pricipal component analysis of this data.
[coeff,score] = princomp(upperX);
a = min(score(:,1)); %The smallest coordinate on dirVect
b = max(score(:,1)); %The biggest coordinate on dirVect
% the point with the smallest score (projection) on the principal axis of
% the data ('upperX').
ext1 = upperX(find(score(:,1) == a),:);
% the point with the highest score (projection) on the principal axis of
% the data ('upperX').
ext2 = upperX(find(score(:,1) == b),:);
%Which extreme point has the biggest z-value? This point we will use in the
%further orientation of the bone, in such a way that this point (and all
%the other points of the bone) will be rotated around the z-axis on to the
%x-z plane.
if ext1(3) > ext2(3) %ext1 has the highest location.
%rotation with respect to ext1
%angle over which to rotate around the Z-axe.
hoekz = -atan(ext1(2)/ext1(1));
[x, y, z, rotz] = rotation_Z_axe(x, y, z, hoekz);
n = rotz*n;
extLat = (rotz * ext1')';
extMed = (rotz * ext2')';
else %ext2 has the highest location.
%rotation with respect to ext2
%angle over which to rotate around the Z-axe.
hoekz = -atan(ext2(2)/ext2(1));
[x, y, z, rotz] = rotation_Z_axe(x, y, z, hoekz);
n = rotz*n;
extMed = (rotz * ext1')';
extLat = (rotz * ext2')';
end
%Make sure extLat lies in the (X>0)-part of the space.
if extLat(1) < 0
%rotation around the z-axis over 180 degrees.
[x, y, z, rotz] = rotation_Z_axe(x, y, z, pi);
n = rotz*n;
extLat = (rotz * extLat')';
extMed = (rotz * extMed')';
185
end
% List representation of the currently oriented bone.
X = unique([x(:) y(:) z(:)],'rows');
%Step 7
%Looking if the bone is a right or a left one.
decideX = X(find(X(:,3) > extMed(3) & X(:,1) < ...
extMed(1) + 0.10*abs(extMed(1))),:);
%The highest (with respect to the z-axis) point of deciderP.
deciderP = decideX(find(decideX(:,3)==max(decideX(:,3))),:);
%Step 8
%Take a mirror image with respect to the x-z plane to transform a left bone
%into its right counterpart. Give back the side as an output argument.
%the bone is from a left arm
if extMed(2) > deciderP(2)
y = -y;
n(2,:) = -n(2,:);
extLat(2) = - extLat(2);
extMed(2) = - extMed(2);
side = 1;
%right
else
%we don't do nothing as we will work on the right scapula
side = 0;
end
B.3.2 infAngleScap.m
function [infAngle] = infAngleScap(X)
%INFANGLESCAP CALCULATES THE POSITION OF THE INFERIOR ANGLE OF THE ORIENTED
%RIGHT SCAPULA.
%
%OUTPUT:
%
infAngle is a 1-by-3 array of the coordinates of the inferior angle
%
of the oriented right scapula
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented right scapula.
%
%
--------%
%
author : Bart Coppieters
%
%
infAngle = X(find(X(:,3) == min(X(:,3))),:);
186
B.3.3 supAngleScap.m
function [supAngle] = supAngleScap(X, extMed, extLat)
%SUPANGLESCAP CALCULATES THE POSITION OF THE SUPERIOR ANGLE OF THE ORIENTED
% RIGHT SCAPULA.
%
%OUTPUT:
%
supAngle is a 1-by-3 array of the coordinates of the superior angle
%
of the right oriented scapula
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented right scapula.
%
%
extMed is a 1-by-3 array of the coordinates of the extreme on the
%
medial side of the oriented right scapula(defined in orientScapula)
%
%
extLat is a 1-by-3 array of the coordinates of the extreme on the
%
lateral side of the oriented right scapula(defined in orientScapula)
%
%
--------%
%
author : Bart Coppieters
%
%
%Step 1
%Define the initial search space as a selection out of all of the points of
%the bone.
searchX = X(find(X(:,1) < 0 & X(:,2) > 0 & X(:,3) > max(X(:,3)) * 0.5),:);
%Step 2
%Calculate for each point in searchX the orthogonal distance to the line
%defined by extMed and extLat.
dir = extMed - extLat;
for i = 1:length(searchX)
d(i) = distancePointLine3d(searchX(i,:), [extMed(1) ...
extMed(2) extMed(3) dir(1) dir(2) dir(3)]);
%The above function is downloaded from the Matlab file exchange center
%and calculates for a given point and line the othogonal distance
%between the point and the line.
end
%Step 3
%The superior angle is the point with the biggest orthogonal distance to
%the former defined line.
supAngle = searchX(find(d == max(d)),:);
187
B.3.4 acromialTipScap.m
function [acrTip] = acromialTipScap(x, y, z, n, extMed)
%ACROMIALTIPSCAP CALCULATES THE POSITION OF THE TIP OF THE ACROMION OF A
%RIGHT ORIENTED SCAPULA.
%
%OUTPUT:
%
acrTip is a 1-by-3 array of the coordinates of the tip of the acromion
%
of the right oriented scapula.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the patch
%
object of the oriented right scapula.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the patch object of the oriented right scapula.
%
%
with N the number of facets of the 3D model of the scapula.
%
%
extMed is a 1-by-3 array of the coordinates of the extreme on the
%
medial side of the scapula(defined in function orientScapula).
%
%
--------%
%
author : Bart Coppieters
%
%
%Step 1
%Construct a list-representation of x, y and z(patch representation).
X = unique([x(:) y(:) z(:)],'rows');
%Define for saving time more or less that part of the bone where the
%feature with certainty resides, the rough acromion, we will refer to it as
%the search space.
%We provide the patch representation and the corresponding
%list representation of the mentioned search space.
[x2 y2 z2 n2] = localPatchLimit(x, y, z, n, max(X(:,1)), max(X(:,1))/2, ...
max(X(:,2)), min(X(:,2)), max(X(:,3))+1,...
extMed(3) + (max(X(:,3)) - extMed(3))/2);
X2 = unique([x2(:) y2(:) z2(:)],'rows');
% Step 2
%Define for each vertex in the patch representation of the roughly selected
%acromion its neighboring vertices. This info will be stocked in V.
%Look to which facets each vertex belongs.
A = vertexInFaces(x2, y2, z2); %Appendix D
%Look for the neighboring points of each point of the search space. This
%yields V, a cell array. This will be used in step 4.
V = findPointNeigh(x2, y2, z2, A, 1); %Appendix D
%Step 3
%Initialize Macromion with p as only element.
188
p = X(find(X(:,3) == max(X(:,3))),:);
% Step 4
Macromion = p;
%Step 5
%Do the following iterative process: go repeatedly through Macromion and
%calculate of every point in Macromion its neighboring points and append
%them to Macromion. Do this until a certain stop condition is met.
lengths = 0;
stop = 0;
while stop == 0
lengths = [lengths, size(Macromion,1)];
for i = lengths(end-1)+1:lengths(end) %to be sure to calculate just
%once the neighbours of a point.
point = Macromion(i,:);
ind = find(X2(:,1) == point(1) & X2(:,2) == point(2)...
& X2(:,3) == point(3));
M = cell2mat(V{ind});
%The list of neigboring points of the i-th point in Macromion.
M = reshape(M,3,length(M)/3)';
for j = 2:2:length(M) %we pass by 1 point to save time.
if M(j,3) < max(X(:,3)) * 17/18
%the stop condition: if a newly added point has a z-value
%smaller than 17/18 of the max(all z-coordinates), than
%stop extending the list.
stop = 1;
break
end
%if the newly calculated neighbor, M(j,:) already is contained
%in Macromion, it will not be added to Macromion.
if abs(prod(Macromion(:,1) - M(j,1))) < 0.00001 && ...
abs(prod(Macromion(:,2) - M(j,2))) < 0.00001 && ...
abs(prod(Macromion(:,3) - M(j,3))) < 0.00001
%if both of the above conditions aren't fulfilled add the
%newly calculated point to Macromion.
else
Macromion = [Macromion;M(j,:)];
end
end
end
end
%Step 6
%Look for the tip end of the acromion and select of this tip the most
%lateral point.
yDist = norm(max(Macromion(:,2)) - min(X(:,2)));
zDist = norm(max(Macromion(:,3)) - min(Macromion(:,3)));
%Definition of the tip of the acromion. The
189
%parameters were set through trial and error to get the most suitable
%result.
searchTip = Macromion(find(Macromion(:,2)>...
max(Macromion(:,2))-1/5 * yDist),:);
%Selection of the most lateral point of the tip of searchTip.
acrTip = searchTip(find(searchTip(:,1) == max(searchTip(:,1))),:);
B.3.5 acrAngleScap.m
function [acrAngle] = acrAngleScap(x, y, z, n)
%ACRANGLESCAP CALCULATES THE POSITION OF THE ACROMIAL ANGLE OF A RIGHT
%ORIENTED SCAPULA.
%
%OUTPUT:
%
acrAngle is a 1-by-3 array of the coordinates of the acromial angle
%
of the right oriented scapula
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the patch
%
object of the oriented right scapula.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the patch object of the oriented right scapula.
%
%
with N the number of facets of the 3D model of the oriented scapula.
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% Define a search space in which to look for the acromial angle.
X = unique([x(:) y(:) z(:)],'rows');
%The list-representation of the search space
searchAng = X(find(X(:,1) > 0.5*max(X(:,1))& X(:,2) < 0.75*min(X(:,2))),:);
% The patch-representation of the search space, needed for step 2.
[x2 y2 z2 n2] = localPatchBunch(x,y,z, n, searchAng);
% Step 2
% Calculate for each point in this search space its mean curvature. Sort
% the points of the search space in order of ascending mean
% curvature. Select the 10 points with the smallest mean curvature.
cfinalang = globalCurvature(x2,y2,z2,n2,1); %Appendix D
curv = unique([x2(:) y2(:) z2(:) cfinalang(:)],'rows');
curv = sortrows(curv, 4);
% Select the points with the smallest mean curvature.
Smin = curv(1:10,1:3);
% Calculate the mean of these Smin.
Smean = mean(Smin);
190
% Step 3
% Calculate the point with the smallest distance to Smean. This will be
% the acromial angle.
% List of distances to Smean.
d = sqrt(sum((Smin - repmat(Smean,length(Smin),1)).^2,2));
% The output argument
acrAngle = Smin( find(d == min(d)),: );
B.3.6 corTipScap.m
function [corTip] = corTipScap(x, y, z, n, extMed)
%CORTIPSCAP CALCULATES THE POSITION OF THE TIP OF THE CORACOID PROCESS OF A
%RIGHT ORIENTED SCAPULA.
%
%OUTPUT:
%
corTip is a 1-by-3 array of the coordinates of the tip of the coracoid
%
process of the right oriented scapula
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the patch
%
object of the oriented right scapula.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the patch object of the oriented right scapula.
%
%
extMed is a 1-by-3 array of the coordinates of the extreme on the
%
medial side of the scapula(defined in function orientScapula).
%
%
with N the number of facets of the oriented 3D model of the scapula
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% Locate and isolate a part of the bone that with certainty contains the
% coracoid process, this will be referred to as the search space.
% We will provide the patch representation and the corresponding
% list representation of the mentioned search space.
% The boundaries are chosen by trial and error on the 13 scapulas in order
% to get a good starting search space. The patch representation of the
% search space will be the input for the neighbor defining function of Step
% 2.
X = unique([x(:) y(:) z(:)],'rows');
X = sortrows(X, -2);
% patch representation
[x2 y2 z2 n2] = localPatchLimit(x, y, z, n, max(X(:,1)), max(X(:,1))/2,...
max(X(:,2)), 0, max(X(:,3)), 0);
% list representation
X2 = unique([x2(:) y2(:) z2(:)],'rows');
191
% Step 2
% Define for each vertex in the patch representation of the search space
% its neighboring vertices. This info will be stocked in V.
%Look to which facets each vertex belongs.
A = vertexInFaces(x2, y2, z2); %Appendix D
%Look for the neighboring points of each point of the search space. This
%yields V, a cell array. This will be used in step 5.
V = findPointNeigh(x2, y2, z2, A, 1); %Appendix D
% Step 3
% Select the most anterior point of the search space, p.
p = X2(find(X2(:,2) == max(X2(:,2))),:);
%Step 4
%Initialize Mcoracoid with p as only element.
Mcoracoid = p;
% Step 5
% Do the following iterative process: go repeatedly through Mcoracoid and
% calculate of every point in Mcoracoid its neighboring points and append
% them to Mcoracoid. Do this until a certain stop condition is met.
lengths = [0];
stop = 0;
while stop == 0
lengths = [lengths, size(Mcoracoid,1)];
for i = lengths(end-1)+1:lengths(end)%to be sure to calculate just
%one time the neighbors of a point.
point = Mcoracoid(i,:);
ind = find(X2(:,1) == point(1) & X2(:,2) == point(2) & ...
X2(:,3) == point(3));
M = cell2mat(V{ind});
%The list of neigboring points of the i-th point in Mcoracoid.
M = reshape(M,3,length(M)/3)';
for j = 2:2:length(M) %we pass by 1 point to save time.
if M(j,2) < max(X2(:,2)) * 5/8
%the stop condition: if a newly added point has an x-value
%smaller than 3/4 of the max(all x-coordinates of the
%search space), than stop extending the list.
Mcoracoid = [Mcoracoid;M(j,:)];
stop = stop + 1;
end
%if the newly calculated neighbor, M(j,:), already is contained
%in Macromion, it will not be added to Mcoracoid.
if abs(prod(Mcoracoid(:,1) - M(j,1))) < 0.00001 ...
&& abs(prod(Mcoracoid(:,2) - M(j,2))) < 0.00001 ...
&& abs(prod(Mcoracoid(:,3) - M(j,3))) < 0.00001
%if both of the above conditions aren't fulfilled, add the
%newly calculated point to Mcoracoid.
192
else
Mcoracoid = [Mcoracoid;M(j,:)];
end
if stop == 1
disp('STOP')
break
end
end
if stop == 1
break
end
end
end
% Step 6
% Look for the lateral end part of the coracoid process and select of this
% end the most lateral and centic point.
% Sort the rows with descending x-value.
Mcoracoid = sortrows(Mcoracoid, -1);
% Select the first fifth part of points of this sorted list. This will
% represent the lateral end of the coracoid process
McoracoidTip = Mcoracoid(1:round(length(Mcoracoid)*0.2),:);
meanTip = mean(McoracoidTip);
% Make a list of euclidean distances to meanTip
d = sqrt(sum((McoracoidTip-repmat(meanTip,length(McoracoidTip),1)).^2,2));
% The output argument, the point with the smallest distance to meanTip.
corTip = McoracoidTip( find(d == min(d)),: );
B.3.7 trigSpinScap.m
function [trigSpin] = trigSpinScap(x, y, z, n, extMed)
%TRIGSPINSCAP CALCULATES THE POSITION OF THE ROOT OF THE SPINE OF A
%RIGHT ORIENTED SCAPULA.
%
%OUTPUT:
%
trigSpin is a 1-by-3 array of the coordinates of root of the spine
%
of the right oriented scapula.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the patch
%
object of the oriented right scapula.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the patch object of the oriented right scapula.
%
%
with N the number of facets of the 3D model
%
%
extMed is a 1-by-3 array of the coordinates of the extreme on the
%
medial side of the scapula(defined in function orientScapula).
%
%
--------%
%
author : Bart Coppieters
%
193
%
% Step 1
% Locate and isolate a part of the bone that with certainty contains the
% root of the spine, this will be referred to as the search space.
% The list representation of the input scapula.
X = unique([x(:) y(:) z(:)],'rows');
% Calculation of the midpoint along the z-axis.
mid = (max(X(:,3))-min(X(:,3)))/2;
% Specification of the list representation of the search space. This will
% depend on the original location of extMed. Dependent on extMed the
% boundaries are defined differently.
if extMed(2) > 0
searchX = X(find(X(:,1)<min(X(:,1))/2 & X(:,2)<extMed(2)/2 & ...
X(:,3)>mid),:);
else
searchX = X(find(X(:,1)<min(X(:,1))/2 & X(:,2)<extMed(2) & ...
X(:,3)>mid),:);
end
% The patch representation of the search space
[x2 y2 z2 n2] = localPatchBunch(x, y, z, n, searchX);
% Step 2
% Calculate for each point of searchX the mean curvature.
% cfinal is a 3-by-N matrix of the curvatures of each point in searchX
cfinal = calculateCurvature(x2,y2,z2,n2,1); %Appendix D
% Add cfinal as a column to the list representation of the search space,
% searchX. searchX will now have 4 columns and is sorted with an ascending
% 4th column, being the mean curvatures.
searchX = sortrows(unique([x2(:) y2(:) z2(:) cfinal(:)],'rows'),4);
% Select the first 5% of the sorted searchX. This will be a list of the 5%
% points of the search space with the smallest mean curvatures.
thr = ceil(length(searchX)*0.02);%determining the bounding index
searchXmin = searchX(1:thr,:);%selecting the first thr rows of searchX
% Step 3
% Calculate the euclidean distances of the points in searchXmin to the mean
% of the points in searchXmin.
meanSpin = mean(searchXmin(:,1:3));
d = sqrt(sum((searchXmin(:,1:3) - ...
repmat(meanSpin,length(searchXmin),1)).^2,2));
% Step 4
% Take only those points of searchXmin with a distance smaller than the
% mean distance to the mean of searchXmin.
searchX2 = searchXmin(find(d < mean(d)),:);
% Step 5
% Of this refined list of points, searchX2, take the most medial one. This
% is the output argument.
trigSpin = searchX2(find(searchX2(:,1) == min(searchX2(:,1))),1:3);
194
B.3.8 glenoidScap.m
function [glenoidC glenoidR glenoidNormal]= glenoidScap(x, y, z, n, corTip)
%INFANGLESCAP CALCULATES THE 3D CIRCLE THAT BEST FITS THE POINTS OF THE
%GLENOID LABRUM.
%
%OUTPUT:
%
glenoidC is a 1-by-3 array of the coordinates of the center of the 3D
%
circle represEnting the glenoid cavity.
%
%
glenoidR represents the radius of the calculated 3D circle.
%
%
glenoidNormal is a 1-by-3 array that represents the vector
%
perpendicular to the plane of the calculated 3D circle.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the patch
%
object of the oriented right scapula.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the patch object of the oriented right scapula.
%
%
corTip is a 1-by-3 array of the coordinates of the tip of the coracoid
%
process. (defined in function corTipScap)
%
%
with N the number of facets of the oriented 3D model.
%
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% Locate and isolate the points of the bone that will be given as input
% arguments to a function that will carry out the fitting to a 3D circle.
% This step will start with a search space and this space will be refined
% throughout this step.
% List representation of the entire input scapula.
X = unique([x(:) y(:) z(:)],'rows');
% All the points of the lateral side that have a smaller z-value than the
% z-value of the tip of the coracoid process.
searchX = X( find(X(:,1)> corTip(1) - 10 & X(:,3) <= corTip(3)),:);
% Making a list of euclidean distances to the tip of the coracoid process.
d = sqrt(sum((searchX - repmat(corTip,length(searchX),1)).^2,2));
%
%
M
%
%
M
%
%
M is the matrix with in each row a point of the search space and in the
last column the distance to the tip of the coracoid process.
= [searchX, d];
Sort M with respect to ascending distance to the tip of the coracoid
process.
= sortrows(M, 4);
Look which point is the closest to the tip of the coracoid process and
which is not a point of the coracoid process. This is a point of the
195
% glenoid labrum. We call this point gPoint.
for i = 2:length(M)
%Go through the sorted list and stop (and save the index) if the
%distance between two subsequent points in the list is bigger than 2.
%This represents the gap between the coracoid process and the glenoid
%labrum.
if M(i,4) - M( i-1 ,4) > 2
break
end
end
gPoint = M(i,1:3);
% Step 2
% Use gPoint to define a patch representation of the rough approximation of
% the glenoid cavity.
[x2 y2 z2 n2] = localPatchLimit(x,y,z, n, max(X(:,1)), gPoint(1), ...
gPoint(2), min(M(:,2)), gPoint(3), 0);
% Calculate for each point of this approximation the mean curvature.
cfinal = globalCurvature(x2,y2,z2,n2,1);
% Isolate the fifth of the points with the smallest mean curvatures, fitX1.
C = unique([x2(:) y2(:) z2(:) cfinal(:)],'rows');
C = sortrows(C, 4);
L = ceil(length(C) * 0.2);
fitX1 = C(1:L,1:3);
% Refine fitX1 for a better approximation of the points of the glenoid
% cavity, fitX2. fPoint is the most lateral point and because the glenoid
% cavity is oriented a bit upward, points below fpoint should not be
% involved in fitX2.
fPoint = fitX1(find(fitX1(:,1) == max(fitX1(:,1))),:);
fitX2 = fitX1(find(fitX1(:,3) > fPoint(3)),:);
% Step 3
% First fitting phase.
x0 = mean(fitX2);
r0 = max(fitX2(:,2)) - min(fitX2(:,2));
a0 = [1 0 0];
tolp = 0.1;
tolg = 0.1;
%MATLAB FILE EXCHANGE CENTRE
%It carries out the least squares fitting
%method to a 3d circle. It takes a list of points and some initialization
%parameters as input and produces the center, the radius and the normal of
%the fitted 3D circle.
[x0n, an, rn] = ls3dcircle(fitX2, x0', a0', r0, tolp, tolg);
glenoidC_rough = x0n';
glenoidR_rough = rn;
glenoidNormal_rough = an';
% Step 4
% Second, more refined fitting phase.
% The list of euclidean distances of the points of fitX2 to the center of
196
% the 3d circle fitted in step 3.
d_fitX_glenoidC = sqrt(sum((fitX2 - repmat(glenoidC_rough,...
length(fitX2),1)).^2,2));
% the mean distance and the standard deviation of the distances
mu = mean(d_fitX_glenoidC);
sigma = std(d_fitX_glenoidC);
% Discard the outliers from fitX2. Outliers are those points with a
% distance of sigma or bigger different of the radius of the 3d circle of
% step 3.
ind = [];
for i = 1:length(fitX2)
% contain only the points of fitX2 that lie closer than sigma to the
% radius of step 3 AND that lie lower than the center of step 3.
if d_fitX_glenoidC(i) > glenoidR_rough - sigma && d_fitX_glenoidC(i)...
< glenoidR_rough + sigma && fitX2(i,3) < glenoidC_rough(3)
ind = [ind; i];
end
end
% the refined list of points to give to the fitting function ls3dcircle.
fitX3 = fitX2(ind,:);
x0 = mean(fitX3);
r0 = max(fitX3(:,2)) - min(fitX3(:,2));
a0 = [1 0 0];
tolp = 0.1;
tolg = 0.1;
%MATLAB FILE EXCHANGE CENTRE
[x0n, an, rn] = ls3dcircle(fitX3, x0', a0', r0, tolp, tolg);
% The output arguments that define the 3d circle representing the lower
% part of the glenoid cavity.
glenoidC = x0n';
glenoidR = rn;
glenoidNormal = an';
197
B.4
Clavicle
B.4.1 orientClavicle.m
function [x, y, z, n, side] = orientClavicle(x,y,z,n)
%ORIENTCLAVICLE WILL ORIENT A 3D-MODEL OF A CLAVICLE FOR FURTHER
%PROCESSING, I.E. FEATURE EXTRACTION.
%
%OUTPUT:
%
x, y and z are 3-by-N matrices that together form the oriented patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the oriented patch object.
%
%
side is a scalar that serves as a logical to state whether it is a left
%
(side == 1) or a right (side == 0) bone.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the original patch object.
%
%
with N the total number of facets of the 3D model of the clavicle.
%
%
--------%
%
author : Bart Coppieters
%
%
%Step 1
%Define the prominent direction.
X = unique([x(:) y(:) z(:)],'rows');
[coeff,score] = princomp(X); %Predefined Matlab-function to carry out the
%principal component analysis. coeff will give the principal components
%directions, score will give the scores of the points with respect to
%the principal component space.
meanX = mean(X,1);
dirVect = coeff(:,1); %The principal component axis of the data.
a = min(score(:,1)); %The smallest coordinate on dirVect
b = max(score(:,1)); %The biggest coordinate on dirVect
%the two extreme points on the principal axis.
ext1 = a*dirVect' + meanX;
ext2 = b*dirVect' + meanX;
%Step 2
%First translation defined by meanX.
198
[x,y,z,o] = translation(x,y,z,meanX,meanX);
ext1 = ext1 - meanX;
ext2 = ext2 - meanX;
%Step 3
%Do a sequence of rotations to get ext2 onto the positive x-axis.
%Rotation around z-axis to get ext2 into the x-z plane on the half of the
%positive x-axis.
hoekz = -atan(ext2(2)/ext2(1)); %angle to rotate around the z-axis.
[x, y, z, rotz] = rotation_Z_axe(x,y,z,hoekz);
n = rotz*n;
ext2 = (rotz*ext2')';
ext1 = (rotz*ext1')';
% Rotate over 180 degrees if ext2 lies in the half of negative x-axis.
if ext2(1) < 0
[x, y, z, rotz] = rotation_Z_axe(x,y,z,pi);
n = rotz*n;
ext2 = (rotz*ext2')';
ext1 = (rotz*ext1')';
end
%Rotation around y-axis to get ext2 onto the positive x-axis.
hoeky = atan(ext2(3)/ext2(1));%angle over which to rotate around the y-axis
[x, y, z, roty] = rotation_Y_axe(x,y,z,hoeky);
n = roty*n;
ext2 = (roty*ext2')';
ext1 = (roty*ext1')';
%Step 4
%Do a rotation around the x-axis in order to get the same position as in
%the human body, that is the 'plane' lies in the x-y plane.
%Select along the prominent axis only the middle part.
%We need the patch object of the bone, rather than the list of points,
%because we have to do rotations of this part of the bone.
X = unique([x(:) y(:) z(:)],'rows');
[xresult yresult zresult nresult] = localPatchLimit(x, y, z, n, ...
max(X(:,1))* 0.4, min(X(:,1)) * 0.4, max(X(:,2)), min(X(:,2)),...
max(X(:,3)),min(X(:,3)));
%Do rotations in intervals of pi/36 rad and calculate in each end
%position the distance between the maximal y-value and the minimal y-value.
%The rotation that yields the biggest y-distance will be the wanted
%rotation.
j = 1;
for i = 0:pi/36:35/36*pi
[xb, yb, zb, rotx] = rotation_X_axe(xresult,yresult,zresult,i);
dist(j) = max(yb(:)) - min(yb(:)); %calculating the maximal y-distance
j = j+1;
end
hoekx = (find(dist == max(dist)) - 1) * pi/36; %calculating the angle
%associated with the biggest y-distance
[x, y, z, rotx] = rotation_X_axe(x,y,z,hoekx);
199
n =rotx*n;
X = unique([x(:) y(:) z(:)],'rows');
%Step 5
%Look which half has the biggest y-distance in this orientation. With this
%step we determine that the medial end lies onto the positive x-axis.
%Because the biggest part should be the lateral half.
leftpart = X(find( X(:,1) > 0.60 * min(X(:,1)) & X(:,1) < 0 ),:);
leftdist = max(leftpart(:,2)) - min(leftpart(:,2));
rightpart = X(find( X(:,1) < 0.60 * max(X(:,1)) & X(:,1) > 0 ),:);
rightdist = max(rightpart(:,2)) - min(rightpart(:,2));
%if this condition holds, the lateral half lies onto the positive x-axis,
%therefore we need a rotation of 180 degrees around the z-axis.
if rightdist > leftdist
[x, y, z, rotz] = rotation_Z_axe(x,y,z,pi);
n = rotz*n;
end
X = unique([x(:) y(:) z(:)],'rows');
%Step 6
%look where lies the posterior convexity this should lie in the half of
%the positive y-axis.
%Isolate the part to look.
leftpart = X(find( X(:,1) > 0.75 * min(X(:,1))&X(:,1)<0.25*min(X(:,1))),:);
leftmax = max(leftpart(:,2)); leftmin = min(leftpart(:,2));
%If this condition holds, the curve lies in the part of positive y-axis.
%This is specified by the logical latcurv.
if abs(leftmax) > abs(leftmin)
p = leftpart(find(leftpart(:,2) == max(leftpart(:,2))),:);%will be used
%to determine a search space in the next step.
latcurv = 1;
%In this case the curve lies in the part of the negative y-axis.
else
p = leftpart(find(leftpart(:,2) == min(leftpart(:,2))),:);
latcurv = 0;
end
%Step 7
%Look whether the bone lies in its natural position, i.e. the superior
%surface points upwards. We use the info provided by the curvature
%function to do this. On the inferior surface of the clavicle lies the
%conoid tubercle so determining more or less this tubercle will determine
%the inferior surface.
xdist = max(X(:,1))-min(X(:,1)); %maximal x-distance.
200
[x2, y2, z2, n2] = localPatchLimit(x, y, z, n, p(1) + xdist * 0.2, ...
0.85 * min(X(:,1)), p(2) + 10, p(2) - xdist * 0.1, max(X(:,3)), ...
min(X(:,3))); %the search space. Has to be a patch
%representation of the bone to give it to the curvature function.
cfinal = globalCurvature(x2, y2, z2, n2,1); %calculate the mean curvature
%Look for the 10 points that show the biggest convex mean curvature, i.e.
%the smallest values of the calculated mean curvature. The conoid tubercle
%exhibits namely convexity. The 10 point with smallest mean curvature are
%stocked in curveMatrix.
curveMatrix = sortrows(unique([x2(:) y2(:) z2(:) cfinal(:)],'rows'),4);
curveMatrix = curveMatrix(1:10,1:3);
meanSelect = mean(curveMatrix(:,:)); %the mean of these 10 points.
meanAll = mean(leftpart(:,3)); %the mean of the entire left part.
% a logical that specifies whether the bone lies with its superior surface
% upwards.
natural = meanSelect(3) < meanAll;
%Step 8
%Determine the side of the clavicle, left or right.
%This property can be determined by examining the 2 variables latcurv and
%meanSelect. Each combination of these will yield a side.
if latcurv
if natural
side = 0; %right side
else
side = 1; % left side
z = -z;
end
else
if ~natural
side = 0; %right side
[x, y, z, rotx] = rotation_X_axe(x,y,z,pi);
n = rotx*n;
else
side = 1; %left side
y = -y;
end
end
B.4.2 sternClav.m
function sternClav = sternClav(X)
%STERNCLAV CALCULATES THE POSITION OF THE MOST ANTERIOR POINT ON THE
%STERNOCLAVICULAR JOINT SURFACE OF THE ORIENTED RIGHT CLAVICLE.
%
%OUTPUT:
%
sternClav is a 1-by-3 array of the coordinates of the most anterior
%
point of the sternal joint surface of the oriented right clavicle.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
201
%
constitute the oriented right clavicle.
%
--------%
%
author : Bart Coppieters
%
%
%Locate the most medial part of the bone.
medX = X( find( X(:,1) > 0.95 * max(X(:,1))) , :);
%The most anterior point. The point in medX with the smallest y-value in
%the current orientation.
sternClav = medX( find( medX(:,2) == min(medX(:,2))),:);
B.4.3 acrClav.m
function acrClav = acrClav(X)
%ACRCLAV CALCULATES THE POSITION OF THE MOST POSTERIOR POINT ON THE
%ACROMIOCLAVICULAR JOINT SURFACE OF THE ORIENTED RIGHT CLAVICLE.
%
%OUTPUT:
%
acrClav is a 1-by-3 array of the coordinates of the most dorsal
%
point of the acromial joint surface of the oriented right clavicle.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented right clavicle.
%
--------%
%
author : Bart Coppieters
%
%
% The most lateral point. The point with the smalles x-value in the current
% orientation.
acrClav = X( find( X(:,1) == min(X(:,1))),:);
202
B.5
Ulna
B.5.1 orientUlna.m
function [x, y, z, n, side] = orientUlna(x,y,z,n)
%ORIENTULNA WILL ORIENT A 3D-MODEL OF AN ULNA FOR FURTHER PROCESSING,
%I.E. FEATURE EXTRACTION.
%
%OUTPUT:
%
x, y and z are 3-by-N matrices that together form the oriented patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the oriented patch object.
%
%
side is a scalar that serves as a logical to state whether it is a left
%
(side == 1) or a right (side == 0) bone.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the original input patch object.
%
with N the number of facets of the 3D model.
%
--------%
%
author : Bart Coppieters
%
% Step 1
% Define the principal component axis of the 3D model. This axis will be the
% best line around which the data of the 3D model is distributed.
% the list representation of the input patch representation of the entire
% ulna.
X = unique([x(:) y(:) z(:)],'rows');
%Predefined function of the Matlab-library to carry out the principal
%component analysis of the data points of the bone.
%coeff will give the main 3 principal components, score will give
%the coordinates of each point in X with respect to the base formed by the
%3 principal components.
[coeff,score] = princomp(X);
meanX = mean(X,1);
dirVect = coeff(:,1); %The principal component axis of the data.
a = min(score(:,1)); %The smallest coordinate (projection) on the dirVect
b = max(score(:,1)); %The biggest coordinate (projection) on the dirVect
temp11 = a*dirVect' + meanX; %an extreme point on the principal axis.
203
temp2 = b*dirVect' + meanX; %an extreme point on the principal axis.
% Step 2
% Do a translation defined by temp1.
[x,y,z,temp2] = translation(x,y,z,temp11,temp2);
temp1 = [0 0 0];
% Step 3
%Do a sequence of rotations of the 3D model of the ulna in order to get
%point temp2 to lie on the z-axis.
%First rotation around the z-axis to force temp2 into the x-z plane.
%Define the angle over which to rotate around the z-axis and carry out the
%rotation.
hoekz = -atan(temp2(2)/temp2(1));
[x, y, z, rotz] = rotation_Z_axe(x,y,z,hoekz); %of the patch representation
n = rotz * n; %of the matrix of normals.
temp2 = (rotz * temp2')'; %of temp2
%Second rotation around the y-axis to force temp2 on the z-axis.
%Define the angle over which to rotate around the y-axis and carry out the
%rotation.
hoeky = -atan(temp2(1)/temp2(3));
[x, y, z, roty] = rotation_Y_axe(x,y,z,hoeky); %of the patch representation
n = roty * n;%of the matrix of normals.
temp2 = (roty * temp2')';%of temp2
%Possibly third rotation around the y-axis if temp2 lies on the negative
%z-axis.
if temp2(3) < 0
[x, y, z, roty] = rotation_Y_axe(x,y,z,pi); %of the patch representation
n = roty * n;%of the matrix of normals.
temp2 = (roty * temp2')';%of temp2
end
X = unique([x(:) y(:) z(:)],'rows');
% Step 4
% Determine the right up-down orientation of the ulna, thus the orientation
% as in the forearm in a neutral vertical position.
% List representations of the two halves of the bone.
% On this moment it is not clear if upperX represents the distal or the
% proximal half of the bone. The same holds for underX.
midZ = max(X(:,3)) / 2;
upperX = X( find( X(:,3) > midZ ),:);
underX = X( find( X(:,3) < midZ ),:);
% Do for upperX and underX the projection onto the x-y plane and
% subsequently calculate for each point of both 2 dimensional lists of
% points its euclidean distance to the origin. Thus this is the same as
% calculating their x-y norm. Than select the biggest norm in both sets of
% points. ->maxUpperDist and maxUnderDist
upperX2 = upperX(:,1:2);
upperDist = sqrt(sum(upperX2.^2,2));
204
maxUpperDist = max(upperDist);
%biggest norm in the x-y plane of the uppermost half
underX2 = underX(:,1:2);
underDist = sqrt(sum(underX2.^2,2));
maxUnderDist = max(underDist);
%biggest norm in the x-y plane of the undermost half
%The proximal part (natural highest part) has a bigger norm in the x-y
%plane, so if we detect the biggest norm, we know that this corresponds to
%the proximal half of the ulna. And logically this half has to lie above
%the distal half.
if maxUpperDist < maxUnderDist
%If the above condition holds, the defined undermost half, underX,
%corresponds to the proximal part. Therefore a rotation around the y-axis
%of 180 degrees is executed.
%Rotation
[x, y, z, roty] = rotation_Y_axe(x,y,z,pi);%of the patch representation
n = roty * n;%of the matrix of normals.
temp1 = (roty * temp1')';%of temp 1.
temp2 = (roty * temp2')';%of temp 2.
end
%The correct specification of the two extreme points on the principal axis.
%proximal represents the most proximal point on this axis and distal the
%most distal. The current up down orientation of the bone is correct, thus
%we can say that the extreme point with the biggest z-value is proximal.
if temp1(3) > temp2(3)
proximal = temp1;
distal = temp2;
else
proximal = temp2;
distal = temp1;
end
%Do a translation defined by the most distal point, distal, in order to get
%the bone to lie in the half defined by the positive z-axis. This
%translation will be in the direction of the z-axis.
[x,y,z,proximal] = translation(x,y,z,distal,proximal);
%list representation of the currently oriented ulna.
X = unique([x(:) y(:) z(:)],'rows');
% Step 5
% Make the ulna's anterior aspect to point to the negative y-axis.
%list representation of the points with a z-value bigger than 80 %
%of the height of the bone. This is a set of the points of the proximal
%epiphysis.
upperX = X( find( X(:,3) > max(X(:,3)) * 0.85 ),:);
%Do rotations around the z-axis with well chosen angles and calculate for
%each outcome orientation the maximal y-distance of the proximal epiphysis.
%Store these y-distances in dist.
205
% the patch representation of list representation upperX
[x2, y2, z2, n2] = localPatchBunch(x, y, z, n, upperX);
j = 1;
for i = 0: pi/36: 35/36*pi
%We take steps of pi/36 and go not further than pi because this would
%produce double work. The y-distance for pi/36 and for 37 * pi/36 is the
%same.
%Do the rotation around the z-axis of i * (180/pi) degrees.
[xb, yb, zb, rotz] = rotation_Z_axe(x2,y2,z2,i); %the patch
%representation of upperX
dist(j) = max(yb(:)) - min(yb(:)); %the maximal y-distance in this
%orientation.
j = j+1;
end
%Look for the angle which yields the biggest y-distance with the help of
%dist and use this angle to rotate around the z-axis once more.
hoekz = (find(dist == max(dist)) - 1) * pi/36;
[x, y, z, rotz] = rotation_Z_axe(x,y,z,hoekz);
n =rotz*n;
if max(y(:)) > abs(min(y(:)))
%The coronoid process lies in the part of space defined by the positive
%y-axis, therefore the ulna's anterior aspect points towards the positive
%y-axis. -> Do a rotation over 180 degrees around the z-axis.;
[x, y, z, rotz] = rotation_Z_axe(x,y,z,pi);
n =rotz*n;
end
% Step 6
%Look whether it is a right or a leftsided bone.
%list representation of the currently oriented ulna.
X = unique([x(:) y(:) z(:)],'rows');
lowest = X(find(X(:,3) == min(X(:,3))),:);
if lowest(1)< 0 %left bone
x = -x;
side = 1;
else
side = 0;
end
B.5.2 olecranonUlna.m
function [olecUlna] = olecranonUlna(X)
%OLECRANONULNA CALCULATES THE POSITION OF THE APEX OF THE OLECRANON OF THE
%ORIENTED RIGHT ULNA.
%
%OUTPUT:
%
olecUlna is a 1-by-3 array of the coordinates of the apex of the
%
olecranon.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
206
%
%
%
%
%
%
constitute the oriented right ulna.
--------author : Bart Coppieters
% Step 1
% List representation of the highest 3% of the oriented ulna.
upperX = X( find( X(:,3) > min(X(:,3)) + 0.98 * (max(X(:,3)) min(X(:,3)))),:);
% Step 2
% The apex of the olecranon is the point of upperX with the biggest
% y-value.
olecUlna = upperX( find( upperX(:,2) == max(upperX(:,2))),:);
B.5.3 coronoidUlna.m
function [corUlna] = coronoidUlna(X)
%OLECRANONULNA CALCULATES THE POSITION OF THE APEX OF THE OLECRANON OF THE
%ORIENTED RIGHT ULNA.
%
%OUTPUT:
%
corUlna is a 1-by-3 array of the coordinates of the coronoid process
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented right ulna.
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% The apex of the olecranon is the point of upperX with the smallest
% y-value.
corUlna = X( find( X(:,2) == min(X(:,2))),:);
B.5.4 styloidUlna.m
aaaa
function [stylUlna] = styloidUlna(X)
%STYLOIDULNA CALCULATES THE POSITION OF THE TIP OF THE STYLOID PROCESS OF
%THE ORIENTED RIGHT ULNA.
%
%OUTPUT:
%
stylUlna is a 1-by-3 array of the coordinates of the tip of the styloid
%
process of the ulna.
%
%INPUT:
207
%
%
%
%
%
%
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
constitute the oriented right ulna.
--------author : Bart Coppieters
%The most distal point or in other words the point with the smallest
%z-value.
stylUlna = X( find( X(:,3) == min(X(:,3))),:);
B.5.5 headUlna.m
function [sphCentUlna sphRadUlna] = headUlna(X)
%HEADULNA DEFINES THE SPHERE THAT APPROXIMATES THE ULNAR HEAD OF THE
%ORIENTED RIGHT ULNA.
%
%OUTPUT:
%
sphCentUlna is a 1-by-3 array of the coordinates of the center of the
%
sphere representing the approximated ulnar head.
%
%
sphRadUlna represents the radius of the calculated sphere representing
%
the approximated ulnar head.
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
together make up the humerus.
%
%
--------%
%
author : Bart Coppieters
% Step 1
% Define a initial search space that contain with certainty the points of
% the ulnar head. This is the distalmost part of the ulna.
underX1 = X( find( X(:,3) < min(X(:,3)) + ...
0.05 * (max(X(:,3)) - min(X(:,3)))),:);
%The maximal y-distance between points in underX1.
yDist = max(underX1(:,2)) - min(underX1(:,2));
% Step 2
%Make a list of points that have to be involved in the sphere fitting.
vector = [-1 -1 0]/norm([-1 -1 0]);
%The lowest point -> styloid process
lowest = X( find( X(:,3) == min(X(:,3))),:);
%For each point of underX1, make a vector that starts in (lowest +
%yDist/2*vector) in the direction defined by the line between the point and
%(lowest + 2*yDist/3*vector). The point (lowest + 2*yDist/3*vector) will
%have the same z-value as lowest and will be situated more to the center.
208
underV = underX1 - repmat(lowest + vector * 2*yDist/3,length(underX1),1);
for i = 1:length(underV)
proj(i) = dot(vector, underV(i,:));
end
underX2 = underX1(find(proj > 0),:);
%Step 3
%The fitting of underX2 to a sphere.
%pass over a number of interval points in underX to get a list with less
%than 1000 points. ->fitX
interval = ceil(length(underX2)/1000);
fitX = underX2(1:interval:end,:);
meanX = mean(fitX);
%MATLAB FILE EXCHANGE CENTRE
%Does a sphere fit of the points contained in fitX.
%x0n is the center of the fitted sphere.
%rn is the radius of the fitted sphere.
[x0n, rn] = lssphere(fitX, meanX', 0.01 * ...
(max(X(:,3)) - min(X(:,3))), 0.01, 0.01);
%the output arguments.
sphCentUlna = x0n';
sphRadUlna = rn;
209
B.6
Radius
B.6.1 orientRadius.m
function [x, y, z, n, side] = orientRadius(x,y,z,n)
%ORIENTRADIUS WILL ORIENT A 3D-MODEL OF A RADIUS FOR FURTHER PROCESSING,
%I.E. FEATURE EXTRACTION.
%
%OUTPUT:
%
x, y and z are 3-by-N matrices that together form the oriented patch
%
object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the oriented patch object.
%
%
side is a scalar that serves as a logical to state whether it is a left
%
(side == 1) or a right (side == 0) bone.
%
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the original input patch object.
%
%
with N the number of facets of the 3D model.
%
--------%
%
author : Bart Coppieters
%
% Step 1
% Define the principal component axis of the 3D model. This axis will be
% the best line around which the data of the 3D model is distributed.
% the list representation of the input patch representation of the entire
% radius.
X = unique([x(:) y(:) z(:)],'rows');
%Predefined function of the Matlab-library to carry out the principal
%component analysis of the data points of the bone.
%coeff will give the main 3 principal components, score will give
%the coordinates of each point in X with respect to the base formed by the
%3 principal components.
[coeff,score] = princomp(X);
meanX = mean(X,1);
dirVect = coeff(:,1); %The principal component axis of the data.
a = min(score(:,1)); %The smallest coordinate (projection) on the dirVect
b = max(score(:,1)); %The biggest coordinate (projection) on the dirVect
210
temp11 = b*dirVect' + meanX; %an extreme point on the principal axis.
temp2 = a*dirVect' + meanX; %an extreme point on the principal axis.
% Step 2
% Do a translation defined by temp1.
[x,y,z,temp2] = translation(x,y,z,temp11,temp2);
temp1 = [0 0 0];
% Step 3
%Do a sequence of rotations of the 3D model of the radius in order to get
%point temp2 to lie on the z-axis.
%First rotation around the z-axis to force temp2 into the x-z plane.
%Define the angle over which to rotate around the z-axis and carry out the
%rotation.
hoekz = -atan(temp2(2)/temp2(1));
[x, y, z, rotz] = rotation_Z_axe(x,y,z,hoekz); %of the patch representation
n = rotz * n; %of the matrix of normals.
temp2 = (rotz * temp2')'; %of temp2
%Second rotation around the y-axis to force temp2 on the z-axis.
%Define the angle over which to rotate around the y-axis and carry out the
%rotation.
hoeky = -atan(temp2(1)/temp2(3));
[x, y, z, roty] = rotation_Y_axe(x,y,z,hoeky); %of the patch representation
n = roty * n;%of the matrix of normals.
temp2 = (roty * temp2')';%of temp2
%Possibly third rotation around the y-axis if temp2 lies on the negative
%z-axis.
if temp2(3) < 0
[x, y, z, roty] = rotation_Y_axe(x,y,z,pi);%of the patch representation
n = roty * n;%of the matrix of normals.
temp2 = (roty * temp2')';%of temp2
end
X = unique([x(:) y(:) z(:)],'rows');
% Step 4
% Determine the right up-down orientation of the radius, thus the
% orientation as in the forearm in a neutral vertical position.
% List representations of the two halves of the bone.
% On this moment it is not clear if upperX represents the distal or the
% proximal half of the bone. The same holds for underX.
midZ = max(X(:,3)) / 2;
upperX = X( find( X(:,3) > midZ),:);
underX = X( find( X(:,3) < midZ),:);
% Do for upperX and underX the projection onto the x-y plane and
% subsequently calculate for each point of both 2 dimensional lists of
% points its euclidean distance to the origin. Thus this is the same as
% calculating their x-y norm. Than select the biggest norm in both sets of
% points. -> maxUpperDist and maxUnderDist
upperX2 = upperX(:,1:2);
211
upperDist = sqrt(sum(upperX2.^2,2));
maxUpperDist = max(upperDist);
underX2 = underX(:,1:2);
underDist = sqrt(sum(underX2.^2,2));
maxUnderDist = max(underDist);
% The proximal part (natural highest part) has a smaller norm in the x-y
% plane, so if we detect the smallest norm, we know that this corresponds to
% the proximal half of the radius.
if maxUpperDist > maxUnderDist
% The above condition states that the undermost half, underX,
% corresponds to the proximal part. Therefore a rotation around the y-axis
% of 180 degrees is executed.
[x, y, z, roty] = rotation_Y_axe(x,y,z,pi);
n = roty * n;
temp1 = (roty * temp1')';
temp2 = (roty * temp2')';
end
%The correct specification of the two extreme points on the principal axis.
%proximal represents the most proximal point on this axis and distal the
%most distal. The current updown orientation of the bone is correct, thus
%we can say that the extreme point with the biggest z-value is proximal.
if temp1(3) > temp2(3)
proximal = temp1;
distal = temp2;
else
proximal = temp2;
distal = temp1;
end
%Do a translation defined by the most distal point, distal. This
%translation will be in the direction of the z-axis.
[x,y,z,proximal] = translation(x,y,z,distal,proximal);
%list representation of the currently oriented radius.
X = unique([x(:) y(:) z(:)],'rows');
%Step 5
%Determine whether it is a right or a left radius.
% The point with the smallest z-coordinate, this value will be 0 in the
% current orientation.
lowest = X( find( X(:,3) == min(X(:,3))),:);
%Do a rotation around the z-axis in order to get lowest in the x-z plane.
hoekz = -atan(lowest(2)/lowest(1)); %the angle
[x, y, z, rotz] = rotation_Z_axe(x,y,z,hoekz);
n =rotz*n;
lowest = (rotz * lowest')';
% We want lowest to have a negative x-value, so if its x-value is positive
% -> rotate the model over 180 degrees around the z-axis.
212
if lowest(1) > 0
[x, y, z, rotz] = rotation_Z_axe(x,y,z,pi);
n =rotz*n;
lowest = (rotz * lowest')';
end
%list representation of the currently oriented radius.
X = unique([x(:) y(:) z(:)],'rows');
%Search for the point with the biggest x-y norm in the proximal fourth of
%the bone. This point is situated on the radial tuberosity. The y-value of
%this point will give us the info to decide upon the side of the bone.
upperX = X( find( X(:,3) < max(X(:,3)) & X(:,3) > 0.75 * max(X(:,3)) ),:);
upperX2 = upperX(:,1:2);
upperDist = sqrt(sum(upperX2.^2,2));
radTub = upperX( find( upperDist == max(upperDist)),:);
%In the current orientation, with lowest on the negative x-axis, the radial
%tuberosity, radTub, should have a negative y-value. Thus if the y-value of
%radTub is positive, we can decide that the bone is a leftsided one. In
%this case we do a mirror operation of the entire bone with respect to the
%x-z plane.
if radTub(2) > 0 %a left bone
side =1;
y = -y;
radTub(2) = -radTub(2);
else % a right bone
side = 0;
end
%
%Step 6
%Last orientation fact: make the orientation equal to the one in the body.
%That is: the radial tuberosity is pointing medialwards. For this to happen
%we force the radial tuberosity into the x-z plane on the side of the
%positive x-axis. This done by a rotation around the z-axis.
hoekz = -atan(radTub(2)/radTub(1));
[x, y, z, rotz] = rotation_Z_axe(x,y,z,hoekz);
n =rotz*n;
radTub = (rotz * radTub')';
%If after the rotation the radial tuberosity lies on the negative x-axis,
%that means it points lateralwards. Another rotation of 180 degrees
%around the z-axis is needed in this case.
if radTub(1) < 0
[x, y, z, rotz] = rotation_Z_axe(x,y,z,pi);
n =rotz*n;
end
B.6.2 headRadius.m
function [headRad radiusHeadRad] = headRadius(X)
%HEADRADIUS CALCULATES THE POSITION OF THE CENTER AND THE RADIUS OF THE
%SPHERE THAT IS FITTED WITH THE POINTS OF THE SUPERIOR SURFACE OF THE
%RADIAL HEAD.
213
%
%OUTPUT:
%
headRad is a 1-by-3 array of the coordinates of the center of the
%
fitted sphere.
%
%
radiusHeadRad represents the radius of the fitted sphere.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the right oriented radius.
%
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% Defining the center point of the cup, orig.
%List representation of the highest 20% of the oriented radius.
upperX = X(find(X(:,3) > max(X(:,3)) * 0.8) , :);
[coeff,score] = princomp(upperX);
%Predefined function of the Matlab-library to carry out the principal
%component analysis of the data points in upperX.
%coeff will give the main 3 principal components, score will give
%the coordinates of each point in upperX with respect to the base formed by
%the 3 principal components, saved in coeff.
meanX = mean(upperX,1);
dirVect = coeff(:,1); %The principal axis of the data.
a = min(score(:,1)); %The smallest coordinate on dirVect
b = max(score(:,1)); %The biggest coordinate on dirVect
%The two extreme points on the principal axis.
temp1 = b*dirVect' + meanX;
temp2 = a*dirVect' + meanX;
%orig has to be the extreme point with the biggest z-value.
if temp1(3) > temp2(3)
orig = temp1;
else
orig = temp2;
end
% Step 2
% list representation of the top 5% of the oriented radius.
upperX = X(find(X(:,3) > max(X(:,3)) * 0.95) , :);
% Calculate for each point of upperDist its orthogonal distance to the axis
% parallel to the z-axis that contains orig. This is the same as the
% distance to orig in the x-y plane.
upperX2 = upperX(:,1:2); %two dimensional equivalent of upperX in the x-y
%plane
% upperDist is the list with distances to orig in the x-y plane.
origM = repmat(orig(1:2),length(upperX2),1);
upperDist = sqrt(sum((upperX2-origM).^2,2));
%Step 3
214
% Define the list of data that will be fitted to the sphere
% fitX will be the list that is given to the function carrying out the
% least square fitting to a sphere.
% Select only those points of upperX, that have a x-y distance to
% orig of less than 30 % the maximal horizontal distance to orig.
fitX = upperX( find( upperDist < max(upperDist) * 0.3),:);
% Step 4
%The fitting phase
%MATLAB FILE EXCHANG CENTRE
%The following function is downloaded from the Matlab file exchange centre
%on the official Matlab site. It takes a list of points, in this case fitX
%and some initialization parameters as input and produces the center and
%the radius of the sphere that best fits the input data.
[x0n, rn] = lssphere(fitX, mean(fitX)', 10, 0.1, 0.1);
headRad = x0n'; %the position of the center of the fitted sphere
radiusHeadRad = rn; %the radius of the fitted sphere.
B.6.3 cylRadius.m
function [radius under upper] = cylRadius(X)
%CYLRADIUS CALCULATES THE RADIUS, THE UNDERMOST AND THE UPPERMOST POINT
%OF THE CYLINDER THAT APPROXIMATES THE RADIAL HEAD PERIPHERY.
%
%OUTPUT:
%
under and upper are 1-by-3 arrays of the coordinates of respectively
%
the under- and uppermost point on the axis of the fitted cylinder.
%
%
radius represents the radius of the fitted cylinder
%
%INPUT:
%
X is a m-by-3 array of the coordinates of the m datapoints that
%
constitute the oriented right radius.
%
--------%
%
author : Bart Coppieters
%
%
% Step 1
% Defining the center point of the cup, orig.
%List representation of the highest 20% of the oriented radius.
upperX = X(find(X(:,3) > max(X(:,3)) * 0.8) , :);
[coeff,score] = princomp(upperX);
%Predefined function of the Matlab-library to carry out the principal
%component analysis of the data points in upperX.
%coeff will give the main 3 principal components, score will give
%the coordinates of each point in upperX with respect to the base formed by
%the 3 principal components, saved in coeff.
meanX = mean(upperX,1);
dirVect = coeff(:,1); %The principal axis of the data.
215
a = min(score(:,1)); %The smallest coordinate on dirVect
b = max(score(:,1)); %The biggest coordinate on dirVect
%The two extreme points on the principal axis.
temp1 = b*dirVect' + meanX;
temp2 = a*dirVect' + meanX;
%orig has to be the extreme point with the biggest z-value.
if temp1(3) > temp2(3)
upper = temp1;
else
upper = temp2;
end
% Step 2
% list representation of the top 5% of the oriented radius.
upperX = X(find(X(:,3) > max(X(:,3)) * 0.95) , :);
% Calculate for each point of upperDist its orthogonal distance to the axis
% parallel to the z-axis that contains orig. This is the same as the
% distance to orig in the x-y plane.
upperX2 = upperX(:,1:2); %two dimensional equivalent of upperX in the x-y
%plane
% upperDist is the list with distances to orig in the x-y plane.
origM = repmat(upper(1:2),length(upperX2),1);
upperDist = sqrt(sum((upperX2-origM).^2,2));
% Step 3
% Define the list of data that will be fitted to the cylinder.
% fitX will be the list that is given to the function carrying out the
% least square fitting to a cylinder.
% Select only those points of upperX, that have a x-y distance to
% upper of more than 80 % the maximal horizontal distance to upper.
fitX = upperX( find( upperDist > max(upperDist) * 0.8),:);
% Step 4
%MATLAB FILE EXCHANGE CENTRE
%The fitting phase
%The following function is downloaded from the Matlab file exchange centre
%on the official Matlab site. It takes a list of points, in this case fitX
%and some initialization parameters as input and produces the center, the
%radius and the direction of the axis of the cylinder that best fits the
%input data.
x0 = upper';
a0 = [0 0 1]';
[x0n, an, rn] = lscylinder(fitX, x0, a0, max(upperDist), 0.1, 0.1);
% Definitions of the output arguments.
radius = rn;
%Assuring the direction has an upwards pointing orientation.
%Only important in defining under.
if dirVect(3) < 0
dirVect = -dirVect;
end
% under lies 5% of the total length of the radius lower than upper while
% following the direction of dirVect of step 1.
under = upper - 0.05 * max(X(:,3)) * dirVect';
216
B.6.4 styloidRadius.m
function [stylRad] = styloidRadius(X)
%STYLOIDRADIUS CALCULATES THE POSITION OF THE TIP OF THE STYLOID PROCESS OF
%THE 3D MODEL OF THE ORIENTED RIGHT RADIUS.
%
%OUTPUT:
%
stylRad is a 1-by-3 array of the coordinates of the tip of the styloid
%
process of the oriented right radius.
%
%INPUT:
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the oriented right radius.
%
--------%
%
author : Bart Coppieters
%
%
%The most distal point or in other words the point with the smallest
%z-value.
stylRad = X(find( X(:,3) == min(X(:,3))),:);
217
B.7 General functions
In this section come some functions used by all the functional procedures of the 5 bone types.
B.7.1 rotation_X_axe
This is the function responsible for a rotation around the x-axis. The functions of the rotations
around the y-axis and z-axis are the same apart from some parameters.
function varargout = rotation_X_axe(varargin)
%ROTATION_X_AXE DOES A ROTATION AROUND THE X-AXis OF ALL THE POINTS IN 3D
%
% 2 forms of use:
%
1 input for 1 output:
%
rot_x = rotation_X_axe(hoekx)
%
4 inputs for 4 outputs:
%
[xx, yy, zz, rot_x] = rotation_X_axe(x, y, z, hoekx)
%
%OUTPUT: variable
%
1 output: rot_x is a 3-by-3 rotation matrix
%
%
4 outputs:
%
xx, yy and zz are 3-by-m matrices of respectively the x-, y- and
%
z-coordinates of the points that constitute the facets of the rotated
%
3D model.
%
rot_x is a 3-by-3 rotation matrix defined by the angle hoekx.
%
%INPUT: variable
%
1 input: hoekx is the angle in rad over which will be rotated.
%
%
4 inputs:
%
x, y and z are 3-by-m matrices of respectively the x-, y- and
%
z-coordinates of the points that constitute the facets of the
%
unrotated 3d-model.
%
hoekx is the angle in rad over which will be rotated.
%
%
%
--------%
%
author : Bart Coppieters
%
%
%input
if length(varargin)==1
hoekx = varargin{1};
x = 0; y = 0; z = 0;
elseif length(varargin)==4
x = varargin{1};
y = varargin{2};
z = varargin{3};
218
hoekx = varargin{4};
end
[hx bx] = size(x);
[hy by] = size(y);
[hz bz] = size(z);
xx = zeros(hx,bx);
yy = zeros(hy,by);
zz = zeros(hz,bz);
rot_x = [1 0 0;0 cos(hoekx) sin(hoekx); 0 -sin(hoekx) cos(hoekx)]; % creation
of the rotation matrix defined by hoekx
% carry out the rotation for every point
if(hx==hy && hx==hz && bx==by && bx==bz)
for i=1:hx
for j=1:bx
gedraaid = rot_x * [x(i,j); y(i,j); z(i,j)];
xx(i,j) = gedraaid(1);
yy(i,j) = gedraaid(2);
zz(i,j) = gedraaid(3);
end
end
end
%output
if nargout == 1
varargout{1} = rot_x;
elseif nargout == 4
varargout{1} = xx;
varargout{2} = yy;
varargout{3} = zz;
varargout{4} = rot_x;
end
B.7.2 translation.m
function [xx,yy,zz,bb] = translation(x,y,z,a,b)
%TRANSLATION DOES A TRANSLATION OF ALL THE POINTS IN 3D DEFINED BY INPUT
%ARGUMENT A.
%
%OUTPUT:
%
xx, yy and zz are 3-by-m matrices of respectively the x-, y- and
%
z-coordinates of the points that constitute the facets of the translated
%
3D model, thus the patch representation.
%
bb is the translated 1-by-3 array of a chosen point of interest.
%
%INPUT:
%
x, y and z are 3-by-m matrices of respectively the x-, y- and
%
z-coordinates of the points that constitute the facets of the
untranslated
%
3D model, thus the patch representation.
%
a is a 1-by-3 array of the coordinates of the point that will define
219
%
%
%
%
%
%
%
%
%
the translation.
b is a 1-by-3 array of the coordinates of a chosen point of interest.
--------author : Bart Coppieters
[hx bx] = size(x);
[hy by] = size(y);
[hz bz] = size(z);
% the output variables.
xx = zeros(hx,bx);
yy = zeros(hy,by);
zz = zeros(hz,bz);
% the linear translation, defined by a.
xx = x - a(1) * ones(size(x));
yy = y - a(2) * ones(size(x));
zz = z - a(3) * ones(size(x));
% the translation of b, a point of interest.
bb = b - a;
B.7.3 localPatchLimit
function [xresult yresult zresult nresult] = ...
localPatchLimit(x, y, z, n, xmax, xmin, ymax, ymin, zmax, zmin)
%FUNCTION TO CONSTRUCT A PATCH OBJECT CONSTRAINED BY LIMITS.
biggestx = max(x);
smallestx = min(x);
biggesty = max(y);
smallesty = min(y);
biggestz = max(z);
smallestz = min(z);
logicbigx =
logicsmallx
logicbigy =
logicsmally
logicbigz =
logicsmallz
biggestx <=
= smallestx
biggesty <=
= smallesty
biggestz <=
= smallestz
xmax;
>= xmin;
ymax;
>= ymin;
zmax;
>= zmin;
M = [logicbigx;logicsmallx;logicbigy;logicsmally ;logicbigz ;logicsmallz];
Mresult = M(1,:) & M(2,:) & M(3,:) & M(4,:) & M(5,:) & M(6,:);
find(Mresult == 1)
xresult = x(:,find(Mresult == 1));
yresult = y(:,find(Mresult == 1));
220
zresult = z(:,find(Mresult == 1));
nresult = n(:,find(Mresult == 1));
B.7.4 localPatchBunch
function [xresult yresult zresult nresult] = localPatchBunch(x,y,z,n, X)
%FUNCTION TO CONSTRUCT A PATCH OBJECT DEFINED BY A SET OF POINTS.
nVertices = length(X);
setFaces = [];
%Look for each vertex to which faces it belongs and store this information
%in a cell array.
for i = 1:nVertices
xVertex = X(i,1);
yVertex = X(i,2);
zVertex = X(i,3);
ind1 = find(x == xVertex);
ind2 = find(y == yVertex);
ind3 = find(z == zVertex);
%if the 3 index-matrices are the same, just use one of them to specify
%to which faces the vertex belongs
if length(ind1) == length(ind2) && length(ind1) == length(ind3)
faces = floor((ind1-1)/3)+1;
%if they are different in length, the shortest one will determine the
%indices of the faces they are member of.
else
l1 = length(ind1);
l2 = length(ind2);
l3 = length(ind3);
l = [l1 l2 l3];
lmin = find(l == min(l));
switch lmin(1)
case 1
faces = floor((ind1-1)/3)+1;
case 2
faces = floor((ind2-1)/3)+1;
case 3
faces = floor((ind3-1)/3)+1;
end
end
setFaces = [setFaces; faces];
end
setFaces = unique(setFaces, 'rows');
xresult = x(:,setFaces);
yresult = y(:,setFaces);
zresult = z(:,setFaces);
nresult = n(:,setFaces);
221
Appendix C: The Stl format
Based on [15].
C.1 Format Specifications
An StL file consists of a list of facet data. Each facet is uniquely identified by a unit
normal and by three vertices. The normal and each vertex are specified by three
coordinates each, so there is a total of 12 numbers stored for each facet.
Facet orientation. The facets define the surface of a 3-dimensional object. As such,
each facet is part of the boundary between the interior and the exterior of the object.
The orientation of the facets (which way is “out” and which way is “in”) is specified
redundantly in two ways which must be consistent. First, the direction of the normal is
outward. Second, the vertices are listed in counterclockwise order when looking at the
object from the outside (right-hand rule). These rules are illustrated in Figure C.1.
1
3
2
Figure C.1: A facet with its outward pointing normal.
222
Vertex-to-vertex rule. Each triangle must share two vertices with each of its adjacent
triangles. In other words, a vertex of one triangle cannot lie on the side of another. This
is illustrated in Figure C.2.
Figure C.2: Left a violation of the rule. Right the same corrected structure.
C.2 Format Specifications
The StL standard includes two data formats, ASCII and binary. Only binary will be
described, because that is the only format we have used.
The binary format uses the IEEE integer and floating point numerical representation.
The syntax for a binary StL file is as follows:
Bytes
Data type
Description
80
ASCII
Header. No data significance
4
Unsigned long integer
Number of facets in file.
12
Float
i
j
for normal
k
12
Float
223
12
Float
x
y
for vertex 2
z
12
Float
x
y
for vertex 3
z
2
Unsigned integer
Attribute byte count
…..
The above in blue corresponds to one facet and therefore has to be repeated more
times for each facet of the model.
224
Appendix D: Curvature
D.1 Matlab implementation
The used algorithm can be found in [12]. Executing this algorithm calculates the mean
curvature as well as the gaussian curvature. In our work we will only use the mean
curvature.
In D.1.1 the general framework of invoked functions is written. In the subsequent
paragraphs the functions used in D.1.1 are outlined. A thorough explanation is not
given because the curvature calculation is not a real objective of the work.
D.1.1 The general framework: calculateCurvature.m
function cfinal = calculateCurvature(x,y,z,n,neighbors)
%CALCULATECURVATURE WILL CARRY OUT THE MEAN CURVATURE CALCULATION FOR A
%TRIANGULAR 3D MODEL
%
%OUTPUT:
%
cfinal is a 3-by-N matrix that contains for each vertex (point) its
%
mean curvature value.
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object of the 3D model.
%
%
n is a 3-by-N matrix representing the normalized normals to the facets
%
of the original input patch object of the 3D model.
%
%
with N the number of facets of the 3D model.
%
%
neighbors represents the neighborhood with which the calculation is
%
executed.
%
--------%
%
author : Bart Coppieters
%
%list representation of the 3D model
X = unique([x(:) y(:) z(:)],'rows');
%function: see vertexInFaces
A = vertexInFaces(x, y, z);
%function: see pointNormal
N = pointNormal(x, y, z, A, n);
%function: see findPointNeigh
225
V = findPointNeigh(x, y, z, A, neighbors);
%function: see curvature
C = curvature(N, V, X);
%function: see patchCurv
c = patchCurv(x,y,z,C);
%function: see removeOutliers
cfinal = removeOutliers(c);
D.1.2 vertexInFaces.m
function A = vertexInFaces(x, y, z)
%VERTEXINFACES CALCULATES FOR EACH VERTEX THE FACETS IT BELONGS TO.
%
%OUTPUT:
%
A is a cell array that contains in each row the facets of the vertex
%
the row corresponds to.
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object of the 3D model.
%
%
with N the number of facets of the 3D model.
%
%
--------%
%
author : Bart Coppieters
%
%list representation of the 3D model
X = unique([x(:) y(:) z(:)],'rows');
%the number of vertices
nVertices = length(X);
A = cell(nVertices,1);
h = waitbar(0, 'Please wait...');
set(h,'Name','vertex in faces (1/6)');
%Look for each vertex to which faces it belongs and store this information
%in a cell array.
for i = 1:nVertices
xVertex = X(i,1);
yVertex = X(i,2);
zVertex = X(i,3);
ind1 = find(x == xVertex);
ind2 = find(y == yVertex);
ind3 = find(z == zVertex);
%if the 3 index-matrices are the same, just use one of them to specify
%to which faces the vertex belongs
if length(ind1) == length(ind2) && length(ind1) == length(ind3)
faces = floor((ind1-1)/3)+1;
226
%if they are different in length, the shortest one will determine the
%indices of the faces the vertex is a member of.
else
l1 = length(ind1);
l2 = length(ind2);
l3 = length(ind3);
l = [l1 l2 l3];
lmin = find(l == min(l));
switch lmin(1)
case 1
faces = floor((ind1-1)/3)+1;
case 2
faces = floor((ind2-1)/3)+1;
case 3
faces = floor((ind3-1)/3)+1;
end
end
% populate the cell array A.
A{i} = faces';
waitbar(i/nVertices, h);
end
close(h);
D.1.3 pointNormal.m
function N = pointNormal(x, y, z, A, n)
% POINTNORMAL computes the normal in every point of the triangular model
% as a weighted sum of the normals of its neighbouring faces.
%
%OUTPUT:
%
N is a cell array that contains in each row the 3 coordinates of
%
a point and and the 3 coordinates of its normal.
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object of the 3D model.
%
%
n is a 3-by-M matrix representing the normalized normals to the facets
%
of the original input patch object of the 3D model.
%
%
with M the number of facets of the 3D model.
%
%
%
%
%
%
A is the output cell array of function vertexInFaces.
--------author : Bart Coppieters
X = unique([x(:) y(:) z(:)],'rows');
227
nVertices = length(X);
N = cell(nVertices, 2);
h = waitbar(0, 'Please wait...');
set(h,'Name','pointNormal (2/5)');
for i = 1:nVertices
faces = A{i};
p = X(i,:);
%
normals = zeros(3,length(faces));
normals = n(:,faces);
W = zeros(1,length(faces));
%make a vector of which each element is a weight that will be used to
%determine the normal in the point.
for k = 1:length(faces)
g = sum([x(:,faces(k)) y(:,faces(k)) z(:,faces(k))])/3;
W(k) = 1/norm(g - p);
end
W = repmat(W,3,1);
N{i,1} = p;
N{i,2} = sum((W .* normals),2)'/norm(sum((W .* normals),2));
waitbar(i/nVertices, h);
end
close(h)
D.1.4 findPointNeigh.m
function V = findPointNeigh(x, y, z, A, buren)
% FINDPOINTNEIGH serves to find for each point in the triangular mesh its
% neighbouring points.
%
%OUTPUT:
% V is a cell array of cell arrays with in each cell array (the row) the
% coordinates of the point of which you want to find the neighbours and the
% coordinates of the neighbours of the point.
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object of the 3D model.
%
%
with N the number of facets of the 3D model.
%
%
A is the output cell array of function vertexInFaces.
%
%
%
buren is a number that will define the neighborhood in which to find
%
for neighbors. For example, a neighborhood of 1 defines all the
%
vertices connected directly to the point, a neighborhood of 2 defines
228
%
%
%
%
%
the vertices connected to the point by 1 or 2 edges....
--------author : Bart Coppieters
X = unique([x(:) y(:) z(:)],'rows');
nVertices = length(X);
V = cell(nVertices,1);
h = waitbar(0, 'Please wait...');
set(h,'Name','findPointNeigh (3/5)');
% For each point p in the mesh:
%
-reveil its neighbouring faces.
%
-look for the points the neighbouring triangles consist of.
%
-make a unique list of these points with p the first element.
%
-convert each list (matrix) point for point in a cell array.
for i = 1:nVertices
faces = A{i};
p = X(i,:);
Vi = cell(1, length(faces) + 1);
vList = zeros(length(faces)*3,3);
for k = 1:length(faces)
vList(3*k-2 : 3*k, :) = [x(:,faces(k)) y(:,faces(k)) z(:,faces(k))];
end
vList = unique(vList, 'rows');
ind = find(vList(:,1) == p(1,1) & vList(:,2) == p(1,2) & vList(:,3) ==
p(1,3));
vList = [vList(ind:end,:);vList(1:ind-1,:)];
for l = 1:length(vList)
Vi{1, l} = vList(l,:);
end
V{i} = Vi;
waitbar(i/nVertices, h);
end
close(h)
if buren > 1
%function: see extendList
V = extendList(V, X, buren);
end
229
D.1.4.1 extendList
function VV = extendList(V, X, buren)
%EXTENDLIST EXTENDS FOR EACH POINT ITS ORIGINAL 1_NEIGHBORHOOD LIST TO A
%BUREN_NEIGHORHOOD LIST
%
%OUTPUT:
%
VV is a cell array of cell arrays with in each row the
%
buren_neighborhood of the point associated to the row.
%INPUT:
%
V is a cell array of cell arrays with in each row the 1_neighborhood of
%
the point associated to the row.
%
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the 3D model.
%
%
buren is a number that will define the neighborhood in which to find
%
for neighbors. For example, a neighborhood of 1 defines all the
%
vertices connected directly to the point, a neighborhood of 2 defines
%
the vertices connected to the point by 1 or 2 edges....
%
--------%
%
author : Bart Coppieters
%
nVertices = length(V);
h = waitbar(0, 'Please wait...');
set(h,'Name','extendList (3/6)');
for i = 1:nVertices
vActual = V{i};
count = buren;
while count - 1 > 0
n1buren = length(vActual) - 1;
nextburen = [vActual{1}];
for j = 1:n1buren
ind = find(X(:,1) == vActual{j+1}(1) & ...
X(:,2) == vActual{j+1}(2) & X(:,3) == vActual{j+1}(3));
nextburen = [nextburen; V{ind}'];
end
nextburenM = cell2mat(nextburen);
nextburenM = unique(nextburenM,'rows');
ind = find(nextburenM(:,1) == vActual{1}(1) & nextburenM(:,2) ...
== vActual{1}(2) & nextburenM(:,3) == vActual{1}(3));
nextburenM = [nextburenM(ind:end,:);nextburenM(1:ind-1,:)];
vActual = mat2cell(nextburenM, ...
[repmat(1,length(nextburenM),1)],[3])';
VV{i,1} = vActual;
count = count -1;
end
waitbar(i/nVertices);
end
230
close(h)
D.1.5 curvature.m
function C = curvature(N, V, X)
%VERTEXINFACES serves to find for each point in the triangular mesh its
% neighbouring points.
%
%OUTPUT:
% C is a m-by-5 matrix that contains in the first 3 columns the coordinates
% of the points, in the 4th column the gaussian curvature and in the 5th
% column the mean curvature.
%INPUT:
%
N is a cell array that contains in each row the 3 coordinates of
%
a point and and the 3 coordinates of its normal.
%
%
V is a cell array of cell arrays with in each row the selected
%
neighborhood of the point associated to the row.
%
%
X is a m-by-3 matrix of the coordinates of the m datapoints that
%
constitute the 3D model.
%
--------%
%
author : Bart Coppieters
%
nVertices = length(N);
C = zeros(nVertices, 5);
h = waitbar(0, 'Please wait...');
set(h,'Name','curvature (4/5)');
% for each point p:
%
-look for its neighbouring points pi -> pList
%
-compute for each point pi the unit length projection of pi-p
%
onto the tangent plane: pi -> ti
%
-compute the normal curvature in direction ti.
%
-look at the maximum normal curvature. The corresponding
%
direction is the first estimate of a principal direction.
for i = 1:nVertices
pList = V{i};
p = pList{1}; %the central point for which we calculate the curvature
n = N{i, 2}; %its normal
max = -inf;
normal_curvatures = zeros(1, length(pList) - 1);
tDirections = cell(1, length(pList) - 1);
for k = 1:length(pList)-1
pi = pList{k+1};
ti = ((pi-p) - dot(pi - p, n)*n)/norm(((pi-p) - dot(pi - p, n)*n));
231
tDirections{1, k} = ti;
ind = find(X(:,1) == pi(1,1) & X(:,2) == pi(1,2) & X(:,3) ==
pi(1,3));
ni = N{ind,2}; %normal in point pi
normal_curvature_ti = - dot(pi - p, ni - n)/dot(pi - p, pi - p);
normal_curvatures(k) = normal_curvature_ti;
% looking for the maximum
if normal_curvature_ti > max
max = normal_curvature_ti;
e1 = ti;
index = k;
end
end
normal_curvatures(1, index) = 0;
normal_curvatures = nonzeros(normal_curvatures)';
a = max;
e2 = cross(e1, n)/norm(cross(e1, n));
thetas = zeros(1, length(tDirections)-1);
plek = 1;%%
for l = 1:length(tDirections)
t = tDirections{1, l};
theta = acos(dot(e1, t));
if norm(theta) > power(10,-6)
thetas(plek) = theta;
plek = plek+1;
end
end
a11 = sum(cos(thetas).^2 .* sin(thetas).^2);
a12 = sum(cos(thetas) .* sin(thetas).^3);
a21 = a12;
a22 = sum(sin(thetas).^4);
a13 = sum((normal_curvatures a*cos(thetas).^2).*cos(thetas).*sin(thetas));
a23 = sum((normal_curvatures - a*cos(thetas).^2).*sin(thetas).^2);
b = (a13*a22 - a23*a12)/(a11*a22 - a12^2);
c = (a11*a23 - a12*a13)/(a11*a22 - a12^2);
Kg = (a*c - b*b)/4;
H = (a + c) / 2;
C(i, 1:3) = p;
C(i, 4) = Kg;
232
C(i, 5) =H;
waitbar(i/nVertices, h);
end
close(h)
D.1.6 patchCurv.m
function c = patchCurv(x,y,z,C)
% PATCHCURV makes the information of C (output of function curvature)
% consistent with the patch representation of the 3D model.
%
%OUTPUT:
%
c is a 3-by-N matrix of the mean curvatures for each point of the model
%
as structured in the patch representation.
%INPUT:
%
x, y and z are 3-by-N matrices that together form the original input
%
patch object of the 3D model.
%
%
C is a m-by-5 matrix that contains in the first 3 columns the coordinates
%
of the points of the 3D model, in the 4th column the gaussian
%
curvature and in the 5th column the mean curvature.
%
--------%
%
author : Bart Coppieters
%
X = [x(:) y(:) z(:)];
len = length(X);
c = zeros(len, 1);
h = waitbar(0, 'Please wait...');
set(h,'Name','patchCurv(5/5)');
for i=1:len
ind = find(C(:,1) == X(i,1) & C(:,2) == X(i,2) & C(:,3) == X(i,3));
c(i) = C(ind,5); %kolom 5 = mean curvature
waitbar(i/len, h);
end
c = reshape(c,3, length(c)/3);
close(h)
D.1.7 removeOutliers.m
function c_update = removeOutliers(c)
% REMOVEOUTLIERS removes the ouliers of c, the input matrix of mean
% curvature data.
%
%OUTPUT:
233
%
c_update is a 3-by-N matrix of the mean curvatures after removing the
%
outliers.
%INPUT:
%
c is a 3-by-N matrix of the mean curvatures for each point of the model
%
as structured in the patch representation.
%
%
%
%
%
with N the number of facets of the 3D model.
--------author : Bart Coppieters
c_update = c(:);
c_update(find(isnan(c_update) == 1)) = 3;
c_update(find(c_update > 3)) = 3;
c_update(find(c_update < -3)) = 3;
mu = mean(c_update,1);
sigma = std(c_update,1);
ind1 = find(c_update > mu
ind2 = find(c_update < mu
+ 3*sigma);
- 3*sigma);
c_update(ind1) = mu + 3*sigma;
c_update(ind2) = mu - 3*sigma;
c_update = reshape(c_update,3, length(c_update)/3);
234
Bibliography
[1] S.Van Sint Jan, Color Atlas of Skeltal landmark Definitions, Edition 1, Elsevier
Health Sciences, Amsterdam, (2007), 208 p.
[2] F.H. Netter, S. Colacino, Atlas of Human Anatomy, Edition 2, ICON Learning
Systems (1998), 525 p.
[3] J.W. Rohen, C. Yokochi, E. Lutjen-Drecoll, Color Atlas of Anatomy: A Photographic
Study of the Human Body, Edition 6, Lippincott Williams & Wilkins (2006), 528 p.
[4] H. Gray, Anatomy of the Human Body, Lea & Febiger, Philadelfia(1918)
[5] B.L. Kaptein, F.C.T. van der Helm, Estimating muscle attachment contours by
transforming geometrical bone models, Journal of Biomechanics 37(2003), 263–273.
[6] C.M.L. Werner, P. Favrea, C. Gerbera, The role of the subscapularis in preventing
anterior glenohumeral subluxation in the abducted, externally rotated position of the
arm, Clinical Biomechanics, Volume 22, Issue 5 (2006), 495-501
[7] Ryan T. Bicknell et al, Early experience with computer-assisted shoulder
hemiarthroplasty for fractures of the proximal humerus: Development of a novel
technique and an in vitro comparison with traditional methods, Journal of Shoulder and
Elbow Surgery, Volume 16, Issue 3, Supplement 1 (2007), Pages S117-S125
[8] S Gupta, FCT van der Helm, Load transfer across the scapula during humeral
abduction, Journal of Biomechanics 37, Issue 7 (2004), 1001–1009
[9] L. A. Murphy, P. J.Prendergast, Acromion-fixation of glenoid components in total
shoulder arthroplasty, Journal of Biomechanics 38, Issue 8 (2004), 1702-1711
[10 ] C.G.M.Meskers et al, In vivo estimation of the glenohumeral joint rotation center
from scapular bony landmarks by linear regression, Journal of Biomechanics, 31
(1998), 93 – 96
[11] G.Wu et al, ISB recommendation on definitions of joint coordinate systems of
various joints for the reporting of human joint motion – Part II: shoulder, elbow ,
wrist and hand, Journal of Biomechanics, 38 (2005), 981 – 992
[12] Dong et al, Curvatures estimation on triangular mesh, Journal of Zhejiang
University Science, 6A (Suppl I) (2005), 128 – 136
235
[13] P. Boileau, G.Walch, The three-dimensional geometry of the proximal humerus,
The Journal of Bone and Joint Surgery, vol 79-B , 5 (1997), 857 – 865
[14] Biomed: The free community for biomedical research and technology.
http://www.biomedtown.org/biomed_town/B3C_Building/products/VPalp/
[15] StereoLithography Interface Specification, 3D Systems, Inc., October 1989
In general:
I.A. Kapandji, Physiology of the Joints (Upper Extremities), edition 5, Churchill
Livingstone (1982) , 208 p
Matlab® – The language of Technical Computing.
http://www.mathworks.com/products/matlab/
236
237