Content Description

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

Digitizing Landmarks

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:


IMPORTANT DETAIL: MISSING LANDMARKS!! Any specimen with missing data (e.g., a broken specimen) may still be digitized. In this case, simply leave the missing landmarks BLANK. They will be treated as NA and can be estimated in subsequent data-processing steps.

IMPORTANT DETAIL: DELETING LANDMARKS!! To delete a landmark, click on the lm, and hit ‘D’.


Scaling

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:

Digitizing Curves

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:

  1. Specify curve names and start/end landmarks (see example_curve.txt) NOTE: do not use spaces or strings used to name landmarks when naming the curves
  2. Re-open the digitizer to record the curves
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 landmakrs 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"