knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
The eggs
package provides a set of functions for estimating distances and areas on the surface of an avian egg. It was developed in order to aid the quantification of pigmentation patterns, and so this is the focus of the examples in this vignette (although obviously does not preclude other uses!). It is also currently still being developed, tested and tweaked, which has a couple of implications: first, the code is not always fast or optimised - when I am confident everything works as it should then I will aim to implement the slower parts in C++; second, it is not yet available on CRAN - the latest version can therefore be obtained from:
install.packages("eggs", repos="http://r-forge.r-project.org")
Finally, because the code currently makes use of the interactive features provided by locator
in the base graphics
package, it works well on Windows versions of R but may not be so happy to run smoothly on other operating systems.
The first thing to do is load an image of an egg. There are various packages available for reading images, including png
, tiff
and jpeg
, and these can be used to obtain a usable image simply with something similar to
egg = readPNG("path/to/egg/image/myimage.png")
However, for convenience the eggs
package contains an example image, which can be loaded using
data(egg)
You can display the image you have just loaded using
egg.image(egg)
The next step is to use the egg.fit
function to estimate some shape and size parameters for the egg, using the approach of Troscianko (2014) "A simple tool for calculating egg shape, volume and surface area from digital images" Ibis 156(4), 874-878. Running
fit = egg.fit()
will allow you to interactively select an arbitrary number of points around the periphery of the egg. The first point you select must the tip of the pointed end; the second point selected must be the tip of the blunt end; the remaining points should be placed at regular(ish) intervals around the periphery. The order you place them in does not matter, but you should ensure there are enough (around 20 is usually fine) to allow shape to be estimated accurately. The resulting fit can be visually assessed using
egg.plot(fit, lwd=3, col="red")
The geodesic is the shortest distance between two points on the surface of an egg, measured along the egg’s surface rather than as a straight line through the egg's interior. Two points can be interactively selected on the surface of the egg using
points = egg.coords(fit, type="points", pch=16, col="red")
and then the geodesic (in pixels) between these two points estimated (using n=1000
increments) by running
egg.geodesic(fit, points, n=1000, plot=TRUE, lwd=3, col="red") #[1] 399.4987
The two selected points and the geodesic are plotted on the egg image
To calculate the (curved) area on the egg surface delimited by a polygonal region, it is first necessary to interactively select the vertices of the polygon
vertices = egg.coords(fit, type="polygon", pch=16, lwd=3, col="green")
The area within this polygon (in pixels^2) can then be estimated using triangulation (in this case with n=6
sets of subdivisions)
egg.polygon.area(fit, vertices, N=6) #[1] 219259.1
The selected polygon is plotted on the egg image
Information on each pixel (or a defined region of pixels) within the egg image can be extracted using the egg.pixel.data
function. For example, the following can be used to obtain pixel data for a 'square' region in the centre of the egg (this can be slow...)
px = egg.pixel.data(egg, fit, lower.theta=pi/4, upper.theta=3*pi/4, lower.phi=pi/4, upper.phi=3*pi/4)
Specifically, this returns information on each pixel's spherical coordinate coords
, colour col
and corrected size pixel.size
. To plot the equirectangular projection of these pixels, use
egg.projection(px, pch=".", pty="s")
To calculate the proportion of the surface area covered by maculated pixels (in this example, pixels have one of two colour values, stored in hexadecimal format as #CCCCCC for the background or #000000 for the pigmented regions) it is possible to use something like this
sum(px$pixel.size[px$col=="#000000"])/sum(px$pixel.size) #[1] 0.153314
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.