Skip to content

Commit f30f7c4

Browse files
Stitch outlines comprising multiple fragments with a hole in the centre
The main work has been to generalis the notion of a rim set to a boundary set. The boundary set is the part of the outline that is not stitched. It may comprise only one connected part, which is by definition the rim, or it may comprise multiple closed paths, the longest of which is assumed to be rim. Once the rim is identified, reconstruction can start. There may be future work to do with ensuring the area of the projection is appropriate, but this will probably have a small influence on the quailty of the reconstruction.
1 parent b601560 commit f30f7c4

17 files changed

+483
-58
lines changed

doc/retistruct-user-guide.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
\documentclass{book}
22

3-
\newcommand{\svninfo}{Retistruct version: 0.7.0 , Date: 2020-08-26}
3+
\newcommand{\svninfo}{Retistruct version: 0.7.1 , Date: 2020-08-28}
44
\pagestyle{myheadings}
55
\markboth{\svninfo}{\svninfo}
66

@@ -386,7 +386,7 @@ \section{Editing the retinal mark-up}
386386
\caption{Adding a correspondence. One correspondence between the two
387387
upper petals has been added. The red dashed line indicate the ends
388388
of the correspondence, and the red highlighted edge indicates the
389-
edges the correspond.}
389+
edges of the correspondence.}
390390
\label{retistruct-user-guide:fig:correspondence}
391391
\end{figure}
392392

pkg/retistruct/DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ Description: Reconstructs retinae by morphing a flat surface with cuts (a
99
shape). It can estimate the position of a point on the intact adult retina
1010
to within 8 degrees of arc (3.6% of nasotemporal axis). The coordinates in
1111
reconstructed retinae can be transformed to visuotopic coordinates.
12-
Version: 0.7.0
12+
Version: 0.7.1
1313
URL: http://davidcsterratt.github.io/retistruct/
1414
BugReports: https://github.com/davidcsterratt/retistruct/issues
15-
Date: 2020-08-26
15+
Date: 2020-08-28
1616
Depends:
1717
R (>= 3.5.0)
1818
Imports:

pkg/retistruct/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
CHANGES IN VERSION 0.7.1 - Released 2020/08/28
2+
3+
* Stitching together of fragments that contain a hole in the centre
4+
is now possible
5+
16
CHANGES IN VERSION 0.7.0 - Released 2020/08/26
27

38
NEW FEATURES

pkg/retistruct/R/AnnotatedOutline.R

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,30 @@ AnnotatedOutline <- R6Class("AnnotatedOutline",
272272
return(self$i0)
273273
},
274274
##' @description Get point IDs of points on rim
275-
##' @return Point IDs of points on rim
275+
##' @return Point IDs of points on rim. If the outline has been
276+
##' stitched (see \code{\link{StitchedOutline}}), the point IDs
277+
##' will be ordered in the direction of the
278+
##' forward pointer.
276279
getRimSet = function() {
280+
## TR <- self$computeTearRelationships(self$tears)
281+
## CR <- self$computeCorrespondenceRelationships(self$corrs)
282+
## Rset <- intersect(TR$Rset, CR$Rset)
283+
return(self$getBoundarySets()[["Rim"]])
284+
},
285+
##' @description Get point IDs of points on boundaries
286+
##' @return List of Point IDs of points on the boundaries.
287+
##' If the outline has been stitched (see \code{\link{StitchedOutline}}),
288+
##' the point IDs in each
289+
##' element of the list will be ordered in the direction of the
290+
##' forward pointer, and the boundary that is longest will be
291+
##' named as \code{Rim}. If the outline has not been stitched,
292+
##' the list will have one element named \code{Rim}.
293+
getBoundarySets = function() {
277294
TR <- self$computeTearRelationships(self$tears)
278295
CR <- self$computeCorrespondenceRelationships(self$corrs)
279-
Rset <- intersect(TR$Rset, CR$Rset)
280-
return(Rset)
296+
## The intersection of these two is the union of the boundary
297+
## sets
298+
return(list(Rim=intersect(TR$Rset, CR$Rset)))
281299
},
282300
##' @description Ensure that the fixed point \code{i0} is in the rim, not a tear.
283301
##' Alters object in which \code{i0} may have been changed.
@@ -294,13 +312,15 @@ AnnotatedOutline <- R6Class("AnnotatedOutline",
294312
}
295313
}
296314
},
297-
##' @description Get flat rim length
298-
##' @return The rim length
299-
getFlatRimLength = function() {
300-
suppressMessages(r <- self$computeTearRelationships(self$V0, self$VB, self$VF))
301-
return(path.length(self$i0, path.next(self$i0, self$gf, r$hf), self$gf, r$hf, self$P) +
302-
path.length(self$i0, path.next(self$i0, self$gf, r$hf), self$gb, r$hb, self$P))
303-
},
315+
## FIXME: Remove getFlatRimLength? It is not used and I'm not convinced it's correct
316+
##
317+
## ##' @description Get flat rim length
318+
## ##' @return The rim length
319+
## getFlatRimLength = function() {
320+
## suppressMessages(r <- self$computeTearRelationships(self$V0, self$VB, self$VF))
321+
## return(path.length(self$i0, path.next(self$i0, self$gf, r$hf), self$gf, r$hf, self$P) +
322+
## path.length(self$i0, path.next(self$i0, self$gf, r$hf), self$gb, r$hb, self$P))
323+
## },
304324
##' @description Label a set of four unlabelled points supposed to refer to a
305325
##' correspondence.
306326
##' @param pids the vector of point indices

