This tutorial summarizes the basic steps of digitizing 2D GM data
using the R-package StereoMorph, and then importing them to
geomorph
. As StereoMorph
uses Shiny to allow
the user to digitize, it is interactive, so you need to run the code to
gain hands-on experience on the details of how digitizing proceeds.
You will need to install and load StereoMorph
first.
install.packages("StereoMorph")
library(StereoMorph)
library(geomorph)
## Loading required package: RRPP
## Loading required package: rgl
## Loading required package: Matrix
First, let´s see how one can digitize fixed landmarks. These correspond to well-defined anatomical points on your structure of interest. You will need a folder with the pictures you will digitize (Images, in our example) In this script, digitized data are stored in another folder, called Shapes To digitize, e.g., five fixed landmarks, run:
digitizeImages(image.file='Data/Fish-Images', shapes.file='Data/Fish-Shapes-ex',
landmarks.ref=paste("LM", c(1:5), sep=""))
To digitize for the first time:
Go to Landmarks tab to see list of landmarks
The first lm is in bold
In the image window, double-click on the desired anatomical location to digitize
The point is now selected, and can be edited, moved etc. (is highlighted in green)
Select the next lm name and repeat
Navigate between landmarks with “n” (next) and “p” (previous)
Select lm and press “d” to delete
Save before moving to the next picture (or select the automatic save option)
NOTE: one has the ability to copy all landmarks to each image, and then move them to the desired locations. This can be useful so that landmarks remain in the correct order.
NA
and can be estimated in
subsequent data-processing steps.To scale landmark coordinates during superimposition and obtain accurate estimates of the relative size of the studied objects, you need to define the scaling of the images used, i.e. to indicate the correspondence of picture pixels with a “true” size measurement. For this:
The easiest way to obtain sliding semilandmarks to describe the shape of curves, is by first digitizing a curve in StereoMorph and then sampling the desired number of points from it. Curves are digitized in StereoMorph using a Bezier approximation. For this you need to:
digitizeImages(image.file='Data/Fish-Images', shapes.file='Data/Fish-Shapes-ex',
landmarks.ref=paste("LM", c(1:5), sep=""),
curves.ref = "Data/example.curves.txt")
You can then:
Once the curve is digitized, you can subsample a desired
number of semilandmarks from it. This is accomplished easiest
with the function, readland.shapes. This is a geomorph
function that reads in data from a class shapes
object. (In
geomorph, there are several readland.___ functions for different
landmark file types.) Before using readland.shapes
, a
shapes object must be created (a Stereomorph function).
shapes <- readShapes("Data/Fish-Shapes-ex")
shapesGM <- readland.shapes(shapes, nCurvePts = 10) # can change 10 to a different number
# Perform GPA
Y.gpa <- gpagen(shapesGM, print.progress = FALSE)
plot(Y.gpa)
When one has completed a serious digitizing effort, the
readland.shapes
function offers extreme flexibility for
choosing the sets of landmarks to use as a definition of “shape”.
It must be stated that for those of us who have spent some years
in GMM, this is profoundly amazing! Not too long ago, one must
have had an a priori definition of a landmark configuration and
digitize every specimen according to a preformed plan. Now, one can
experiment and find an optimal landmark configuration,
post-digitizing.
Too demonstrate this, let’s use a digitizing set with 11 landmarks and 9 curves. First we need to define how many landmarks should be in each curve.
shapes <- readShapes("Data/example.digitized")
# curves include eye, head, tail 1, tail end, tail 2, anal fin,
# pectoral fin, opercle, pre-opercle
curves.list <- c(20, 24, 24, 16, 12, 8, 8, 24, 16)
Then use readland.shapes
to read the data into a useable
format for geomorph.
shapesGM <- readland.shapes(shapes, nCurvePts = curves.list)
Every curve needs to have at least three landmarks (or it is not a curve). Other than that, one can vary the number for every curve. The set chosen is hypothetical. Let’s see what it looks like following generalized Procrustes Analysis (GPA).
Y.gpa <- gpagen(shapesGM, print.progress = FALSE)
plot(Y.gpa)
The density of semilandmarks might be a little too great. We can reduce it by 50%, for example, in one line of code:
shapesGM <- readland.shapes(shapes, nCurvePts = 0.5 * curves.list)
Y.gpa <- gpagen(shapesGM, print.progress = FALSE)
plot(Y.gpa)
Later it might impress you that no arguments for gpagen are needed
when reading data in with readland.shapes
. Class
geomorphShapes
objects also have various attributes that
can be exported for other uses.
class(shapesGM)
## [1] "geomorphShapes"
attributes(shapesGM)
## $names
## [1] "landmarks" "fixed" "sliders" "curves" "n" "p"
## [7] "k" "scaled"
##
## $class
## [1] "geomorphShapes"
shapesGM$fixed # which landmarks are fixed
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
shapesGM$curves # a curves matrix for gpagen - can be modified
## [,1] [,2] [,3]
## curveLM.13 12 13 14
## curveLM.14 13 14 15
## curveLM.15 14 15 16
## curveLM.16 15 16 17
## curveLM.17 16 17 18
## curveLM.18 17 18 19
## curveLM.19 18 19 20
## curveLM.20 19 20 12
## curveLM.21 1 21 22
## curveLM.22 21 22 23
## curveLM.23 22 23 24
## curveLM.24 23 24 25
## curveLM.25 24 25 26
## curveLM.26 25 26 27
## curveLM.27 26 27 28
## curveLM.28 27 28 29
## curveLM.29 28 29 30
## curveLM.30 29 30 2
## curveLM.31 2 31 32
## curveLM.32 31 32 33
## curveLM.33 32 33 34
## curveLM.34 33 34 35
## curveLM.35 34 35 36
## curveLM.36 35 36 37
## curveLM.37 36 37 38
## curveLM.38 37 38 39
## curveLM.39 38 39 40
## curveLM.40 39 40 3
## curveLM.41 3 41 42
## curveLM.42 41 42 43
## curveLM.43 42 43 44
## curveLM.44 43 44 45
## curveLM.45 44 45 46
## curveLM.46 45 46 4
## curveLM.47 4 47 48
## curveLM.48 47 48 49
## curveLM.49 48 49 50
## curveLM.50 49 50 5
## curveLM.51 5 51 52
## curveLM.52 51 52 6
## curveLM.53 7 53 54
## curveLM.54 53 54 8
## curveLM.55 9 55 56
## curveLM.56 55 56 57
## curveLM.57 56 57 58
## curveLM.58 57 58 59
## curveLM.59 58 59 60
## curveLM.60 59 60 61
## curveLM.61 60 61 62
## curveLM.62 61 62 63
## curveLM.63 62 63 64
## curveLM.64 63 64 10
## curveLM.65 11 65 66
## curveLM.66 65 66 67
## curveLM.67 66 67 68
## curveLM.68 67 68 69
## curveLM.69 68 69 70
## curveLM.70 69 70 10
shapesGM$landmarks[[1]] # specimen 1
## [,1] [,2]
## LM1 59.10605 -41.32745
## LM2 74.27244 -37.38964
## LM3 87.95729 -38.09143
## LM4 88.15223 -41.52239
## LM5 81.21233 -42.26316
## LM6 77.97632 -44.09561
## LM7 66.82570 -42.73102
## LM8 67.29356 -44.29055
## LM9 66.16291 -40.78161
## LM10 63.74564 -44.56347
## LM11 64.01856 -40.70364
## LM12 62.80992 -39.37804
## curveLM.13 63.35576 -40.20925
## curveLM.14 63.23879 -41.18580
## curveLM.15 62.56849 -41.91977
## curveLM.16 61.58884 -42.10721
## curveLM.17 60.79722 -41.57606
## curveLM.18 60.50962 -40.63789
## curveLM.19 60.90162 -39.76580
## curveLM.20 61.76877 -39.41703
## curveLM.21 60.09664 -40.23578
## curveLM.22 61.23111 -39.43632
## curveLM.23 62.59470 -38.96945
## curveLM.24 64.00739 -38.67625
## curveLM.25 65.44277 -38.38270
## curveLM.26 66.87240 -38.13042
## curveLM.27 68.38092 -38.01345
## curveLM.28 69.85046 -37.93548
## curveLM.29 71.32668 -37.74054
## curveLM.30 72.78007 -37.54560
## curveLM.31 75.48816 -37.55269
## curveLM.32 76.68105 -37.77086
## curveLM.33 77.89008 -38.00519
## curveLM.34 79.15621 -38.10168
## curveLM.35 80.41810 -38.20840
## curveLM.36 81.69189 -38.28637
## curveLM.37 82.98184 -38.24738
## curveLM.38 84.20719 -38.44232
## curveLM.39 85.39355 -38.20840
## curveLM.40 86.65119 -38.09143
## curveLM.41 88.78695 -38.10234
## curveLM.42 89.43884 -38.53892
## curveLM.43 89.63378 -39.32465
## curveLM.44 89.78973 -40.12653
## curveLM.45 89.59479 -40.91226
## curveLM.46 88.93127 -41.36644
## curveLM.47 86.70989 -41.56138
## curveLM.48 85.26756 -41.60037
## curveLM.49 83.89652 -41.75632
## curveLM.50 82.52547 -41.91227
## curveLM.51 80.08798 -42.76370
## curveLM.52 79.00116 -43.35483
## curveLM.53 67.11477 -43.17604
## curveLM.54 67.33255 -43.69627
## curveLM.55 66.16291 -41.28582
## curveLM.56 66.16291 -41.79002
## curveLM.57 66.08580 -42.26229
## curveLM.58 66.00695 -42.73384
## curveLM.59 65.85100 -43.15060
## curveLM.60 65.63888 -43.56695
## curveLM.61 65.39263 -43.96915
## curveLM.62 65.06841 -44.29338
## curveLM.63 64.68945 -44.48549
## curveLM.64 64.23370 -44.60245
## curveLM.65 64.01856 -41.28233
## curveLM.66 64.01856 -41.86102
## curveLM.67 63.97957 -42.42357
## curveLM.68 63.94058 -42.98611
## curveLM.69 63.90159 -43.52582
## curveLM.70 63.86260 -44.08836
names(shapesGM$landmarks) # all specimen names
## [1] "P1000602" "P1000603" "P1000604" "P1000605" "P1000606" "P1000615"
## [7] "P1000616" "P1000617" "P1000618" "P1000619" "P1000647" "P1000648"
## [13] "P1000649" "P1000650" "P1000651" "P1000657" "P1000658" "P1000659"
## [19] "P1000660" "P1000661" "P1000670" "P1000671" "P1000672" "P1000673"
## [25] "P1000674" "P1000684" "P1000685" "P1000686" "P1000687" "P1000688"
## [31] "P1000696" "P1000697" "P1000698" "P1000699" "P1000700" "P1000708"
## [37] "P1000709" "P1000710" "P1000711" "P1000712" "P1000719" "P1000720"
## [43] "P1000721" "P1000722" "P1000723" "P1000731" "P1000732" "P1000733"
## [49] "P1000734" "P1000735" "P1000743" "P1000744" "P1000745" "P1000746"
## [55] "P1000747" "P1000755" "P1000756" "P1000757" "P1000758" "P1000759"