pkg/retistruct/R/ReconstructedOutline.R

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ ReconstructedOutline <- R6Class("ReconstructedOutline",
287287
}
288288

289289
## Transform the rim set
290-
Rset <- order.Rset(self$ol$getRimSet(), self$ol$gf, self$ol$h)
290+
Rset <- self$ol$getRimSet()
291291
Rsett <- unique(ht[Rset])
292292
i0t <- ht[self$ol$i0]
293293

@@ -669,8 +669,8 @@ ReconstructedOutline <- R6Class("ReconstructedOutline",
669669
}
670670
return(private$ims)
671671
},
672-
##' @description Get location of tear coordinates in spherical coordinates
673-
##' @return Location of tear coordinates in spherical coordinates
672+
##' @description Get locations of tears in spherical coordinates
673+
##' @return List containing locations of tears in spherical coordinates
674674
getTearCoords = function() {
675675
Tss <- list()
676676
for (TF in self$ol$TFset) {
@@ -680,8 +680,8 @@ ReconstructedOutline <- R6Class("ReconstructedOutline",
680680
}
681681
return(Tss)
682682
},
683-
##' @description Get location of correspondence coordinates in spherical coordinates
684-
##' @return Location of correspondence coordinates in spherical coordinates
683+
##' @description Get locations of correspondences in spherical coordinates
684+
##' @return List containing locations of correspondences in spherical coordinates
685685
getCorrespondenceCoords = function() {
686686
Css <- list()
687687
for (CF in self$ol$CFset) {
@@ -691,6 +691,22 @@ ReconstructedOutline <- R6Class("ReconstructedOutline",
691691
}
692692
return(Css)
693693
},
694+
##' @description Get location of non-rim boundaries in spherical coordinates
695+
##' @return List containing locations of non-rim boundaries in spherical coordinates
696+
getNonRimBoundaryCoords = function() {
697+
Bsets <- self$ol$getBoundarySets()
698+
if (length(Bsets) <= 1) {
699+
return(NULL)
700+
}
701+
Bss <- list()
702+
for (B in Bsets[names(Bsets) != "Rim"]) {
703+
## Convert indices to the spherical frame of reference
704+
j <- self$ht[B]
705+
Bss <- c(Bss, list(cbind(phi=self$phi[j], lambda=self$lambda[j])))
706+
}
707+
return(Bss)
708+
709+
},
694710
##' @description Get \link{ReconstructedFeatureSet}
695711
##' @param type Base type of \link{FeatureSet} as string.
696712
##' E.g. \code{PointSet} returns a \link{ReconstructedPointSet}
@@ -1145,16 +1161,24 @@ projection.ReconstructedOutline <- function(r,
11451161
graphics::polygon(boundary[,"x"], boundary[,"y"], border="black")
11461162
}
11471163

1148-
## Plot rim in visutopic space
1164+
## Plot rim in visuotopic space
11491165
rs <- cbind(phi=r$phi0, lambda=seq(0, 2*pi, len=360))
11501166
rs.rot <- rotate.axis(transform(rs, phi0=r$phi0), axisdir*pi/180)
11511167
## "Home" position for a cyclops looking ahead
11521168
## r$axisdir = cbind(phi=0, lambda=0)
1153-
11541169
lines(projection(rs.rot, lambdalim=lambdalim*pi/180, lines=TRUE,
11551170
proj.centre=pi/180*proj.centre),
11561171
col=getOption("TF.col"))
11571172

1173+
## Plot non-rim boundary in visuotopic space
1174+
bss <- r$getNonRimBoundaryCoords()
1175+
for (bs in bss) {
1176+
bs.rot <- rotate.axis(transform(bs, phi0=r$phi0), axisdir*pi/180)
1177+
lines(projection(bs.rot, lambdalim=lambdalim*pi/180, lines=TRUE,
1178+
proj.centre=pi/180*proj.centre),
1179+
col=getOption("TF.col"))
1180+
}
1181+
11581182
## Projection of pole
11591183
if (pole) {
11601184
oa.rot <- rotate.axis(transform(cbind(phi=-pi/2, lambda=0), phi0=r$phi0),

pkg/retistruct/R/StitchedOutline.R

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,48 @@ StitchedOutline <- R6Class("StitchedOutline",
103103
self$h <- self$h[self$h]
104104
}
105105
self$CFset <- r$CFset
106+
},
107+
##' @description Test if the outline has been stitched
108+
##' @return Boolean, indicating if the outline has been stitched or not
109+
isStitched = function() {
110+
return((!(is.null(self$TFset))) &
111+
((nrow(self$corrs) == 0) | !(is.null(self$CFset))))
112+
},
113+
##' @description Get point IDs of points on boundaries
114+
##' @return List of Point IDs of points on the boundaries.
115+
##' If the outline has been stitched,
116+
##' the point IDs in each
117+
##' element of the list will be ordered in the direction of the
118+
##' forward pointer, and the boundary that is longest will be
119+
##' named as \code{Rim}. If the outline has not been stitched,
120+
##' the list will have one element named \code{Rim}.
121+
getBoundarySets = function() {
122+
Bsets <- super$getBoundarySets()
123+
if (!self$isStitched()) {
124+
return(Bsets)
125+
}
126+
UBset <- Bsets[["Rim"]]
127+
## Now separate out the Bsets
128+
Bsets <- list()
129+
Blengths <- c()
130+
P <- self$getPointsScaled()
131+
while(length(UBset) > 0) {
132+
i <- UBset[1]
133+
j <- path.next(i, self$gf, self$hf)
134+
B12 <- path(i, j, self$gf, self$hf)
135+
B21 <- path(j, i, self$gf, self$hf)
136+
BL12 <- path.length(i, j,
137+
self$gf, self$hf, P)
138+
BL21 <- path.length(j, i,
139+
self$gf, self$hf, P)
140+
Bset <- c(B12[-1], B21[-1])
141+
Bsets <- c(Bsets, list(Bset))
142+
Blengths <- c(Blengths, BL12 + BL21)
143+
UBset <- setdiff(UBset, Bset)
144+
}
145+
Bsets <- name.list(Bsets)
146+
names(Bsets)[which.max(Blengths)] <- "Rim"
147+
return(Bsets)
106148
}
107149
)
108150
)

pkg/retistruct/R/spheristruct.R

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
## order.Rset(Rset, gf, hf)
2-
##
3-
## It is nice to create Rset as an ordered set
4-
order.Rset <- function(Rset, gf, hf) {
5-
## To to this, join the path from the first two members of the set.
6-
R12 <- path(Rset[1], Rset[2], gf, hf)
7-
R21 <- path(Rset[2], Rset[1], gf, hf)
8-
Rset <- c(R12[-1], R21[-1])
9-
return(Rset)
10-
}
11-
121
##' Stretch the mesh in the flat retina to a circular outline
132
##'
143
##' @title Stretch mesh

pkg/retistruct/demo/00Index

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ orange Reconstruct a peeled orange!
55
wedge Demonstration of wedge coordinates
66
smi32 Reconstruct a retina labelled with SMI-32
77
parabola Reconstruct a parabolically transformed retina
8+
hole Reconstruct a retina with a holes

pkg/retistruct/demo/hole.R

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
par(mfcol=c(1, 2))
2+
3+
P <- list(rbind(c(1,1.5),
4+
c(1.5,1),
5+
c(2,1),
6+
c(2.5,2),
7+
c(3,1),
8+
c(4,1),
9+
c(1,4)),
10+
rbind(c(-1.5,1),
11+
c(-1,1.5),
12+
c(-1,4),
13+
c(-2,3),
14+
c(-2,2),
15+
c(-3,2),
16+
c(-4,1)),
17+
rbind(c(-4,-1),
18+
c(-1.5,-1),
19+
c(-1,-1.5),
20+
c(-1,-4)),
21+
rbind(c(1,-1.5),
22+
c(1.5,-1),
23+
c(2,-1),
24+
c(2.5,-2),
25+
c(3,-1),
26+
c(4,-1),
27+
c(1,-4)))
28+
## Stitched outlines
29+
a <- StitchedOutline$new(P)
30+
31+
expect_false(a$isStitched())
32+
33+
## Set a fixed point
34+
## One that is in the rim should be fine
35+
a$setFixedPoint(6, "Nasal")
36+
expect_equal(a$i0, c(Nasal=6))
37+
38+
## One that is not in the rim should be moved
39+
a$addTear(c(11, 12, 13))
40+
a$addTear(c(3, 4, 5))
41+
a$addTear(c(21, 22, 23))
42+
43+
## Add correspondences
44+
a$addCorrespondence(c(2, 6, 20, 24))
45+
a$addCorrespondence(c(1, 7, 9, 10))
46+
a$addCorrespondence(c(8, 14, 15, 16))
47+
a$addCorrespondence(c(17, 18, 19, 25))
48+
49+
r <- ReconstructedOutline$new()
50+
r$loadOutline(a)
51+
52+
flatplot(a)
53+
flatplot(r)
54+
55+
r$reconstruct()
56+
57+
flatplot(r)
58+
projection(r)
59+
60+
par(mfcol=c(1, 1))

pkg/retistruct/man/AnnotatedOutline.Rd

Lines changed: 24 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)