├── .DS_Store ├── .Rhistory ├── .gitignore ├── CMakeLists.txt ├── CompilationRecipes.md ├── GraphAnalyzer.R ├── License.txt ├── MitoGraph.cxx ├── MitoThinning.cxx ├── MitoThinning.h ├── README.md ├── ThirdPartLicenses.txt ├── data └── MitoGraphTest001.tif ├── doc ├── Readme.md └── mitograph.png ├── includes.h ├── includes └── dirent.h ├── ssThinning.cxx ├── ssThinning.h └── tools ├── seg2para ├── CMakeLists.txt └── seg2para.cpp └── skell2img ├── CMakeLists.txt ├── includes.h └── skell2img.cxx /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/.DS_Store -------------------------------------------------------------------------------- /.Rhistory: -------------------------------------------------------------------------------- 1 | fit2 <- lm(AvgDegree ~ MitoToCellSurRatio + Media, data=MitoTable) 2 | anova(fit1, fit2) 3 | cv.lm(df=mydata, fit1, m=3) # 3 fold cross-validation 4 | ??cv.lm 5 | library(DAAG) 6 | cv.lm(df=mydata, fit1, m=3) # 3 fold cross-validation 7 | cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation 8 | cv <- cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation 9 | cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation 10 | cv <- cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation 11 | cv 12 | cv$cvpred 13 | cv <- cv.lm(df=MitoTable, fit1, m=3) # 3 fold cross-validation 14 | ?cv.lm 15 | cv <- cv.lm(df=MitoTable, fit1, m=5) # 3 fold cross-validation 16 | fit <- lm(AvgDegree ~ MitoToCellSurRatio + Type + Media, data=MitoTable) 17 | library(bootstrap) 18 | install.packages("bootstrap") 19 | library(bootstrap) 20 | theta.fit <- function(x,y){lsfit(x,y)} 21 | theta.predict <- function(fit,x){cbind(1,x)%*%fit$coef} 22 | X <- as.matrix(mydata[c("x1","x2","x3")]) 23 | X <- as.matrix(MitoTable[c("MitoToCellSurRatio","Type","Media")]) 24 | y <- as.matrix(MitoTable[c("AvgDegree")]) 25 | results <- crossval(X,y,theta.fit,theta.predict,ngroup=10) 26 | library(MASS) 27 | fit <- lm(AvgDegree ~ MitoToCellSurRatio + Type + Media, data=MitoTable) 28 | step <- stepAIC(fit, direction="both") 29 | step$anova # display results 30 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type MitoToCellSurRatio*Media + MitoLength, data=MitoTable) 31 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type MitoToCellSurRatio*Media + MitoLength, data=MitoTable) 32 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type MitoToCellSurRatio*Media, data=MitoTable) 33 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media + MitoLength, data=MitoTable) 34 | step <- stepAIC(fit, direction="both") 35 | step$anova # display results 36 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable) 37 | step <- stepAIC(fit, direction="both") 38 | step$anova # display results 39 | library(leaps) 40 | install.packages("leaps") 41 | library(leaps) 42 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=10) 43 | summary(leaps) 44 | plot(leaps,scale="r2") 45 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable) 46 | step <- stepAIC(fit, direction="both") 47 | step$anova # display results 48 | # All Subsets Regression 49 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=10) 50 | # view results 51 | summary(leaps) 52 | leaps$first 53 | leaps$xnames 54 | leaps$intercept 55 | leaps$np 56 | leaps$d 57 | leaps$rbar 58 | leaps$thetab 59 | leaps$ress 60 | leaps$ir 61 | leaps$lindep 62 | leaps$call 63 | ?leaps 64 | leaps[2] 65 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=1) 66 | leaps 67 | summary(leaps) 68 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=1) 69 | # view results 70 | summary(leaps) 71 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=10) 72 | # view results 73 | summary(leaps) 74 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6) 75 | # view results 76 | summary(leaps) 77 | plot(leaps,scale="r2") 78 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6) 79 | # view results 80 | summary(leaps) 81 | # plot a table of models showing variables in each model. 82 | # models are ordered by the selection statistic. 83 | plot(leaps,scale="r2") 84 | plot(leaps,scale="aic") 85 | plot(leaps,scale="bic") 86 | library(relaimpo) 87 | install.packages("relaimpo") 88 | library(relaimpo) 89 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable) 90 | calc.relimp(fit,type=c("lmg","last","first","pratt"),rela=TRUE) 91 | calc.relimp(fit,type=c("lmg"),rela=TRUE) 92 | impo <- calc.relimp(fit,type=c("lmg"),rela=TRUE) 93 | impo 94 | str(impo) 95 | impo@lmg 96 | boot <- boot.relimp(fit, b = 1000, type = c("lmg"), rank = TRUE, diff = TRUE, rela = TRUE) 97 | boot <- boot.relimp(fit, b = 50, type = c("lmg"), rank = TRUE, diff = TRUE, rela = TRUE) 98 | booteval.relimp(boot) # print result 99 | plot(booteval.relimp(boot,sort=TRUE)) # plot result 100 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6) 101 | # view results 102 | summary(leaps) 103 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable) 104 | step <- stepAIC(fit, direction="both") 105 | step$anova # display results 106 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + Media, data=MitoTable) 107 | step <- stepAIC(fit, direction="both") 108 | step$anova # display results 109 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable) 110 | step <- stepAIC(fit, direction="both") 111 | step$anova # display results 112 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio*Type + MitoToCellSurRatio*Media, data=MitoTable,nbest=6) 113 | # view results 114 | summary(leaps) 115 | plot(leaps,scale="r2") 116 | plot(leaps,scale="bic") 117 | plot(leaps,scale="r2") 118 | fit <- lm(AvgDegree ~ MitoToCellSurRatio * (Type + Media), data=MitoTable) 119 | step <- stepAIC(fit, direction="both") 120 | step$anova # display results 121 | fit <- lm(AvgDegree ~ MitoToCellSurRatio*Type + Media, data=MitoTable) 122 | boot <- boot.relimp(fit, b = 50, type = c("lmg"), rank = TRUE, diff = TRUE, rela = TRUE) 123 | booteval.relimp(boot) # print result 124 | plot(booteval.relimp(boot,sort=TRUE)) # plot result 125 | leaps<-regsubsets(AvgDegree ~ MitoToCellSurRatio * (Type + Media), data=MitoTable,nbest=6) 126 | summary(leaps) 127 | leaps$np 128 | leaps$nrbar 129 | leaps$first 130 | leaps$last 131 | leaps$vorder 132 | str(leaps) 133 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE) 134 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Date,Media))) + geom_point() 135 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Date,Media))) + geom_point() + geom_smooth(method="lm") 136 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Type))) + geom_point() + geom_smooth(method="lm") 137 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Type,Media))) + geom_point() + geom_smooth(method="lm") 138 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=interaction(Type,Media,Date))) + geom_point() + geom_smooth(method="lm") 139 | ggplot(MitoTable,aes(MitoToCellSurRatio,avgDegree,col=interaction(Type,Media,Date))) + geom_point() + geom_smooth(method="lm") 140 | M <- subset(MitoTable,interaction(Date,Type,Media)=="24.WT.Glucose") 141 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE) 142 | fit1 <- lm(M,CellVolume~MitoVolLen) 143 | fit1 <- lm(data=M,CellVolume~MitoVolLen) 144 | fit2 <- lm(data=M,MitoVolLen~CellVolume) 145 | plot(fit1) 146 | plot(fit2) 147 | fit1$coefficients 148 | fit1$coefficients[1] 149 | sumamry(fit1) 150 | summamy(fit1) 151 | summary(fit1) 152 | q<-summary(fit1) 153 | q 154 | fit1$coefficients[1] 155 | fit1$coefficients[2] 156 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2]) 157 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2]) 158 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2]) 159 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = fit1$coefficients[1], slope = fit1$coefficients[2]) 160 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept = 10) 161 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(aes(intercept = fit1$coefficients[1], slope = fit1$coefficients[2])) 162 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=10) 163 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=4) 164 | ggplot(M,aes(CellVolume,MitoVolLen,group=1)) + geom_point() + geom_abline(intercept=4) 165 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point(aes(group=1)) + geom_abline(intercept=4) 166 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point(aes(group=1)) + geom_abline(intercept=4) 167 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(intercept=4) 168 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(intercept=4)) 169 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=4)) 170 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=0.4)) 171 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=0.1)) 172 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=fit1$coefficients[2])) 173 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(aes(slope=fit2$coefficients[2])) 174 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(slope=fit2$coefficients[2]) 175 | ggplot(M,aes(x=CellVolume,y=MitoVolLen)) + geom_point() + geom_abline(intercept=fit2$coefficients[1],slope=fit2$coefficients[2]) 176 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c[2],slope=1/c2[2]) 177 | fit1 <- lm(data=M,CellVolume~MitoVolLen) 178 | c1 <- fit1$coefficients 179 | fit2 <- lm(data=M,MitoVolLen~CellVolume) 180 | c2 <- fit2$coefficients 181 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c[2],slope=1/c2[2]) 182 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c2[2],slope=1/c2[2]) 183 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=c2[1],slope=c2[2]) 184 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) 185 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) + geom_abline(intercept=c2[1],slope=c2[2]) 186 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 187 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) + 188 | geom_abline(intercept=c2[1],slope=c2[2]) + 189 | geom_abline(intercept=c2[1],slope=(c1[2]*c2[2]+1)/(2*c1[2])) 190 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 191 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2]) + 192 | geom_abline(intercept=c2[1],slope=c2[2]) + 193 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2])) 194 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 195 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],type=2) 196 | ?geom_abline 197 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 198 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) 199 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 200 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 201 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 202 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2])) 203 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 204 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 205 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 206 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) 207 | library(graphics) 208 | (pc.cr <- princomp(USArrests)) # inappropriate 209 | princomp(USArrests, cor = TRUE) # =^= prcomp(USArrests, scale=TRUE) 210 | summary(pc.cr <- princomp(USArrests, cor = TRUE)) 211 | loadings(pc.cr) # note that blank entries are small but not zero 212 | plot(pc.cr) # shows a screeplot. 213 | biplot(pc.cr) 214 | princomp(~ ., data = USArrests, cor = TRUE) 215 | ## NA-handling 216 | USArrests[1, 2] <- NA 217 | pc.cr <- princomp(~ Murder + Assault + UrbanPop, 218 | data = USArrests, na.action = na.exclude, cor = TRUE) 219 | pc.cr$scores[1:5, ] 220 | ## (Simple) Robust PCA: 221 | ## Classical: 222 | (pc.cl <- princomp(stackloss)) 223 | ## Robust: 224 | (pc.rob <- princomp(stackloss, covmat = MASS::cov.rob(stackloss))) 225 | df <- data.frame(iris) # iris dataset 226 | pca <- prcomp(df[,1:4], retx=T, scale.=T) # scaled pca [exclude species col] 227 | scores <- pca$x[,1:3] # scores for first three PC's 228 | # k-means clustering [assume 3 clusters] 229 | km <- kmeans(scores, centers=3, nstart=5) 230 | ggdata <- data.frame(scores, Cluster=km$cluster, Species=df$Species) 231 | # stat_ellipse is not part of the base ggplot package 232 | source("https://raw.github.com/low-decarie/FAAV/master/r/stat-ellipse.R") 233 | ggplot(ggdata) + 234 | geom_point(aes(x=PC1, y=PC2, color=factor(Cluster)), size=5, shape=20) + 235 | stat_ellipse(aes(x=PC1,y=PC2,fill=factor(Cluster)), 236 | geom="polygon", level=0.95, alpha=0.2) + 237 | guides(color=guide_legend("Cluster"),fill=guide_legend("Cluster")) 238 | source("https://raw.github.com/low-decarie/FAAV/master/r/stat-ellipse.R") 239 | set.seed(101) 240 | n <- 1000 241 | x <- rnorm(n, mean=2) 242 | y <- 1.5 + 0.4*x + rnorm(n) 243 | df <- data.frame(x=x, y=y, group="A") 244 | x <- rnorm(n, mean=2) 245 | y <- 1.5*x + 0.4 + rnorm(n) 246 | df <- rbind(df, data.frame(x=x, y=y, group="B")) 247 | #calculating ellipses 248 | library(ellipse) 249 | df_ell <- data.frame() 250 | install.packages("ellipse") 251 | library(ellipse) 252 | df_ell <- data.frame() 253 | for(g in levels(df$group)){ 254 | df_ell <- rbind(df_ell, cbind(as.data.frame(with(df[df$group==g,], ellipse(cor(x, y), 255 | scale=c(sd(x),sd(y)), 256 | centre=c(mean(x),mean(y))))),group=g)) 257 | } 258 | #drawing 259 | library(ggplot2) 260 | p <- ggplot(data=df, aes(x=x, y=y,colour=group)) + geom_point(size=1.5, alpha=.6) + 261 | geom_path(data=df_ell, aes(x=x, y=y,colour=group), size=1, linetype=2) 262 | p <- ggplot(data=df, aes(x=x, y=y,colour=group)) + geom_point(size=1.5, alpha=.6) + 263 | geom_path(data=df_ell, aes(x=x, y=y,colour=group), size=1, linetype=2) 264 | df_ell 265 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R") 266 | ??source_url 267 | install.packages("devtools") 268 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R") 269 | library(devtools) 270 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R") 271 | set.seed(20130226) 272 | n <- 200 273 | x1 <- rnorm(n, mean = 2) 274 | y1 <- 1.5 + 0.4 * x1 + rnorm(n) 275 | x2 <- rnorm(n, mean = -1) 276 | y2 <- 3.5 - 1.2 * x2 + rnorm(n) 277 | class <- rep(c("A", "B"), each = n) 278 | df <- data.frame(x = c(x1, x2), y = c(y1, y2), colour = class) 279 | # get code for "stat_ellipse" 280 | library(devtools) 281 | library(ggplot2) 282 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R") 283 | qplot(data = df, x = x, y = y, colour = class) + stat_ellipse() 284 | qplot(data = M, x = CellVolume, y = MitoVolLen) + stat_ellipse() 285 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 286 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 287 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 288 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 289 | stat_ellipse() 290 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 291 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 292 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 293 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 294 | stat_ellipse(alpha=0.4) 295 | ggplot(M,aes(CellVolume,MitoVolLen)) + geom_point() + 296 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 297 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 298 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 299 | stat_ellipse(geom = "polygon", alpha = 1/2) 300 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,fill=Media)) + geom_point() + 301 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 302 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 303 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 304 | stat_ellipse(geom = "polygon", alpha = 1/2) 305 | ggplot(MitoTable,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 306 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 307 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 308 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 309 | stat_ellipse(geom = "polygon", alpha = 1/2) 310 | M <- subset(MitoTable,interaction(Date)=="24") 311 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 312 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 313 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 314 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 315 | stat_ellipse(geom = "polygon", alpha = 1/2) 316 | fit1 <- lm(data=M,CellVolume~MitoVolLen*Media) 317 | c1 <- fit1$coefficients 318 | fit2 <- lm(data=M,MitoVolLen~CellVolume*Media) 319 | c2 <- fit2$coefficients 320 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 321 | geom_abline(intercept=-c1[1]/c1[2],slope=1/c1[2],linetype=2) + 322 | geom_abline(intercept=c2[1],slope=c2[2],linetype=2) + 323 | geom_abline(intercept=0.5*(c2[1]-c1[1]/c1[2]),slope=(c1[2]*c2[2]+1)/(2*c1[2]),size=2) + 324 | stat_ellipse(geom = "polygon", alpha = 1/2) 325 | M <- subset(MitoTable,interaction(Date)=="24") 326 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 327 | stat_ellipse(geom = "polygon", alpha = 1/2) 328 | M <- subset(MitoTable,interaction(Date)=="00") 329 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 330 | stat_ellipse(geom = "polygon", alpha = 1/2) 331 | princomp(M,aes(CellVolume,MitoVolLen,col=Media)) 332 | ?princomp 333 | princomp(~ ., data = USArrests, cor = TRUE) 334 | ## NA-handling 335 | USArrests[1, 2] <- NA 336 | pc.cr <- princomp(~ Murder + Assault + UrbanPop, 337 | data = USArrests, na.action=na.exclude, cor = TRUE) 338 | pc.cr$scores[1:5, ] 339 | ## (Simple) Robust PCA: 340 | ## Classical: 341 | (pc.cl <- princomp(stackloss)) 342 | ## Robust: 343 | (pc.rob <- princomp(stackloss, covmat = MASS::cov.rob(stackloss))) 344 | ## The variances of the variables in the 345 | ## USArrests data vary by orders of magnitude, so scaling is appropriate 346 | (pc.cr <- princomp(USArrests)) # inappropriate 347 | princomp(USArrests, cor = TRUE) # =^= prcomp(USArrests, scale=TRUE) 348 | ## Similar, but different: 349 | ## The standard deviations differ by a factor of sqrt(49/50) 350 | summary(pc.cr <- princomp(USArrests, cor = TRUE)) 351 | loadings(pc.cr) ## note that blank entries are small but not zero 352 | plot(pc.cr) # shows a screeplot. 353 | biplot(pc.cr) 354 | princomp(USArrests) 355 | princomp(MitoTable) 356 | M <- data.frame(M$CellVolume,M$MitoLength) 357 | princomp(M) 358 | p <- princomp(M) 359 | p$center 360 | p$scale 361 | p$loadings 362 | ld<-p$loadings 363 | ld 364 | summary(ld) 365 | ld 366 | ld@Comp.1 367 | list(ld) 368 | ld[1] 369 | ld[2] 370 | ld[3] 371 | ld[5] 372 | ld[4] 373 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 374 | stat_ellipse(geom = "polygon", alpha = 1/2) + 375 | geom_smooth(method="lm") 376 | M <- subset(MitoTable,interaction(Date)=="00") 377 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 378 | stat_ellipse(geom = "polygon", alpha = 1/2) + 379 | geom_smooth(method="lm") 380 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE) 381 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R") 382 | M <- subset(MitoTable,interaction(Date)=="24") 383 | ggplot(M,aes(CellVolume,MitoVolLen,col=Media)) + geom_point() + 384 | stat_ellipse(geom = "polygon", alpha = 1/2) + 385 | geom_smooth(method="lm") 386 | M <- subset(MitoTable,interaction(Date)=="24") 387 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 388 | stat_ellipse(geom = "polygon", alpha = 1/2) + 389 | geom_smooth(method="lm") 390 | M <- subset(MitoTable,interaction(Date)=="72") 391 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 392 | stat_ellipse(geom = "polygon", alpha = 1/2) + 393 | geom_smooth(method="lm") 394 | M <- subset(MitoTable,interaction(Date)!="72") 395 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 396 | stat_ellipse(geom = "polygon", alpha = 1/2) + 397 | geom_smooth(method="lm") 398 | M <- subset(MitoTable,interaction(Date)=="00") 399 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 400 | stat_ellipse(geom = "polygon", alpha = 1/2) + 401 | geom_smooth(method="lm") 402 | M <- subset(MitoTable,interaction(Date)=="24") 403 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 404 | stat_ellipse(geom = "polygon", alpha = 1/2) + 405 | geom_smooth(method="lm") 406 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() 407 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 408 | stat_ellipse(geom = "polygon", alpha = 1/2) + 409 | geom_smooth(method="lm") + 410 | facet_grid(Media~Type) 411 | ggplot(M,aes(CellVolume,MitoVolLen,col=interaction(Media,Type))) + geom_point() + 412 | stat_ellipse(geom = "polygon", alpha = 1/2) + 413 | #geom_smooth(method="lm") + 414 | facet_grid(Media~Type) 415 | ggplot(M,aes(avgDegree,MitoToCellSurRatio,col=interaction(Media,Type))) + geom_point() + 416 | stat_ellipse(geom = "polygon", alpha = 1/2) + 417 | #geom_smooth(method="lm") + 418 | facet_grid(Media~Type) 419 | M <- subset(MitoTable,interaction(Date)=="00") 420 | ggplot(M,aes(avgDegree,MitoToCellSurRatio,col=interaction(Media,Type))) + geom_point() + 421 | stat_ellipse(geom = "polygon", alpha = 1/2) + 422 | #geom_smooth(method="lm") + 423 | facet_grid(Media~Type) 424 | M <- subset(MitoTable,Date=="00"|Date=="24") 425 | M <- subset(MitoTable,Date=="00"|Date=="24") 426 | ggplot(M,aes(avgDegree,MitoToCellSurRatio,col=interaction(Media,Type,Date))) + geom_point() + 427 | stat_ellipse(geom = "polygon", alpha = 1/2) + 428 | #geom_smooth(method="lm") + 429 | facet_grid(Media~Type) 430 | ggplot(M,aes(MitoToCellSurRatio,avgDegree,col=interaction(Media,Type,Date))) + geom_point() + 431 | stat_ellipse(geom = "polygon", alpha = 1/2) + 432 | #geom_smooth(method="lm") + 433 | facet_grid(Media~Type) 434 | source('/Volumes/TOSH/UCI/MyData/NewScopeUnbudded/Analysis/GenTable.R', echo=TRUE) 435 | rm(list=ls()) 436 | library(igraph) 437 | library(ggplot2) 438 | library(devtools) 439 | source_url("https://raw.github.com/JoFrhwld/FAAV/master/r/stat-ellipse.R") 440 | source('~/.active-rstudio-document', echo=TRUE) 441 | setwd("~/GitHub/MitoGraph/") 442 | M <- read.table("RFP-020914_1_40_024.width.width") 443 | M <- read.table("RFP-020914_1_40_024.width") 444 | source('~/.active-rstudio-document', echo=TRUE) 445 | source('~/.active-rstudio-document', echo=TRUE) 446 | source('~/.active-rstudio-document', echo=TRUE) 447 | source('~/.active-rstudio-document', echo=TRUE) 448 | source('~/.active-rstudio-document', echo=TRUE) 449 | source('~/.active-rstudio-document', echo=TRUE) 450 | source('~/.active-rstudio-document', echo=TRUE) 451 | source('~/.active-rstudio-document', echo=TRUE) 452 | source('~/.active-rstudio-document', echo=TRUE) 453 | source('~/.active-rstudio-document', echo=TRUE) 454 | source('~/.active-rstudio-document', echo=TRUE) 455 | setwd("~/GitHub/MitoGraph/") 456 | M <- read.table("temp2.width",col.names=c("width","intensity")) 457 | setwd("~/GitHub/MitoGraph/") 458 | M <- read.table("temp2.width",col.names=c("id","length",width","intensity")) 459 | M <- read.table("temp2.width",col.names=c("id","length","width","intensity")) 460 | library(ggplot2) 461 | ggplot(M,aes(intensity,width)) + geom_point() + geom_smooth(method="loess") 462 | dim(M) 463 | setwd("~/GitHub/MitoGraph/") 464 | M <- read.table("temp1.width",col.names=c("id","length","width","intensity")) 465 | library(ggplot2) 466 | ggplot(M,aes(intensity,width)) + geom_point() + geom_smooth(method="loess") 467 | ggplot(M,aes(intensity,width,col=as.factor(id))) + geom_point() + geom_smooth(method="loess") 468 | M <- read.table("temp2.width",col.names=c("id","length","width","intensity")) 469 | ggplot(M,aes(intensity,width,col=as.factor(id))) + geom_point() + geom_smooth(method="loess") 470 | ggplot(M,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="loess") 471 | M 472 | plot(M$width~M$intensity) 473 | M <- read.table("temp2.width",col.names=c("id","length","width","intensity")) 474 | ggplot(M,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="loess") 475 | mean(M$length) 476 | ggplot(M,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="lm") 477 | source('~/.active-rstudio-document', echo=TRUE) 478 | mean(M$length) 479 | source('~/.active-rstudio-document', echo=TRUE) 480 | source('~/.active-rstudio-document', echo=TRUE) 481 | source('~/.active-rstudio-document', echo=TRUE) 482 | source('~/.active-rstudio-document', echo=TRUE) 483 | source('~/.active-rstudio-document', echo=TRUE) 484 | source('~/.active-rstudio-document', echo=TRUE) 485 | source('~/.active-rstudio-document', echo=TRUE) 486 | M11 <- read.table("temp2.width",col.names=c("id","length","width","intensity")) 487 | M12 <- subset(M11,length > mean(M12$length)) 488 | M21 <- read.table("temp2.width",col.names=c("id","length","width","intensity")) 489 | M22 <- subset(M21,length > mean(M21$length)) 490 | source('~/.active-rstudio-document', echo=TRUE) 491 | source('~/.active-rstudio-document', echo=TRUE) 492 | source('~/.active-rstudio-document', echo=TRUE) 493 | source('~/.active-rstudio-document', echo=TRUE) 494 | f11 <- ggplot(M11,aes(intensity,width,col=length)) + geom_point() + geom_smooth(method="lm") + 495 | scale_x_continuous(limits = c(2500,7500), expand = c(0, 0)) + 496 | scale_y_continuous(limits = c(0.00,0.40), expand = c(0, 0)) 497 | grid.arrange(f11,f12,f21,f22,ncol=2,clip=TRUE) 498 | source('~/.active-rstudio-document', echo=TRUE) 499 | f <- lm(M22$width~M22$intensity) 500 | summary(f) 501 | f11 <- summary(f11) 502 | f12 <- summary(f12) 503 | f21 <- summary(f21) 504 | f22 <- summary(f22) 505 | f11 <- summary(f11) 506 | f11 507 | f11 <- lm(M11$width~M11$intensity) 508 | f11 509 | f11 <- summary(f11) 510 | f11 511 | f11$r.squared 512 | f11$adj.r.squared 513 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | data/.DS_Store 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 3 | 4 | PROJECT(MitoGraph) 5 | 6 | FIND_PACKAGE(VTK) 7 | INCLUDE(${VTK_USE_FILE}) 8 | INCLUDE_DIRECTORIES(${VTK_INCLUDE_DIRS}) 9 | 10 | ADD_EXECUTABLE(MitoGraph MitoGraph MitoThinning ssThinning) 11 | 12 | if(VTK_LIBRARIES) 13 | TARGET_LINK_LIBRARIES(MitoGraph ${VTK_LIBRARIES}) 14 | else() 15 | TARGET_LINK_LIBRARIES(MitoGraph vtkHybrid vtkWidgets) 16 | endif() 17 | 18 | -------------------------------------------------------------------------------- /CompilationRecipes.md: -------------------------------------------------------------------------------- 1 | ## Recipe for MacOS 12.5.1 Chipset M2 2 | 3 | ``` 4 | mkdir mitograph 5 | cd mitograph 6 | wget https://www.vtk.org/files/release/8.2/VTK-8.2.0.tar.gz 7 | tar -xvf VTK-8.2.0.tar.gz && cd VTK-8.2.0 8 | mkdir build && cd build 9 | brew install cmake 10 | brew install libpng 11 | export CFLAGS="-DPNG_ARM_NEON_OPT=0" 12 | export CXXFLAGS="-DPNG_ARM_NEON_OPT=0" 13 | cmake -DPNG_PNG_INCLUDE_DIR=/opt/homebrew/include -DPNG_LIBRARY_RELEASE=/opt/homebrew/lib/libpng.dylib .. 14 | make 15 | sudo make install 16 | cd ../.. 17 | git clone https://github.com/vianamp/MitoGraph.git && cd MitoGraph 18 | mkdir build && cd build 19 | cmake .. 20 | make 21 | ``` 22 | 23 | ## Recipe for Windows 10 24 | 25 | 1. Install CMake 26 | 2. Install Visual Studio 17 2022 27 | 3. Download VTK 8.2.0 Source Code 28 | 4. Open CMake (cmake-gui). 29 | 5. Set the source directory to the VTK source directory. 30 | 6. Set the build directory to where you want to build the binaries (e.g., C:/vtk-build). 31 | 7. Click Configure and select your Visual Studio version 32 | 8. Click Generate and then Open Project. 33 | 9. In Visual Studio, build the project (ALL_BUILD). 34 | 35 | -------------------------------------------------------------------------------- /GraphAnalyzer.R: -------------------------------------------------------------------------------- 1 | # 2 | # External arguments 3 | # 4 | 5 | options(warn=-1) 6 | suppressMessages(library(igraph)) 7 | 8 | # args = '/Users/mviana/Desktop/MitoGraph/data/MitoGraphTest001' 9 | args = commandArgs(trailingOnly=TRUE) 10 | 11 | FileName <- args[1] 12 | 13 | # 14 | # Loading graph 15 | # 16 | 17 | G <- read.table(paste(FileName,'.gnet',sep=''), skip=1, col.names=c('Source','Target','Length')) 18 | G <- graph.data.frame(as.data.frame(G), directed=F) 19 | 20 | # 21 | # Loading volume information 22 | # 23 | 24 | Vol <- data.frame(read.table(paste(FileName,'.cc',sep=''), skip=1)) 25 | names(Vol) <- c('node','cc','vol_cc') 26 | 27 | ids <- as.numeric(V(G)$name) 28 | V(G)$cc_vol <- Vol$vol_cc[match(ids,Vol$node)] 29 | 30 | # 31 | # Connected component analysis 32 | # 33 | 34 | List <- decompose(G) 35 | 36 | Table <- NULL 37 | for (g in List) { 38 | Table <- rbind(Table,data.frame(vcount(g), ecount(g), sum(E(g)$Length), max(V(g)$cc_vol))) 39 | } 40 | 41 | names(Table) <- c('nodes','edges','length_(um)','vol_from_img_(um3)') 42 | 43 | Table <- Table[order(Table[,4], decreasing=T),] 44 | 45 | # 46 | # Loading global measurements 47 | # 48 | 49 | Global <- data.frame(read.table(paste(FileName,'.mitograph',sep=''), skip=1)) 50 | 51 | names(Global) <- c('vol_from_voxels_(um)', 'avg_width_(um)', 'std_width_(um)', 'total_length_(um)', 'vol_from_length_(um3)') 52 | 53 | Global$nodes <- vcount(G) 54 | 55 | Global$edges <- ecount(G) 56 | 57 | Global$components <- length(List) 58 | 59 | output_file <- paste(FileName,'.mitograph',sep='') 60 | 61 | cat('::MitoGraph\n',file=output_file, append=F) 62 | cat(paste(Sys.time(),'\n'),file=output_file, append=T) 63 | cat('\n',file=output_file, append=T) 64 | cat('GLOBAL STATISTICS:\n',file=output_file, append=T) 65 | cat('\n',file=output_file, append=T) 66 | write.table(Global,output_file, 67 | append=T, 68 | row.names=F, 69 | col.names=T, 70 | sep="\t", 71 | quote=F) 72 | cat('\n',file=output_file, append=T) 73 | cat('COMPONENTS STATISTICS:\n',file=output_file, append=T) 74 | cat('\n',file=output_file, append=T) 75 | write.table(Table,output_file, 76 | append=T, 77 | row.names=F, 78 | col.names=T, 79 | sep="\t", 80 | quote=F) 81 | 82 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /MitoThinning.cxx: -------------------------------------------------------------------------------- 1 | // ===================================================================================================== 2 | // MitoThinning: This routine receives as input an ImageData binary from MitoGraph main routine a and 3 | // apply a thinning process over it, resulting in a new but topologically equivalent image. 4 | // 5 | // Matheus P. Viana - vianamp@gmail.com - 2014.06.10 6 | // Susanne Rafelski Lab, University of California Irvine 7 | // ===================================================================================================== 8 | 9 | #include "MitoThinning.h" 10 | 11 | int ssdx[26] = {-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1,-1, 0, 1}; 12 | int ssdy[26] = {-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 13 | int ssdz[26] = { 1, 1, 1, 0, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0,-1,-1,-1, 1, 1, 1, 0, 0, 0,-1,-1,-1}; 14 | 15 | // Routine used to save .gnet and .coo files representing 16 | // the skeleton of the mitochondrial network. 17 | void ExportGraphFiles(vtkSmartPointer PolyData, long int nnodes, const char Prefix[]); 18 | 19 | // Routine to create the file _nodes.vtk. This file contains 20 | // little speres located at the junctions (nodes) coordinates 21 | // and might have the nodes label depending on if the variable 22 | // export_node_labels is true or false. 23 | void ExportNodes(vtkSmartPointer PolyData, long int nnodes, long int *ValidId, _mitoObject *mitoObject); 24 | 25 | // Routine used to check whether a voxel is locates at the border 26 | // of the binary image or not. A border voxel is defined as those 27 | // that have at least one of their 6-neighbors equal to zero. 28 | bool IsBorder(vtkIdType id, vtkSmartPointer Image); 29 | 30 | // Routine used to smooth the parametric curves that describe the 31 | // skeleton edges. A simple average filter is used to do the job. 32 | // Sigma represents the number of times the filter is applied. 33 | void SmoothEdgesCoordinates(vtkSmartPointer PolyData, double sigma); 34 | 35 | // Estimate the mitochondrial volume by counting the number of 36 | // pixels in the binary image used as input for thinning. 37 | void GetVolumeFromVoxels(vtkSmartPointer Image, std::vector *Atts); 38 | 39 | // Estimate the mitochondrial volume by using the skeleton 40 | // total length and assuming constant radius. 41 | //void GetVolumeFromSkeletonLength(vtkSmartPointer PolyData, double *attributes); 42 | 43 | // Calculate the length of a given edge. 44 | //double GetEdgeLength(vtkIdType edge, vtkSmartPointer PolyData); 45 | 46 | // Returns the number of voxels around the voxel (x,y,z) with 47 | // value given different of "value". 48 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, int x, int y, int z, long int value); 49 | 50 | // Returns the number of voxels around the voxel (x,y,z) with 51 | // value different of "value" in the vector "Volume". 52 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value); 53 | 54 | // Returns the number of voxels around the voxel (x,y,z) with 55 | // value given by "value". 56 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, int x, int y, int z, long int value); 57 | 58 | // Returns the number of voxels around the voxel (x,y,z) with 59 | // value "value" in the vector "Volume". 60 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value); 61 | 62 | // Returns one neighbor of (x,y,z) with value "value" in the 63 | // vector "Volume". 64 | vtkIdType GetOneNeighborWithValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value); 65 | 66 | // Returns one neighbor of (x,y,z) with value different of 67 | // "value" in the vector "Volume". 68 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value); 69 | 70 | // Returns one neighbor of (x,y,z) with value different of 71 | // "value". 72 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, long int value); 73 | 74 | // Merge together junctions that touch each other. 75 | bool JunctionsMerge(std::list Junctions, vtkSmartPointer Image, vtkSmartPointer Volume); 76 | 77 | // Track an edge starting at voxel (x,y,z) in the volume "Volume". 78 | std::list GetEdgeStartingAt(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume); 79 | 80 | // Returns an adjacency edge "edge_label". 81 | long int GetOneAdjacentEdge(vtkSmartPointer PolyData, long int edge_label, long int junction_label, bool *found_on_left); 82 | 83 | // Track all the nodes and edges of a 3D structured thinned by 84 | // the routine Thinning3D. 85 | vtkSmartPointer Skeletonization(vtkSmartPointer Image, _mitoObject *mitoObject); 86 | 87 | // Replace two edges A and B attached to a node of degree 2 88 | // with one edge C that corresponds to A + B. The degree of the 89 | // node is set to -1 and A and B are moreved from PolyData. 90 | bool MergeEdgesOfDegree2Nodes(vtkSmartPointer PolyData, long int nedges_before_filtering, int *K); 91 | 92 | // After merging edges attached to nodes of degree 2, the original 93 | // edges must be deleted throught this routine. 94 | void RemoveCellsWithInvalidNodes(vtkSmartPointer PolyData, int *K); 95 | 96 | /* ================================================================ 97 | I/O ROUTINES 98 | =================================================================*/ 99 | 100 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample) { 101 | #ifdef DEBUG 102 | printf("Saving ImageData File...\n"); 103 | #endif 104 | 105 | vtkSmartPointer Flip = vtkSmartPointer::New(); 106 | Flip -> SetInputData(Image); 107 | Flip -> SetFilteredAxis(1); 108 | Flip -> PreserveImageExtentOn(); 109 | Flip -> Update(); 110 | 111 | vtkSmartPointer writer = vtkSmartPointer::New(); 112 | writer -> SetFileName(FileName); 113 | 114 | // TIF writer does not support data of type double 115 | if (Image -> GetScalarType() == VTK_DOUBLE) { 116 | 117 | double range[2]; 118 | Image -> GetScalarRange( range ); 119 | vtkSmartPointer ShiftFilter = vtkSmartPointer::New(); 120 | ShiftFilter -> SetInputData(Flip->GetOutput()); 121 | ShiftFilter -> SetScale( 65535./(range[1]-range[0])); 122 | ShiftFilter -> SetShift( -range[0] ); 123 | ShiftFilter -> SetOutputScalarTypeToUnsignedShort(); 124 | ShiftFilter -> Update(); 125 | 126 | writer -> SetInputData(ShiftFilter->GetOutput()); 127 | 128 | } else { 129 | 130 | if (_resample) { 131 | #ifdef DEBUG 132 | printf("\tResampling data...%f\t%f\n",_dxy,_dz); 133 | #endif 134 | vtkSmartPointer Resample = vtkSmartPointer::New(); 135 | Resample -> SetInterpolationModeToLinear(); 136 | Resample -> SetDimensionality(3); 137 | Resample -> SetInputData(Flip->GetOutput()); 138 | Resample -> SetAxisMagnificationFactor(0,1.0); 139 | Resample -> SetAxisMagnificationFactor(1,1.0); 140 | Resample -> SetAxisMagnificationFactor(2,_dz/_dxy); 141 | Resample -> Update(); 142 | 143 | vtkSmartPointer ImageResampled = Resample -> GetOutput(); 144 | ImageResampled -> SetSpacing(1,1,1); 145 | 146 | writer -> SetInputData(ImageResampled); 147 | } else { 148 | 149 | writer -> SetInputData(Flip->GetOutput()); 150 | 151 | } 152 | 153 | } 154 | 155 | writer -> Write(); 156 | 157 | #ifdef DEBUG 158 | printf("\tFile Saved!\n"); 159 | #endif 160 | } 161 | 162 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[]) { 163 | 164 | #ifdef DEBUG 165 | printf("Saving PolyData...\n"); 166 | #endif 167 | 168 | #ifdef DEBUG 169 | printf("\t#Points in PolyData file: %llu.\n",(vtkIdType)PolyData->GetNumberOfPoints()); 170 | #endif 171 | 172 | vtkSmartPointer Writer = vtkSmartPointer::New(); 173 | #ifndef DEBUG 174 | Writer -> SetFileType(VTK_BINARY); 175 | #endif 176 | Writer -> SetFileName(FileName); 177 | Writer -> SetInputData(PolyData); 178 | Writer -> Write(); 179 | 180 | #ifdef DEBUG 181 | printf("\tFile Saved!\n"); 182 | #endif 183 | } 184 | 185 | void ExportGraphFiles(vtkSmartPointer PolyData, long int nnodes, long int *ValidId, const char Prefix[]) { 186 | 187 | #ifdef DEBUG 188 | printf("Saving .coo file...\n"); 189 | #endif 190 | 191 | char _fullpath[256]; 192 | 193 | vtkPoints *Points = PolyData -> GetPoints(); 194 | 195 | double r[3]; 196 | long int node, exact_nnodes = 0; 197 | for (node = 0; node < nnodes; node++) { 198 | if (ValidId[node]>=0) exact_nnodes++; 199 | } 200 | 201 | sprintf(_fullpath,"%s.coo",Prefix); 202 | FILE *fcoo = fopen(_fullpath,"w"); 203 | for (node = 0; node < nnodes; node++) { 204 | if (ValidId[node]>=0) { 205 | Points -> GetPoint(node,r); 206 | fprintf(fcoo,"%1.4f\t%1.4f\t%1.4f\n",_dxy*r[0],_dxy*r[1],_dz*r[2]); 207 | } 208 | } 209 | fclose(fcoo); 210 | 211 | double length; 212 | vtkIdType edge, npoints, i, j; 213 | sprintf(_fullpath,"%s.gnet",Prefix); 214 | FILE *fgnet = fopen(_fullpath,"w"); 215 | fprintf(fgnet,"%ld\n",exact_nnodes); 216 | for (edge = 0; edge < PolyData -> GetNumberOfCells(); edge++) { 217 | npoints = PolyData -> GetCell(edge) -> GetNumberOfPoints(); 218 | i = PolyData -> GetCell(edge) -> GetPointId(0); 219 | j = PolyData -> GetCell(edge) -> GetPointId(npoints-1); 220 | if ( ValidId[i] >= 0 && ValidId[j] >= 0 ) { 221 | length = GetEdgeLength(edge,PolyData); 222 | fprintf(fgnet,"%ld\t%ld\t%1.5f\n",ValidId[i],ValidId[j],length); 223 | } 224 | } 225 | fclose(fgnet); 226 | 227 | } 228 | 229 | void ExportNodes(vtkSmartPointer PolyData, long int nnodes, long int *ValidId, _mitoObject *mitoObject) { 230 | 231 | #ifdef DEBUG 232 | if (_export_nodes_label) { 233 | printf("Exporting nodes and their labels...\n"); 234 | } else { 235 | printf("Exporting nodes...\n"); 236 | } 237 | #endif 238 | 239 | vtkPoints *Points = PolyData -> GetPoints(); 240 | vtkSmartPointer Append = vtkSmartPointer::New(); 241 | Append -> SetOutputPointsPrecision(vtkAlgorithm::DEFAULT_PRECISION); 242 | 243 | double r[3]; 244 | long int node; 245 | char node_txt[16]; 246 | for (node = 0; node < nnodes; node++) { 247 | if ( ValidId[node] >= 0 ) { 248 | Points -> GetPoint(node,r); 249 | 250 | #ifdef DEBUG 251 | printf("Node = %d\n",(int)node); 252 | #endif 253 | 254 | vtkSmartPointer Node = vtkSmartPointer::New(); 255 | if (_scale_polydata_before_save) { 256 | Node -> SetRadius(2*_dxy); 257 | Node -> SetCenter(_dxy*(r[0]+mitoObject->Ox),_dxy*(r[1]+mitoObject->Oy),_dz*(r[2]+mitoObject->Oz)); 258 | } else { 259 | Node -> SetRadius(2.0); 260 | Node -> SetCenter(r[0]+mitoObject->Ox,r[1]+mitoObject->Oy,r[2]+mitoObject->Oz); 261 | } 262 | 263 | Node -> SetThetaResolution(6); 264 | Node -> SetPhiResolution(6); 265 | Node -> Update(); 266 | Append -> AddInputData(Node->GetOutput()); 267 | Append -> Update(); 268 | 269 | if (_export_nodes_label) { 270 | sprintf(node_txt,"%ld",ValidId[node]); 271 | vtkSmartPointer PolyText = vtkSmartPointer::New(); 272 | PolyText -> SetText(node_txt); 273 | PolyText -> Update(); 274 | 275 | vtkSmartPointer T = vtkSmartPointer::New(); 276 | if (_scale_polydata_before_save) { 277 | T -> Translate(_dxy*(r[0]+1+mitoObject->Ox),_dxy*(r[1]+1+mitoObject->Oy),_dz*(r[2]+mitoObject->Oz)); 278 | T -> Scale(2*_dxy,2*_dxy,1); 279 | } else { 280 | T -> Translate(r[0]+2+mitoObject->Ox,r[1]+mitoObject->Oy,r[2]+mitoObject->Oz); 281 | T -> Scale(2,2,1); 282 | } 283 | 284 | vtkSmartPointer Trans = vtkSmartPointer::New(); 285 | Trans -> SetInputData(PolyText->GetOutput()); 286 | Trans -> SetTransform(T); 287 | Trans -> Update(); 288 | 289 | Append -> AddInputData(Trans -> GetOutput()); 290 | Append -> Update(); 291 | } 292 | } 293 | 294 | } 295 | 296 | SavePolyData(Append->GetOutput(),(mitoObject->FileName+"_nodes.vtk").c_str()); 297 | } 298 | 299 | 300 | /* ================================================================ 301 | IMAGE TRANSFORMATION 302 | =================================================================*/ 303 | 304 | void CleanImageBoundaries(vtkSmartPointer ImageData) { 305 | #ifdef DEBUG 306 | printf("Cleaning the image boundaries...\n"); 307 | #endif 308 | int p, q; 309 | int *Dim = ImageData -> GetDimensions(); 310 | for ( p = Dim[0]; p--; ) { 311 | for ( q = Dim[1]; q--; ) { 312 | ImageData -> SetScalarComponentFromDouble(p,q,0,0,0); 313 | ImageData -> SetScalarComponentFromDouble(p,q,Dim[2]-1,0,0); 314 | } 315 | } 316 | for ( p = Dim[0]; p--; ) { 317 | for ( q = Dim[2]; q--; ) { 318 | ImageData -> SetScalarComponentFromDouble(p,0,q,0,0); 319 | ImageData -> SetScalarComponentFromDouble(p,Dim[1]-1,q,0,0); 320 | } 321 | } 322 | for ( p = Dim[1]; p--; ) { 323 | for ( q = Dim[2]; q--; ) { 324 | ImageData -> SetScalarComponentFromDouble(0,p,q,0,0); 325 | ImageData -> SetScalarComponentFromDouble(Dim[0]-1,p,q,0,0); 326 | } 327 | } 328 | } 329 | 330 | /* ================================================================ 331 | AUXILIAR ROUTINES 332 | =================================================================*/ 333 | 334 | 335 | bool IsBorder(vtkIdType id, vtkSmartPointer Image) { 336 | double r[3]; 337 | int x, y, z; 338 | Image -> GetPoint(id,r); 339 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 340 | if(!Image->GetScalarComponentAsDouble(x,y,z,0)) return false; 341 | if(!Image->GetScalarComponentAsDouble(x+1,y,z,0)) return true; 342 | if(!Image->GetScalarComponentAsDouble(x-1,y,z,0)) return true; 343 | if(!Image->GetScalarComponentAsDouble(x,y+1,z,0)) return true; 344 | if(!Image->GetScalarComponentAsDouble(x,y-1,z,0)) return true; 345 | if(!Image->GetScalarComponentAsDouble(x,y,z+1,0)) return true; 346 | if(!Image->GetScalarComponentAsDouble(x,y,z-1,0)) return true; 347 | return false; 348 | } 349 | 350 | void SmoothEdgesCoordinates(vtkSmartPointer PolyData, double sigma){ 351 | 352 | double r1[3], r2[3], r3[3]; 353 | long int id, line, nlines, n, s; 354 | vtkPoints *Points = PolyData -> GetPoints(); 355 | 356 | vtkCell *Line; 357 | nlines = PolyData -> GetNumberOfCells(); 358 | 359 | for (line = 0; line < nlines; line++){ 360 | Line = PolyData -> GetCell(line); 361 | n = Line -> GetNumberOfPoints(); 362 | double *X = new double[n]; 363 | double *Y = new double[n]; 364 | double *Z = new double[n]; 365 | for (s = 0; s < int(sigma); s++) { 366 | for (id = 1; id < n-1; id++ ) { 367 | Points -> GetPoint(Line->GetPointId(id-1),r1); 368 | Points -> GetPoint(Line->GetPointId(id+0),r2); 369 | Points -> GetPoint(Line->GetPointId(id+1),r3); 370 | X[id] = 0.125*(r1[0]+6*r2[0]+r3[0]); 371 | Y[id] = 0.125*(r1[1]+6*r2[1]+r3[1]); 372 | Z[id] = (1.0/3.0)*(r1[2]+r2[2]+r3[2]); 373 | } 374 | for (id = 1; id < n-1; id++ ) { 375 | Points -> SetPoint(Line->GetPointId(id),X[id],Y[id],Z[id]); 376 | } 377 | } 378 | delete[] X; delete[] Y; delete[] Z; 379 | } 380 | PolyData -> Modified(); 381 | } 382 | 383 | void GetVolumeFromVoxels(vtkSmartPointer Image, std::vector *Atts) { 384 | double v; 385 | unsigned long int nv = 0; 386 | for (vtkIdType id=Image->GetNumberOfPoints();id--;) { 387 | v = Image -> GetPointData() -> GetScalars() -> GetTuple1(id); 388 | if (v) nv++; 389 | } 390 | attribute newAtt = {"Volume from voxels",nv * (_dxy * _dxy * _dz)}; 391 | Atts -> push_back(newAtt); 392 | } 393 | /* 394 | void GetVolumeFromSkeletonLength(vtkSmartPointer PolyData, double *attributes) { 395 | double r1[3], r2[3], length = 0.0; 396 | vtkPoints *Points = PolyData -> GetPoints(); 397 | for (vtkIdType edge=PolyData->GetNumberOfCells();edge--;) { 398 | length += GetEdgeLength(edge,PolyData); 399 | } 400 | attributes[1] = length; 401 | attributes[2] = length * (acos(-1.0)*pow(_rad,2)); 402 | } 403 | */ 404 | double GetEdgeLength(vtkIdType edge, vtkSmartPointer PolyData) { 405 | double r1[3], r2[3]; 406 | double length = 0.0; 407 | for (vtkIdType n = 1; n < PolyData->GetCell(edge)->GetNumberOfPoints(); n++) { 408 | PolyData -> GetPoint(PolyData->GetCell(edge)->GetPointId(n-1),r1); 409 | PolyData -> GetPoint(PolyData->GetCell(edge)->GetPointId(n ),r2); 410 | length += sqrt(pow(_dxy*(r2[0]-r1[0]),2)+pow(_dxy*(r2[1]-r1[1]),2)+pow(_dz*(r2[2]-r1[2]),2)); 411 | } 412 | return length; 413 | } 414 | 415 | /* ================================================================ 416 | THINNING 3D 417 | =================================================================*/ 418 | 419 | vtkSmartPointer Thinning3D(vtkSmartPointer ImageData, _mitoObject *mitoObject) { 420 | 421 | #ifdef DEBUG 422 | SaveImageData(ImageData,(mitoObject->FileName+"_binary.tif").c_str()); 423 | #endif 424 | 425 | vtkIdType N = ImageData -> GetNumberOfPoints(); 426 | GetVolumeFromVoxels(ImageData,&mitoObject->attributes); 427 | 428 | int x, y, z; 429 | double r[3], v, vl; 430 | vtkIdType ndels, id; 431 | ssThinVox *STV = new ssThinVox(); 432 | 433 | CleanImageBoundaries(ImageData); 434 | 435 | int i, j, ***Vol = new int**[3]; 436 | for (i = 0; i < 3; i++) { 437 | Vol[i] = new int*[3]; 438 | for (j = 0; j < 3; j++) { 439 | Vol[i][j] = new int[3]; 440 | } 441 | } 442 | 443 | #ifdef DEBUG 444 | printf("Starting thinning process...\n"); 445 | #endif 446 | 447 | std::list ToBeDeleted; 448 | std::list OnTheSurface; 449 | std::list::iterator itId; 450 | 451 | do { 452 | ndels = 0; 453 | for (id = N; id--;) { 454 | if (IsBorder(id, ImageData)) { 455 | OnTheSurface.insert(OnTheSurface.begin(),id); 456 | } 457 | } 458 | 459 | for (int direction = 6; direction--;) { 460 | for ( itId=OnTheSurface.begin(); itId!=OnTheSurface.end(); itId++) { 461 | id = *itId; 462 | ImageData -> GetPoint(id,r); 463 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 464 | v = ImageData -> GetScalarComponentAsDouble(x,y,z,0); 465 | if (v) { 466 | for (i = 26; i--;) { 467 | vl = ImageData -> GetScalarComponentAsDouble(x+ssdx[i],y+ssdy[i],z+ssdz[i],0); 468 | Vol[1+ssdx[i]][1+ssdy[i]][1+ssdz[i]] = (vl) ? 1 : 0; 469 | } 470 | if ( STV -> match(direction,Vol) ) ToBeDeleted.insert(ToBeDeleted.begin(),id); 471 | } 472 | } 473 | itId = ToBeDeleted.begin(); 474 | while (itId != ToBeDeleted.end()) { 475 | ndels++; 476 | ImageData -> GetPoint(*itId,r); 477 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 478 | ImageData -> SetScalarComponentFromDouble(x,y,z,0,0); 479 | ToBeDeleted.erase(itId++); 480 | } 481 | } 482 | 483 | #ifdef DEBUG 484 | printf("\t#Surface = %llu / #Deletions = %llu\n",(long long int)OnTheSurface.size(),ndels); 485 | #endif 486 | 487 | OnTheSurface.clear(); 488 | 489 | } while(ndels); 490 | 491 | delete STV; 492 | 493 | #ifdef DEBUG 494 | printf("Thinning done!\n"); 495 | #endif 496 | 497 | OnTheSurface.clear(); 498 | ToBeDeleted.clear(); 499 | 500 | return Skeletonization(ImageData,mitoObject); 501 | 502 | } 503 | 504 | /* ================================================================ 505 | SKELETONIZATION 506 | =================================================================*/ 507 | 508 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, int x, int y, int z, long int value) { 509 | double r[3]; 510 | char nn = 0; 511 | for (char k = 26; k--;) { 512 | if (Image->GetScalarComponentAsDouble(x+ssdx[k],y+ssdy[k],z+ssdz[k],0) != value) nn++; 513 | } 514 | return nn; 515 | } 516 | 517 | char GetNumberOfNeighborsWithoutValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value) { 518 | double r[3]; 519 | char nn = 0; 520 | vtkIdType idk; 521 | for (char k = 26; k--;) { 522 | idk = Image->FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]); 523 | if (Volume->GetTuple1(idk) != value) nn++; 524 | } 525 | return nn; 526 | } 527 | 528 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, int x, int y, int z, long int value) { 529 | double r[3]; 530 | char nn = 0; 531 | for (char k = 26; k--;) { 532 | if (Image->GetScalarComponentAsDouble(x+ssdx[k],y+ssdy[k],z+ssdz[k],0) == value) nn++; 533 | } 534 | return nn; 535 | } 536 | 537 | char GetNumberOfNeighborsWithValue(vtkSmartPointer Image, vtkSmartPointer Volume, int x, int y, int z, long int value) { 538 | double r[3]; 539 | char nn = 0; 540 | vtkIdType idk; 541 | for (char k = 26; k--;) { 542 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]); 543 | if (Volume->GetTuple1(idk) == value) nn++; 544 | } 545 | return nn; 546 | } 547 | 548 | vtkIdType GetOneNeighborWithValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value) { 549 | vtkIdType idk; 550 | for (char k = 26; k--;) { 551 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]); 552 | if (Volume -> GetTuple1(idk) == value) { 553 | return idk; 554 | } 555 | } 556 | return 0; // We can do it because, by construction the voxel at id 0 should always be empty 557 | } 558 | 559 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume, long int value) { 560 | vtkIdType idk; 561 | for (char k = 26; k--;) { 562 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]); 563 | if (Volume -> GetTuple1(idk) && Volume -> GetTuple1(idk) != value) { 564 | return idk; 565 | } 566 | } 567 | return 0; // We can do it because, by construction the voxel at id 0 should always be empty 568 | } 569 | 570 | vtkIdType GetOneNeighborWithoutValue(int x, int y, int z, vtkSmartPointer Image, long int value) { 571 | vtkIdType idk; 572 | for (char k = 26; k--;) { 573 | idk = Image -> FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]); 574 | if (Image->GetScalarComponentAsDouble(x+ssdx[k],y+ssdy[k],z+ssdz[k],0)!=value) return idk; 575 | } 576 | return 0; // We can do it because, by construction the voxel at id 0 should always be empty 577 | } 578 | 579 | bool JunctionsMerge(std::list Junctions, vtkSmartPointer Image, vtkSmartPointer Volume) { 580 | char nk; 581 | double r[3]; 582 | vtkIdType id; 583 | int x, y, z, k; 584 | bool _has_changed = false; 585 | std::list::iterator itId; 586 | long int junction_label, neigh_junction_label; 587 | for (itId=Junctions.begin(); itId!=Junctions.end(); itId++) { 588 | Image -> GetPoint(*itId,r); 589 | junction_label = Volume -> GetTuple1(*itId); 590 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 591 | for (k = 0; k < 26; k++) { 592 | id = Image->FindPoint(x+ssdx[k],y+ssdy[k],z+ssdz[k]); 593 | neigh_junction_label = Volume -> GetTuple1(id); 594 | if (junction_label < neigh_junction_label) { 595 | _has_changed = true; 596 | Volume -> SetTuple1(id,junction_label); 597 | } 598 | } 599 | } 600 | Volume -> Modified(); 601 | return _has_changed; 602 | } 603 | 604 | std::list GetEdgeStartingAt(int x, int y, int z, vtkSmartPointer Image, vtkSmartPointer Volume) { 605 | double r[3]; 606 | vtkIdType idk; 607 | std::list Edge; 608 | do { 609 | idk = GetOneNeighborWithValue(x,y,z,Image,Volume,-1); 610 | if (idk) { 611 | Volume -> SetTuple1(idk,0); 612 | Edge.insert(Edge.end(),idk); 613 | Image -> GetPoint(idk,r); 614 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 615 | } 616 | } while(idk); 617 | return Edge; 618 | } 619 | 620 | long int GetOneAdjacentEdge(vtkSmartPointer PolyData, long int edge_label, long int original_source, bool *_common_source) { 621 | vtkCell *Edge; 622 | long int source, target; 623 | for (long int edge = PolyData->GetNumberOfCells();edge--;) { 624 | if (edge != edge_label) { 625 | Edge = PolyData -> GetCell((vtkIdType)edge); 626 | source = Edge -> GetPointId(0); 627 | target = Edge -> GetPointId(Edge->GetNumberOfPoints()-1); 628 | if (original_source==source) { 629 | *_common_source = true; 630 | return edge; 631 | } 632 | if (original_source==target) { 633 | *_common_source = false; 634 | return edge; 635 | } 636 | } 637 | } 638 | return -1; 639 | } 640 | 641 | vtkSmartPointer Skeletonization(vtkSmartPointer Image, _mitoObject *mitoObject) { 642 | 643 | #ifdef DEBUG 644 | SaveImageData(Image,(mitoObject->FileName+"_thinned.tif").c_str()); 645 | #endif 646 | 647 | double r[3]; 648 | int x, y, z; 649 | vtkIdType id; 650 | long int junction_label = 1; 651 | vtkIdType N = Image -> GetNumberOfPoints(); 652 | std::list Junctions; 653 | std::list::iterator itId; 654 | 655 | // Inside this IF statement, isolated voxels and isolated pairs of voxels 656 | // are expanded. If this is not done, these voxels will not be detected. 657 | // This requires O(N). 658 | if (_improve_skeleton_quality) { 659 | 660 | #ifdef DEBUG 661 | printf("Improving skeletonization [step 1: isolated single and pair of voxels]\n"); 662 | #endif 663 | 664 | char nn; 665 | double rn[3]; 666 | vtkIdType idn; 667 | int xn, yn, zn; 668 | for (id = N; id--;) { 669 | Image -> GetPoint(id,r); 670 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 671 | if (Image->GetScalarComponentAsDouble(x,y,z,0)) { 672 | nn = GetNumberOfNeighborsWithoutValue(Image,x,y,z,0); 673 | if (nn==0) { 674 | // Expanding isolated voxel 675 | Image -> SetScalarComponentFromDouble(x+1,y,z,0,255); 676 | Image -> SetScalarComponentFromDouble(x-1,y,z,0,255); 677 | } else if (nn==1) { 678 | idn = GetOneNeighborWithoutValue(x,y,z,Image,0); 679 | Image -> GetPoint(idn,rn); 680 | xn = (int)rn[0]; yn = (int)rn[1]; zn = (int)rn[2]; 681 | if (GetNumberOfNeighborsWithoutValue(Image,xn,yn,zn,0)==1) { 682 | // Expanding isolated pair of voxels 683 | Image -> SetScalarComponentFromDouble(x-(int)(rn[0]-r[0]),y-(int)(rn[1]-r[1]),z-(int)(rn[2]-r[2]),0,255); 684 | Image -> SetScalarComponentFromDouble(xn+(int)(rn[0]-r[0]),yn+(int)(rn[1]-r[1]),zn+(int)(rn[2]-r[2]),0,255); 685 | } 686 | } 687 | } 688 | } 689 | } 690 | 691 | vtkSmartPointer Volume = vtkSmartPointer::New(); 692 | Volume -> SetNumberOfComponents(1); 693 | Volume -> SetNumberOfTuples(N); 694 | 695 | // Inside this IF statement, we label all connected components 696 | // and we search for those cc that don't have junctions. If any 697 | // is found, we force it to have a junction by adding its first 698 | // voxel to the list Junctions. This fixes the problem of not 699 | // detecting loop-shaped ccs. 700 | if (_improve_skeleton_quality) { 701 | #ifdef DEBUG 702 | printf("Improving skeletonization [step 2: verifying connected components]\n"); 703 | #endif 704 | long int n_fixed = 0; 705 | std::vector CSz; 706 | long int cc, ncc = LabelConnectedComponents(Image,Volume,CSz,26,0); 707 | 708 | bool *HasJunction = new bool[ncc]; 709 | for (cc = ncc; cc--;) HasJunction[cc] = 0; 710 | for (id = N; id--;) { 711 | Image -> GetPoint(id,r); 712 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 713 | cc = (long int)Volume -> GetTuple1(id); 714 | if (cc) { 715 | if (GetNumberOfNeighborsWithValue(Image,Volume,x,y,z,cc) != 2) { 716 | HasJunction[(unsigned long int)(-cc-1)] = true; 717 | } 718 | } 719 | Image -> SetScalarComponentFromDouble(x,y,z,0,-cc); 720 | } 721 | for (id = N; id--;) { 722 | Image -> GetPoint(id,r); 723 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 724 | cc = (long int)Volume -> GetTuple1(id); 725 | if (cc) { 726 | if (!HasJunction[(unsigned long int)(-cc-1)]) { 727 | HasJunction[(unsigned long int)(-cc-1)] = true; 728 | Junctions.insert(Junctions.begin(),id); 729 | Volume -> SetTuple1(id,junction_label); 730 | junction_label++; 731 | n_fixed++; 732 | } else { 733 | Volume -> SetTuple1(id,-1); 734 | } 735 | } else { 736 | Volume -> SetTuple1(id,0); 737 | } 738 | } 739 | delete[] HasJunction; 740 | 741 | #ifdef DEBUG 742 | printf("\t#Components fixed = %ld\n",n_fixed); 743 | #endif 744 | 745 | Image -> GetPointData() -> GetScalars() -> Modified(); 746 | 747 | } else { 748 | 749 | for (id = N; id--;) { 750 | if (Image -> GetPointData() -> GetScalars() -> GetTuple1(id)) { 751 | Volume -> SetTuple1(id,-1); 752 | } else { 753 | Volume -> SetTuple1(id,0); 754 | } 755 | } 756 | Volume -> Modified(); 757 | 758 | } 759 | 760 | #ifdef DEBUG 761 | printf("Starting skeletonization...\n"); 762 | printf("\tSearching for junctions...\n"); 763 | #endif 764 | 765 | for (id = N; id--;) { 766 | Image -> GetPoint(id,r); 767 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 768 | if (Image->GetScalarComponentAsDouble(x,y,z,0)) { 769 | if (GetNumberOfNeighborsWithoutValue(Image,x,y,z,0) != 2) { 770 | Junctions.insert(Junctions.begin(),id); 771 | Volume -> SetTuple1(id,junction_label); 772 | junction_label++; 773 | } 774 | } 775 | } 776 | Volume -> Modified(); 777 | 778 | if (!Junctions.size()) { 779 | printf("Z-stack seems to be empty. Aborting...\n"); 780 | return 0; 781 | } 782 | 783 | #ifdef DEBUG 784 | printf("\t#Junctions before merging = %ld\n",Junctions.size()); 785 | #endif 786 | 787 | // MERGING: During the merging process, voxels belonging to 788 | // the same junction are merged together forming nodes. 789 | while (JunctionsMerge(Junctions,Image,Volume)); 790 | 791 | // Listing all nodes label we have until this point 792 | std::list Labels; 793 | std::list::iterator itLabel; 794 | for (itId=Junctions.begin(); itId!=Junctions.end(); itId++) { 795 | Labels.insert(Labels.begin(),(long int)Volume->GetTuple1(*itId)); 796 | } 797 | 798 | // UNIQUE of labels 799 | Labels.sort(); // must sort first 800 | Labels.unique(); 801 | long int NumberOfNodes = Labels.size(); 802 | 803 | #ifdef DEBUG 804 | printf("\t#Junctions (nodes) after merging = %ld\n",NumberOfNodes); 805 | #endif 806 | 807 | // COORDINATES of nodes 808 | // Vectors with static size to make the average calculation easy. 809 | long int node; 810 | double *X = new double[NumberOfNodes]; //Vector for x-coordinate 811 | double *Y = new double[NumberOfNodes]; //Vector for y-coordinate 812 | double *Z = new double[NumberOfNodes]; //Vector for z-coordinate 813 | double *S = new double[NumberOfNodes]; //Vector for junctions size 814 | int *K = new int[NumberOfNodes]; //Vector for junctions degree 815 | for (node = 0; node < NumberOfNodes; node++) { 816 | K[node] = 0; 817 | X[node] = Y[node] = Z[node] = S[node] = 0.0; 818 | } 819 | 820 | for (itId=Junctions.begin(); itId!=Junctions.end(); itId++) { 821 | junction_label = (long int)Volume -> GetTuple1(*itId); 822 | itLabel = std::find(Labels.begin(),Labels.end(),junction_label); 823 | node = (long int)std::distance(Labels.begin(),itLabel); 824 | Volume -> SetTuple1(*itId,node+1); 825 | Image -> GetPoint(*itId,r); 826 | X[node] += r[0]; 827 | Y[node] += r[1]; 828 | Z[node] += r[2]; 829 | S[node] ++; 830 | } 831 | Volume -> Modified(); 832 | 833 | // Dynamic list to make easy the insertion of the coordinates 834 | // of remaining voxels detected during the edge tracking process. 835 | std::list PointsListX; 836 | std::list PointsListY; 837 | std::list PointsListZ; 838 | for (node=0;node EdgeArray = vtkSmartPointer::New(); 848 | 849 | bool _should_add; 850 | itId = Junctions.begin(); 851 | long int voxel_label = NumberOfNodes; 852 | long int junction_label_left, junction_label_right; 853 | long int source_node, target_node; 854 | while (itId != Junctions.end()) { 855 | Image -> GetPoint(*itId,r); 856 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 857 | if (GetNumberOfNeighborsWithValue(Image,Volume,x,y,z,-1)) { 858 | _should_add = true; 859 | 860 | //Tracking new edge 861 | std::list Edge = GetEdgeStartingAt(x,y,z,Image,Volume); 862 | 863 | //Identifying junctions on left side of the edge 864 | source_node = Volume -> GetTuple1(*itId); 865 | 866 | //Identifying junctions on right side of the edge 867 | Image -> GetPoint(Edge.back(),r); 868 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 869 | target_node = Volume -> GetTuple1(GetOneNeighborWithoutValue(x,y,z,Image,Volume,source_node)); 870 | 871 | // When target_node is equal to 0 at this point, we are 872 | // dealing with loops. These loops can be real loops or noise 873 | // loops of very small length. This very short loops are often 874 | // related to noise around junctions or 1-voxel holes in the 875 | // data. 876 | // @@PARAMETER: Minimum loop length (in voxels) 877 | if (!target_node) { 878 | target_node = source_node; 879 | if (Edge.size() < 3) _should_add = false; 880 | } 881 | 882 | if (_should_add) { 883 | // Creating new cell for this edge 884 | EdgeArray -> InsertNextCell(Edge.size()+2); 885 | // Adding node 1 886 | EdgeArray -> InsertCellPoint(source_node-1); 887 | // Addint the new points coordinates as well as the edge itself 888 | for (std::list::iterator itIde=Edge.begin(); itIde!=Edge.end(); itIde++) { 889 | Image -> GetPoint(*itIde,r); 890 | PointsListX.insert(PointsListX.end(),r[0]); 891 | PointsListY.insert(PointsListY.end(),r[1]); 892 | PointsListZ.insert(PointsListZ.end(),r[2]); 893 | EdgeArray -> InsertCellPoint(voxel_label); 894 | voxel_label++; 895 | } 896 | // Adding node 2 897 | EdgeArray -> InsertCellPoint(target_node-1); 898 | // Updating nodes degree 899 | K[source_node-1]++; 900 | K[target_node-1]++; 901 | } 902 | 903 | } else { 904 | Junctions.erase(itId++); 905 | } 906 | } 907 | 908 | vtkSmartPointer Points = vtkSmartPointer::New(); 909 | Points -> SetNumberOfPoints(PointsListX.size()); 910 | 911 | #ifdef DEBUG 912 | printf("#Points in vtkPoints = %lld\n",Points -> GetNumberOfPoints()); 913 | #endif 914 | 915 | voxel_label = 0; 916 | std::list::iterator itX = PointsListX.begin(); 917 | std::list::iterator itY = PointsListY.begin(); 918 | std::list::iterator itZ = PointsListZ.begin(); 919 | while (itX != PointsListX.end()) { 920 | Points -> SetPoint(voxel_label,*itX,*itY,*itZ); 921 | itX++; itY++; itZ++; 922 | voxel_label++; 923 | } 924 | Points -> Modified(); 925 | 926 | PointsListX.clear(); 927 | PointsListY.clear(); 928 | PointsListZ.clear(); 929 | 930 | // Creating raw polyData 931 | vtkSmartPointer PolyData = vtkPolyData::New(); 932 | PolyData -> SetPoints(Points); 933 | PolyData -> SetLines(EdgeArray); 934 | PolyData -> Modified(); 935 | PolyData -> BuildLinks(); 936 | 937 | long int nedges_before_filtering = PolyData -> GetNumberOfCells(); 938 | 939 | #ifdef DEBUG 940 | printf("\t#Edges before filtering = %ld\n",nedges_before_filtering); 941 | SavePolyData(PolyData,(mitoObject->FileName+"_skeleton_raw.vtk").c_str()); 942 | #endif 943 | 944 | // PolyData filtering by removing degree-2 nodes. These nodes rise 945 | // for two reasons: 1) very short edges that are not detected, 946 | // although the bifurcation is detected. 2) Short loops that were 947 | // removed. 948 | 949 | #ifdef DEBUG 950 | printf("\t#Filtering...\n"); 951 | #endif 952 | 953 | while ( 954 | MergeEdgesOfDegree2Nodes(PolyData,nedges_before_filtering,K) 955 | ); 956 | 957 | #ifdef DEBUG 958 | printf("\t#Creating new ids...\n"); 959 | #endif 960 | 961 | //Creating a list with final Ids of nodes after degree-2 nodes 962 | //deletetion. 963 | long int valid_id = 0; 964 | long int *ValidId = new long int[NumberOfNodes]; 965 | for (node = 0; node < NumberOfNodes; node++) { 966 | if (K[node] > 0) { 967 | //printf("%d] - k = %d\n",(int)node,(int)K[node]); 968 | ValidId[node] = valid_id; 969 | valid_id++; 970 | } else { 971 | ValidId[node] = -1; 972 | } 973 | } 974 | 975 | // for (node = 0; node < NumberOfNodes; node++) { 976 | // printf("%d\t%d\n",(int)node,(int)ValidId[node]); 977 | // } 978 | 979 | //Creating an array called nodes used to mark true nodes 980 | 981 | vtkSmartPointer TrueNode = vtkSmartPointer::New(); 982 | TrueNode -> SetNumberOfComponents(1); 983 | TrueNode -> SetNumberOfTuples(PolyData->GetNumberOfPoints()); 984 | TrueNode -> FillComponent(0,-1); 985 | TrueNode -> SetName("Nodes"); 986 | 987 | valid_id = 0; 988 | for (node = 0; node < NumberOfNodes; node++) { 989 | if (ValidId[node]>-1) { 990 | TrueNode -> SetTuple1(node,valid_id); 991 | valid_id++; 992 | } 993 | } 994 | 995 | TrueNode -> Modified(); 996 | 997 | PolyData -> GetPointData() -> AddArray(TrueNode); 998 | 999 | // Export graph files 1000 | 1001 | #ifdef DEBUG 1002 | printf("\t#Edges after filtering = %lld\n",PolyData->GetNumberOfCells()); 1003 | printf("Skeletonization done!\n"); 1004 | #endif 1005 | 1006 | SmoothEdgesCoordinates(PolyData,3); 1007 | 1008 | if (_export_graph_files) ExportGraphFiles(PolyData,NumberOfNodes,ValidId,mitoObject->FileName.c_str()); 1009 | 1010 | ExportNodes(PolyData,NumberOfNodes,ValidId,mitoObject); 1011 | 1012 | return PolyData; 1013 | } 1014 | 1015 | bool MergeEdgesOfDegree2Nodes(vtkSmartPointer PolyData, long int nedges_before_filtering, int *K) { 1016 | 1017 | // Given this edge: (source) o---->----o (target), it's necessary 1018 | // to check whether either source or target are nodes of degree 2. 1019 | 1020 | std::list Merg; 1021 | std::list::iterator itId; 1022 | 1023 | vtkCell *Edge, *NeighEdge; 1024 | long int i, source, target, edge, edge_length, neigh_edge, neigh_edge_length; 1025 | bool _common_source, _merged = false; 1026 | 1027 | for (edge = 0; edge < PolyData -> GetNumberOfCells(); edge++) { 1028 | 1029 | Edge = PolyData -> GetCell(edge); 1030 | edge_length = Edge -> GetNumberOfPoints(); 1031 | source = (long int)Edge -> GetPointId(0); 1032 | target = (long int)Edge -> GetPointId(Edge->GetNumberOfPoints()-1); 1033 | 1034 | if (K[source]==2 && source!=target) { 1035 | 1036 | // [ neigh | original ] 1037 | // o----?----o---->-----o 1038 | // s t 1039 | 1040 | _merged = true; 1041 | neigh_edge = GetOneAdjacentEdge(PolyData,edge,source,&_common_source); 1042 | NeighEdge = PolyData -> GetCell((vtkIdType)neigh_edge); 1043 | neigh_edge_length = NeighEdge -> GetNumberOfPoints(); 1044 | 1045 | if (_common_source) {// o----<----o---->----o 1046 | for (i=0;iGetCell(edge)->GetPointId(i)); 1048 | for (i=1;iGetCell(neigh_edge)->GetPointId(i)); 1050 | } else { // o---->----o---->----o 1051 | for (i=0;iGetCell(neigh_edge)->GetPointId(i)); 1053 | for (i=1;iGetCell(edge)->GetPointId(i)); 1055 | } 1056 | K[source] = -1; // Tagged as not valid node 1057 | 1058 | } else if (K[target]==2 && source!=target) { 1059 | 1060 | // [ original | neigh ] 1061 | // o---->-----o----?----o 1062 | // s t 1063 | 1064 | _merged = true; 1065 | neigh_edge = GetOneAdjacentEdge(PolyData,edge,target,&_common_source); 1066 | NeighEdge = PolyData -> GetCell((vtkIdType)neigh_edge); 1067 | neigh_edge_length = NeighEdge -> GetNumberOfPoints(); 1068 | 1069 | if (_common_source) {// o---->----o---->----o 1070 | for (i=0;iGetCell(edge)->GetPointId(i)); 1072 | for (i=1;iGetCell(neigh_edge)->GetPointId(i)); 1074 | } else {// o---->----o----<----o 1075 | for (i=0;iGetCell(edge)->GetPointId(i)); 1077 | for (i=neigh_edge_length-1;i--;) 1078 | Merg.insert(Merg.end(),PolyData->GetCell(neigh_edge)->GetPointId(i)); 1079 | } 1080 | K[target] = -1; // Tagged as not valid node 1081 | } 1082 | 1083 | if (_merged) { 1084 | i = 0; 1085 | // Removing the two pieces that were merged together 1086 | PolyData -> BuildLinks(); 1087 | PolyData -> DeleteCell(edge); 1088 | PolyData -> DeleteCell(neigh_edge); 1089 | PolyData -> RemoveDeletedCells(); 1090 | // Adding the new "merged" edge 1091 | std::vector IdList(Merg.size()); 1092 | for (itId=Merg.begin(); itId!=Merg.end(); itId++) { 1093 | IdList[i] = *itId; 1094 | i++; 1095 | } 1096 | PolyData -> InsertNextCell(VTK_POLY_LINE,Merg.size(),IdList.data()); 1097 | Merg.clear(); 1098 | return true; 1099 | } 1100 | 1101 | } 1102 | return false; 1103 | } 1104 | 1105 | long int LabelConnectedComponents(vtkSmartPointer ImageData, vtkSmartPointer Volume, std::vector &CSz, int ngbh, double threshold) { 1106 | 1107 | #ifdef DEBUG 1108 | printf("\tCalculating connected components...\n"); 1109 | #endif 1110 | 1111 | int *Dim = ImageData -> GetDimensions(); 1112 | 1113 | vtkIdType i, s, ido, id; 1114 | 1115 | int x, y, z; 1116 | double v, r[3]; 1117 | bool find = true; 1118 | long long int ro[3]; 1119 | long int scluster, label; 1120 | ro[0] = Dim[0] * Dim[1] * Dim[2]; 1121 | ro[1] = Dim[0] * Dim[1]; 1122 | 1123 | vtkSmartPointer CurrA = vtkSmartPointer::New(); 1124 | vtkSmartPointer NextA = vtkSmartPointer::New(); 1125 | 1126 | Volume -> CopyComponent(0,ImageData->GetPointData()->GetScalars(),0); 1127 | Volume -> Modified(); 1128 | 1129 | label = 0; 1130 | while (find) { 1131 | for (s = 0; s < CurrA->GetNumberOfIds(); s++) { 1132 | ido = CurrA -> GetId(s); 1133 | ImageData -> GetPoint(ido,r); 1134 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 1135 | for (i = 0; i < ngbh; i++) { 1136 | id = ImageData -> FindPoint(x+ssdx_sort[i],y+ssdy_sort[i],z+ssdz_sort[i]); 1137 | v = Volume -> GetTuple1(id); 1138 | if (v > threshold) { 1139 | NextA -> InsertNextId(id); 1140 | Volume -> SetTuple1(id,-label); 1141 | scluster++; 1142 | } 1143 | } 1144 | } 1145 | if (!NextA->GetNumberOfIds()) { 1146 | find = false; 1147 | for (id=ro[0]; id--;) { 1148 | v = Volume -> GetTuple1(id); 1149 | if (v > threshold) { 1150 | find = true; 1151 | ro[0] = id; 1152 | break; 1153 | } 1154 | } 1155 | if (label) { 1156 | CSz.push_back(scluster); 1157 | } 1158 | if (find) { 1159 | label++; 1160 | scluster = 1; 1161 | Volume -> SetTuple1(id,-label); 1162 | CurrA -> InsertNextId(id); 1163 | } 1164 | } else { 1165 | CurrA -> Reset(); 1166 | CurrA -> DeepCopy(NextA); 1167 | NextA -> Reset(); 1168 | } 1169 | } 1170 | 1171 | #ifdef DEBUG 1172 | printf("\tNumber of detected components: %ld\n",(long int)CSz.size()); 1173 | #endif 1174 | 1175 | //return (long int)CSz->GetNumberOfTuples(); 1176 | return (long int)CSz.size(); 1177 | } 1178 | -------------------------------------------------------------------------------- /MitoThinning.h: -------------------------------------------------------------------------------- 1 | #ifndef MITOTHINNING_H 2 | #define MITOTHINNING_H 3 | 4 | #include "includes.h" 5 | 6 | extern double _rad; 7 | extern double _dxy, _dz; 8 | extern bool _export_graph_files; 9 | extern bool _scale_polydata_before_save; 10 | extern bool _export_nodes_label; 11 | extern double _div_threshold; 12 | extern bool _improve_skeleton_quality; 13 | 14 | extern int ssdx_sort[26]; 15 | extern int ssdy_sort[26]; 16 | extern int ssdz_sort[26]; 17 | 18 | // Thinning algorithm based on the paper: "A 3D 6-subinteration thinning 19 | // algorithm for extracting medial lines", by Kálman Palágyi and Attila 20 | // Kuba. 21 | vtkSmartPointer Thinning3D(vtkSmartPointer ImageData, _mitoObject *mitoObject); 22 | 23 | // Routine used to save an ImageData 24 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample = false); 25 | 26 | // Routine used to save a PolyData 27 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[]); 28 | 29 | // Calculate the length of a given edge. 30 | double GetEdgeLength(vtkIdType edge, vtkSmartPointer PolyData); 31 | 32 | // Label connected components in Image. Results are stored 33 | // in Volume as negative labels. The routine returns the total 34 | // number of connected components. 35 | long int LabelConnectedComponents(vtkSmartPointer ImageData, vtkSmartPointer Volume, std::vector &CSz, int ngbh, double threshold); 36 | 37 | // Routine to delete all voxels located at boundaries of the 38 | // image volume. Otherwise the algorithm will have problems 39 | // checking the 3D neighborhood of those voxels. 40 | void CleanImageBoundaries(vtkSmartPointer ImageData); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | MitoGraph is a fully automated image processing method and software dedicated to calculating the three-dimensional morphology of mitochondria in live cells. MitoGraph is currently optimized and validated only for quantifying the volume and topology of tubular mitochondrial networks in budding yeast [1,2]. However, MitoGraph can also be applied to mitochondria in other cell types and possibly other intracellular (or tissue) structures, with proper validation. MitoGraph is continuously being updated. Please contact us if you have questions that go beyond those discussed in [1,2] or any request that would make MitoGraph a better tool for your research. 6 | 7 | Matheus Viana - vianamp@gmail.com - 06.25.2024 8 | 9 | ### v3.1 Release 10 | 11 | ✓ MitoGraph is now compatible to Windows 10 12 | 13 | ✓ Extra flag `-export_image_binary` to export the segmented version of the input 14 | 15 | ### v3.0 Release 16 | 17 | ✓ Adaptive threshold 18 | 19 | ✓ Support binary and VTK input 20 | 21 | ✓ Support 2D image data 22 | 23 | ✓ Export skeleton coordinates as text file 24 | 25 | ✓ Save skeleton with information of mitochondrial tubules width, pixel intensity, edge length and nodes position 26 | 27 | ### v2.1 Release 28 | 29 | ✓ Extra flag that lets you use __R__ to perform basic analysis of MitoGraph output 30 | 31 | --- 32 | 33 | ### How to Install 34 | 35 | Please follow the steps bellow to install MitoGraph. 36 | 37 | 1. Download the latest version of MitoGraph available for Mac OSX 10.10 or later 38 | 39 | 2. Create a folder in your Desktop and name it MitoGraph 40 | 41 | 3. Move the downloaded file to the folder MitoGraph in your and unzip it 42 | 43 | --- 44 | 45 | ### Testing Data, ImageJ Macros and Other Tools 46 | 47 | Before running MitoGraph on your own dataset, you may want to check the tools we made available for preparing your data and our test datasets. 48 | 49 |

50 | 51 |

52 | 53 | * MitoGraph Tools: in this repository you will find an example dataset to test MitoGraph on. There is also two ImageJ scripts that help you to prepare your data to make them similar to our test dataset. 54 | 55 | --- 56 | 57 | ### How to Run MitoGraph 58 | 59 | Download the test dataset mentioned in the previous section and unzip the downloaded file in your Desktop. Type the following command in the terminal of your Mac OS (spotlight + terminal) 60 | 61 | `cd ~/Desktop/MitoGraph` 62 | 63 | `./MitoGraph -xy 0.056 -z 0.2 -path ~/Desktop/MitoGraphTools-1.0` 64 | 65 | The flag `-xy` specifies the pixel size in microns and the flag `-z` specifies the z-spacing also in microns of your images. Finally, the flag `-path` indicates the folder that contains the images you want to analyze. 66 | 67 | #### Optional Flags 68 | 69 | `-scales a b c` where a, b and c are numeric values specifying the initial, final and total number of scales which should be used by MitoGraph [1]. For example: `-scales 1.5 2.0 6`. Default values are a=1.0, b=1.5 and c=6. 70 | 71 | `-threshold a` where a is numeric value in the range [0,1] for the post-divergence threshold. For example: `-threshold 0.1`. Default value is a=0.1667. 72 | 73 | `-adaptive a` where a is a numeric integer value specifying that the input image should be split into a x a blocks before the segmentation. This is useful for images with high variablity of pixel intensity. 74 | 75 | `-binary`: indicates that the input is a binary image. 76 | 77 | `-vtk`: indicates that the input data is of __VTK Imagedata__ type instead of TIFF. 78 | 79 | `-labels_off`: turns off the labels of nodes in the output file __filename_nodes.vtk__. 80 | 81 | `-analyze`: uses R to do a per connected component analysis of MitoGraph output. This flag requires __R__ and its package __igraph__ to be installed in your system. 82 | 83 | --- 84 | 85 | ### MitoGraph Outputs 86 | 87 | The output of MitoGraph will be saved in the directory specified with `-path`. 88 | 89 | **Single files:** 90 | 91 | * __mitograph.config__ - Stores the parameters used to run MitoGraph and the date and time when the analysis was complete. 92 | 93 | **Text files that can be open in any Text Editor (one file per sample):** 94 | 95 | * __filename.gnet__ - Connection list of type `node_i` `node_j` of the graph that represents the mitochondria. First line of this file gives the total number of nodes. 96 | * __filename.coo__ - Coordinates xyz of nodes in the graph. 97 | * __filename.mitograph__ - Mitochondrial attributes: volume from voxels, average width (µm), std width (µm), total length (µm) and volume from length (µm3). This file also shows per component statistics when the flag `-analyze` is used. 98 | * __filename.txt__ - Coordinates of all the points along the mitochondrial skeleton as well as the local width (µm) and original pixel intensity. 99 | * __filename.cc__ - Connected component which each node belong to and the component volume (µm3). Only when the flag `-analyze` is used. 100 | 101 | **Image files (one file per sample):** 102 | 103 | * __filename.png__ - Max projection of mitochondria after MitoGraph binarization. Should be used for fast assessment of MitoGraph segmentation result. 104 | 105 | **VTK files that can be open using Paraview [3] (one file per sample):** 106 | 107 | * __filename_Nodes.vtk__ - Nodes of the graph that represents the mitochondria and their labels. 108 | * __filename_skeleton.vtk__ - Mitochondrial skeleton. This file contains information about mitochondrial tubule width, pixel intensity, edge length and nodes position that can be viewd in Paraview by setting the coloring mode. 109 | * __filename_mitosurface.vtk__ - Mitochondrial surface. 110 | 111 | --- 112 | 113 | ### Contributions to MitoGraph 114 | 115 | * With help of Hill Lab, we also provide an example dataset of mitochondria in mammalian cells and R scripts that will help you to analyze the data generated by MitoGraph. Please, check this out in MitoGraph-Contrib-RScripts. 116 | 117 | --- 118 | 119 | ### References 120 | 121 | [1] - Matheus P Viana, Swee Lim, Susanne M Rafelski, Quantifying Mitochondrial Content in Living Cells (2015), Biophysical Methods in Cell Biology, (125) - 77-93 (http://www.sciencedirect.com/science/article/pii/S0091679X14000041) 122 | 123 | [2] - Viana, M.P., Brown, A.I., Mueller, I.A., Goul, C., Koslover, E.F. and Rafelski, S.M., 2020. Mitochondrial Fission and Fusion Dynamics Generate Efficient, Robust, and Evenly Distributed Network Topologies in Budding Yeast Cells. Cell Systems (https://www.cell.com/cell-systems/fulltext/S2405-4712(20)30035-1) 124 | 125 | [3] - https://www.paraview.org/ 126 | -------------------------------------------------------------------------------- /ThirdPartLicenses.txt: -------------------------------------------------------------------------------- 1 | Vizualization Toolkit - VTK 2 | --------------------------- 3 | 4 | Copyright (c) 1993-2008 Ken Martin, Will Schroeder, Bill Lorensen 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names 18 | of any contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /data/MitoGraphTest001.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/data/MitoGraphTest001.tif -------------------------------------------------------------------------------- /doc/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /doc/mitograph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/doc/mitograph.png -------------------------------------------------------------------------------- /includes.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifdef _WIN32 8 | #include "includes/dirent.h" 9 | #else 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #ifndef _MITOGRAPH_ENV_VARS 56 | 57 | #define _MITOGRAPH_ENV_VARS 58 | 59 | struct attribute { std::string name; double value; }; 60 | 61 | struct _mitoObject { 62 | std::string Type; 63 | std::string Folder; 64 | std::string FileName; 65 | bool _analyze; 66 | bool _binary_input; 67 | double Ox; 68 | double Oy; 69 | double Oz; 70 | double _sigmai; 71 | double _sigmaf; 72 | double _dsigma; 73 | int _nsigma; 74 | bool _adaptive_threshold; 75 | int _nblks; 76 | 77 | std::vector attributes; 78 | }; 79 | 80 | #endif 81 | 82 | // #define DEBUG 83 | #include "ssThinning.h" 84 | #include "MitoThinning.h" 85 | -------------------------------------------------------------------------------- /includes/dirent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Dirent interface for Microsoft Visual Studio 3 | * 4 | * Copyright (C) 1998-2019 Toni Ronkko 5 | * This file is part of dirent. Dirent may be freely distributed 6 | * under the MIT license. For all details and documentation, see 7 | * https://github.com/tronkko/dirent 8 | */ 9 | #ifndef DIRENT_H 10 | #define DIRENT_H 11 | 12 | /* Hide warnings about unreferenced local functions */ 13 | #if defined(__clang__) 14 | # pragma clang diagnostic ignored "-Wunused-function" 15 | #elif defined(_MSC_VER) 16 | # pragma warning(disable:4505) 17 | #elif defined(__GNUC__) 18 | # pragma GCC diagnostic ignored "-Wunused-function" 19 | #endif 20 | 21 | /* 22 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with 23 | * Windows Sockets 2.0. 24 | */ 25 | #ifndef WIN32_LEAN_AND_MEAN 26 | # define WIN32_LEAN_AND_MEAN 27 | #endif 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | /* Indicates that d_type field is available in dirent structure */ 42 | #define _DIRENT_HAVE_D_TYPE 43 | 44 | /* Indicates that d_namlen field is available in dirent structure */ 45 | #define _DIRENT_HAVE_D_NAMLEN 46 | 47 | /* Entries missing from MSVC 6.0 */ 48 | #if !defined(FILE_ATTRIBUTE_DEVICE) 49 | # define FILE_ATTRIBUTE_DEVICE 0x40 50 | #endif 51 | 52 | /* File type and permission flags for stat(), general mask */ 53 | #if !defined(S_IFMT) 54 | # define S_IFMT _S_IFMT 55 | #endif 56 | 57 | /* Directory bit */ 58 | #if !defined(S_IFDIR) 59 | # define S_IFDIR _S_IFDIR 60 | #endif 61 | 62 | /* Character device bit */ 63 | #if !defined(S_IFCHR) 64 | # define S_IFCHR _S_IFCHR 65 | #endif 66 | 67 | /* Pipe bit */ 68 | #if !defined(S_IFFIFO) 69 | # define S_IFFIFO _S_IFFIFO 70 | #endif 71 | 72 | /* Regular file bit */ 73 | #if !defined(S_IFREG) 74 | # define S_IFREG _S_IFREG 75 | #endif 76 | 77 | /* Read permission */ 78 | #if !defined(S_IREAD) 79 | # define S_IREAD _S_IREAD 80 | #endif 81 | 82 | /* Write permission */ 83 | #if !defined(S_IWRITE) 84 | # define S_IWRITE _S_IWRITE 85 | #endif 86 | 87 | /* Execute permission */ 88 | #if !defined(S_IEXEC) 89 | # define S_IEXEC _S_IEXEC 90 | #endif 91 | 92 | /* Pipe */ 93 | #if !defined(S_IFIFO) 94 | # define S_IFIFO _S_IFIFO 95 | #endif 96 | 97 | /* Block device */ 98 | #if !defined(S_IFBLK) 99 | # define S_IFBLK 0 100 | #endif 101 | 102 | /* 103 | * Symbolic link. Be ware that S_IFLNK value and S_ISLNK() macro are only 104 | * usable with dirent - they do not work with stat() function call! 105 | */ 106 | #if !defined(S_IFLNK) 107 | # define S_IFLNK (_S_IFDIR | _S_IFREG) 108 | #endif 109 | 110 | /* Socket */ 111 | #if !defined(S_IFSOCK) 112 | # define S_IFSOCK 0 113 | #endif 114 | 115 | /* Read user permission */ 116 | #if !defined(S_IRUSR) 117 | # define S_IRUSR S_IREAD 118 | #endif 119 | 120 | /* Write user permission */ 121 | #if !defined(S_IWUSR) 122 | # define S_IWUSR S_IWRITE 123 | #endif 124 | 125 | /* Execute user permission */ 126 | #if !defined(S_IXUSR) 127 | # define S_IXUSR 0 128 | #endif 129 | 130 | /* User full permissions */ 131 | #if !defined(S_IRWXU) 132 | # define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) 133 | #endif 134 | 135 | /* Read group permission */ 136 | #if !defined(S_IRGRP) 137 | # define S_IRGRP 0 138 | #endif 139 | 140 | /* Write group permission */ 141 | #if !defined(S_IWGRP) 142 | # define S_IWGRP 0 143 | #endif 144 | 145 | /* Execute group permission */ 146 | #if !defined(S_IXGRP) 147 | # define S_IXGRP 0 148 | #endif 149 | 150 | /* Group full permissions */ 151 | #if !defined(S_IRWXG) 152 | # define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) 153 | #endif 154 | 155 | /* Read others permission */ 156 | #if !defined(S_IROTH) 157 | # define S_IROTH 0 158 | #endif 159 | 160 | /* Write others permission */ 161 | #if !defined(S_IWOTH) 162 | # define S_IWOTH 0 163 | #endif 164 | 165 | /* Execute others permission */ 166 | #if !defined(S_IXOTH) 167 | # define S_IXOTH 0 168 | #endif 169 | 170 | /* Other full permissions */ 171 | #if !defined(S_IRWXO) 172 | # define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) 173 | #endif 174 | 175 | /* Maximum length of file name */ 176 | #if !defined(PATH_MAX) 177 | # define PATH_MAX MAX_PATH 178 | #endif 179 | #if !defined(FILENAME_MAX) 180 | # define FILENAME_MAX MAX_PATH 181 | #endif 182 | #if !defined(NAME_MAX) 183 | # define NAME_MAX FILENAME_MAX 184 | #endif 185 | 186 | /* File type flags for d_type */ 187 | #define DT_UNKNOWN 0 188 | #define DT_REG S_IFREG 189 | #define DT_DIR S_IFDIR 190 | #define DT_FIFO S_IFIFO 191 | #define DT_SOCK S_IFSOCK 192 | #define DT_CHR S_IFCHR 193 | #define DT_BLK S_IFBLK 194 | #define DT_LNK S_IFLNK 195 | 196 | /* Macros for converting between st_mode and d_type */ 197 | #define IFTODT(mode) ((mode) & S_IFMT) 198 | #define DTTOIF(type) (type) 199 | 200 | /* 201 | * File type macros. Note that block devices and sockets cannot be 202 | * distinguished on Windows, and the macros S_ISBLK and S_ISSOCK are only 203 | * defined for compatibility. These macros should always return false on 204 | * Windows. 205 | */ 206 | #if !defined(S_ISFIFO) 207 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) 208 | #endif 209 | #if !defined(S_ISDIR) 210 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 211 | #endif 212 | #if !defined(S_ISREG) 213 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 214 | #endif 215 | #if !defined(S_ISLNK) 216 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 217 | #endif 218 | #if !defined(S_ISSOCK) 219 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 220 | #endif 221 | #if !defined(S_ISCHR) 222 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 223 | #endif 224 | #if !defined(S_ISBLK) 225 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 226 | #endif 227 | 228 | /* Return the exact length of the file name without zero terminator */ 229 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) 230 | 231 | /* Return the maximum size of a file name */ 232 | #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) 233 | 234 | 235 | #ifdef __cplusplus 236 | extern "C" { 237 | #endif 238 | 239 | 240 | /* Wide-character version */ 241 | struct _wdirent { 242 | /* Always zero */ 243 | long d_ino; 244 | 245 | /* Position of next file in a directory stream */ 246 | long d_off; 247 | 248 | /* Structure size */ 249 | unsigned short d_reclen; 250 | 251 | /* Length of name without \0 */ 252 | size_t d_namlen; 253 | 254 | /* File type */ 255 | int d_type; 256 | 257 | /* File name */ 258 | wchar_t d_name[PATH_MAX+1]; 259 | }; 260 | typedef struct _wdirent _wdirent; 261 | 262 | struct _WDIR { 263 | /* Current directory entry */ 264 | struct _wdirent ent; 265 | 266 | /* Private file data */ 267 | WIN32_FIND_DATAW data; 268 | 269 | /* True if data is valid */ 270 | int cached; 271 | 272 | /* True if next entry is invalid */ 273 | int invalid; 274 | 275 | /* Win32 search handle */ 276 | HANDLE handle; 277 | 278 | /* Initial directory name */ 279 | wchar_t *patt; 280 | }; 281 | typedef struct _WDIR _WDIR; 282 | 283 | /* Multi-byte character version */ 284 | struct dirent { 285 | /* Always zero */ 286 | long d_ino; 287 | 288 | /* Position of next file in a directory stream */ 289 | long d_off; 290 | 291 | /* Structure size */ 292 | unsigned short d_reclen; 293 | 294 | /* Length of name without \0 */ 295 | size_t d_namlen; 296 | 297 | /* File type */ 298 | int d_type; 299 | 300 | /* File name */ 301 | char d_name[PATH_MAX+1]; 302 | }; 303 | typedef struct dirent dirent; 304 | 305 | struct DIR { 306 | struct dirent ent; 307 | struct _WDIR *wdirp; 308 | }; 309 | typedef struct DIR DIR; 310 | 311 | 312 | /* Dirent functions */ 313 | static DIR *opendir(const char *dirname); 314 | static _WDIR *_wopendir(const wchar_t *dirname); 315 | 316 | static struct dirent *readdir(DIR *dirp); 317 | static struct _wdirent *_wreaddir(_WDIR *dirp); 318 | 319 | static int readdir_r( 320 | DIR *dirp, struct dirent *entry, struct dirent **result); 321 | static int _wreaddir_r( 322 | _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); 323 | 324 | static int closedir(DIR *dirp); 325 | static int _wclosedir(_WDIR *dirp); 326 | 327 | static void rewinddir(DIR *dirp); 328 | static void _wrewinddir(_WDIR *dirp); 329 | 330 | static long telldir(DIR *dirp); 331 | static long _wtelldir(_WDIR *dirp); 332 | 333 | static void seekdir(DIR *dirp, long loc); 334 | static void _wseekdir(_WDIR *dirp, long loc); 335 | 336 | static int scandir(const char *dirname, struct dirent ***namelist, 337 | int (*filter)(const struct dirent*), 338 | int (*compare)(const struct dirent**, const struct dirent**)); 339 | 340 | static int alphasort(const struct dirent **a, const struct dirent **b); 341 | 342 | static int versionsort(const struct dirent **a, const struct dirent **b); 343 | 344 | static int strverscmp(const char *a, const char *b); 345 | 346 | /* For compatibility with Symbian */ 347 | #define wdirent _wdirent 348 | #define WDIR _WDIR 349 | #define wopendir _wopendir 350 | #define wreaddir _wreaddir 351 | #define wclosedir _wclosedir 352 | #define wrewinddir _wrewinddir 353 | #define wtelldir _wtelldir 354 | #define wseekdir _wseekdir 355 | 356 | /* Compatibility with older Microsoft compilers and non-Microsoft compilers */ 357 | #if !defined(_MSC_VER) || _MSC_VER < 1400 358 | # define wcstombs_s dirent_wcstombs_s 359 | # define mbstowcs_s dirent_mbstowcs_s 360 | #endif 361 | 362 | /* Optimize dirent_set_errno() away on modern Microsoft compilers */ 363 | #if defined(_MSC_VER) && _MSC_VER >= 1400 364 | # define dirent_set_errno _set_errno 365 | #endif 366 | 367 | 368 | /* Internal utility functions */ 369 | static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); 370 | static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); 371 | static long dirent_hash(WIN32_FIND_DATAW *datap); 372 | 373 | #if !defined(_MSC_VER) || _MSC_VER < 1400 374 | static int dirent_mbstowcs_s( 375 | size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, 376 | const char *mbstr, size_t count); 377 | #endif 378 | 379 | #if !defined(_MSC_VER) || _MSC_VER < 1400 380 | static int dirent_wcstombs_s( 381 | size_t *pReturnValue, char *mbstr, size_t sizeInBytes, 382 | const wchar_t *wcstr, size_t count); 383 | #endif 384 | 385 | #if !defined(_MSC_VER) || _MSC_VER < 1400 386 | static void dirent_set_errno(int error); 387 | #endif 388 | 389 | 390 | /* 391 | * Open directory stream DIRNAME for read and return a pointer to the 392 | * internal working area that is used to retrieve individual directory 393 | * entries. 394 | */ 395 | static _WDIR * 396 | _wopendir(const wchar_t *dirname) 397 | { 398 | wchar_t *p; 399 | 400 | /* Must have directory name */ 401 | if (dirname == NULL || dirname[0] == '\0') { 402 | dirent_set_errno(ENOENT); 403 | return NULL; 404 | } 405 | 406 | /* Allocate new _WDIR structure */ 407 | _WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR)); 408 | if (!dirp) 409 | return NULL; 410 | 411 | /* Reset _WDIR structure */ 412 | dirp->handle = INVALID_HANDLE_VALUE; 413 | dirp->patt = NULL; 414 | dirp->cached = 0; 415 | dirp->invalid = 0; 416 | 417 | /* 418 | * Compute the length of full path plus zero terminator 419 | * 420 | * Note that on WinRT there's no way to convert relative paths 421 | * into absolute paths, so just assume it is an absolute path. 422 | */ 423 | #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 424 | /* Desktop */ 425 | DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL); 426 | #else 427 | /* WinRT */ 428 | size_t n = wcslen(dirname); 429 | #endif 430 | 431 | /* Allocate room for absolute directory name and search pattern */ 432 | dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16); 433 | if (dirp->patt == NULL) 434 | goto exit_closedir; 435 | 436 | /* 437 | * Convert relative directory name to an absolute one. This 438 | * allows rewinddir() to function correctly even when current 439 | * working directory is changed between opendir() and rewinddir(). 440 | * 441 | * Note that on WinRT there's no way to convert relative paths 442 | * into absolute paths, so just assume it is an absolute path. 443 | */ 444 | #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 445 | /* Desktop */ 446 | n = GetFullPathNameW(dirname, n, dirp->patt, NULL); 447 | if (n <= 0) 448 | goto exit_closedir; 449 | #else 450 | /* WinRT */ 451 | wcsncpy_s(dirp->patt, n+1, dirname, n); 452 | #endif 453 | 454 | /* Append search pattern \* to the directory name */ 455 | p = dirp->patt + n; 456 | switch (p[-1]) { 457 | case '\\': 458 | case '/': 459 | case ':': 460 | /* Directory ends in path separator, e.g. c:\temp\ */ 461 | /*NOP*/; 462 | break; 463 | 464 | default: 465 | /* Directory name doesn't end in path separator */ 466 | *p++ = '\\'; 467 | } 468 | *p++ = '*'; 469 | *p = '\0'; 470 | 471 | /* Open directory stream and retrieve the first entry */ 472 | if (!dirent_first(dirp)) 473 | goto exit_closedir; 474 | 475 | /* Success */ 476 | return dirp; 477 | 478 | /* Failure */ 479 | exit_closedir: 480 | _wclosedir(dirp); 481 | return NULL; 482 | } 483 | 484 | /* 485 | * Read next directory entry. 486 | * 487 | * Returns pointer to static directory entry which may be overwritten by 488 | * subsequent calls to _wreaddir(). 489 | */ 490 | static struct _wdirent * 491 | _wreaddir(_WDIR *dirp) 492 | { 493 | /* 494 | * Read directory entry to buffer. We can safely ignore the return 495 | * value as entry will be set to NULL in case of error. 496 | */ 497 | struct _wdirent *entry; 498 | (void) _wreaddir_r(dirp, &dirp->ent, &entry); 499 | 500 | /* Return pointer to statically allocated directory entry */ 501 | return entry; 502 | } 503 | 504 | /* 505 | * Read next directory entry. 506 | * 507 | * Returns zero on success. If end of directory stream is reached, then sets 508 | * result to NULL and returns zero. 509 | */ 510 | static int 511 | _wreaddir_r( 512 | _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result) 513 | { 514 | /* Validate directory handle */ 515 | if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) { 516 | dirent_set_errno(EBADF); 517 | *result = NULL; 518 | return -1; 519 | } 520 | 521 | /* Read next directory entry */ 522 | WIN32_FIND_DATAW *datap = dirent_next(dirp); 523 | if (!datap) { 524 | /* Return NULL to indicate end of directory */ 525 | *result = NULL; 526 | return /*OK*/0; 527 | } 528 | 529 | /* 530 | * Copy file name as wide-character string. If the file name is too 531 | * long to fit in to the destination buffer, then truncate file name 532 | * to PATH_MAX characters and zero-terminate the buffer. 533 | */ 534 | size_t i = 0; 535 | while (i < PATH_MAX && datap->cFileName[i] != 0) { 536 | entry->d_name[i] = datap->cFileName[i]; 537 | i++; 538 | } 539 | entry->d_name[i] = 0; 540 | 541 | /* Length of file name excluding zero terminator */ 542 | entry->d_namlen = i; 543 | 544 | /* Determine file type */ 545 | DWORD attr = datap->dwFileAttributes; 546 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) 547 | entry->d_type = DT_CHR; 548 | else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) 549 | entry->d_type = DT_LNK; 550 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) 551 | entry->d_type = DT_DIR; 552 | else 553 | entry->d_type = DT_REG; 554 | 555 | /* Read the next directory entry to cache */ 556 | datap = dirent_next(dirp); 557 | if (datap) { 558 | /* Compute 31-bit hash of the next directory entry */ 559 | entry->d_off = dirent_hash(datap); 560 | 561 | /* Push the next directory entry back to cache */ 562 | dirp->cached = 1; 563 | } else { 564 | /* End of directory stream */ 565 | entry->d_off = (long) ((~0UL) >> 1); 566 | } 567 | 568 | /* Reset other fields */ 569 | entry->d_ino = 0; 570 | entry->d_reclen = sizeof(struct _wdirent); 571 | 572 | /* Set result address */ 573 | *result = entry; 574 | return /*OK*/0; 575 | } 576 | 577 | /* 578 | * Close directory stream opened by opendir() function. This invalidates the 579 | * DIR structure as well as any directory entry read previously by 580 | * _wreaddir(). 581 | */ 582 | static int 583 | _wclosedir(_WDIR *dirp) 584 | { 585 | if (!dirp) { 586 | dirent_set_errno(EBADF); 587 | return /*failure*/-1; 588 | } 589 | 590 | /* 591 | * Release search handle if we have one. Being able to handle 592 | * partially initialized _WDIR structure allows us to use this 593 | * function to handle errors occurring within _wopendir. 594 | */ 595 | if (dirp->handle != INVALID_HANDLE_VALUE) { 596 | FindClose(dirp->handle); 597 | } 598 | 599 | /* 600 | * Release search pattern. Note that we don't need to care if 601 | * dirp->patt is NULL or not: function free is guaranteed to act 602 | * appropriately. 603 | */ 604 | free(dirp->patt); 605 | 606 | /* Release directory structure */ 607 | free(dirp); 608 | return /*success*/0; 609 | } 610 | 611 | /* 612 | * Rewind directory stream such that _wreaddir() returns the very first 613 | * file name again. 614 | */ 615 | static void _wrewinddir(_WDIR* dirp) 616 | { 617 | /* Check directory pointer */ 618 | if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) 619 | return; 620 | 621 | /* Release existing search handle */ 622 | FindClose(dirp->handle); 623 | 624 | /* Open new search handle */ 625 | dirent_first(dirp); 626 | } 627 | 628 | /* Get first directory entry */ 629 | static WIN32_FIND_DATAW * 630 | dirent_first(_WDIR *dirp) 631 | { 632 | /* Open directory and retrieve the first entry */ 633 | dirp->handle = FindFirstFileExW( 634 | dirp->patt, FindExInfoStandard, &dirp->data, 635 | FindExSearchNameMatch, NULL, 0); 636 | if (dirp->handle == INVALID_HANDLE_VALUE) 637 | goto error; 638 | 639 | /* A directory entry is now waiting in memory */ 640 | dirp->cached = 1; 641 | return &dirp->data; 642 | 643 | error: 644 | /* Failed to open directory: no directory entry in memory */ 645 | dirp->cached = 0; 646 | dirp->invalid = 1; 647 | 648 | /* Set error code */ 649 | DWORD errorcode = GetLastError(); 650 | switch (errorcode) { 651 | case ERROR_ACCESS_DENIED: 652 | /* No read access to directory */ 653 | dirent_set_errno(EACCES); 654 | break; 655 | 656 | case ERROR_DIRECTORY: 657 | /* Directory name is invalid */ 658 | dirent_set_errno(ENOTDIR); 659 | break; 660 | 661 | case ERROR_PATH_NOT_FOUND: 662 | default: 663 | /* Cannot find the file */ 664 | dirent_set_errno(ENOENT); 665 | } 666 | return NULL; 667 | } 668 | 669 | /* Get next directory entry */ 670 | static WIN32_FIND_DATAW * 671 | dirent_next(_WDIR *dirp) 672 | { 673 | /* Return NULL if seek position was invalid */ 674 | if (dirp->invalid) 675 | return NULL; 676 | 677 | /* Is the next directory entry already in cache? */ 678 | if (dirp->cached) { 679 | /* Yes, a valid directory entry found in memory */ 680 | dirp->cached = 0; 681 | return &dirp->data; 682 | } 683 | 684 | /* Read the next directory entry from stream */ 685 | if (FindNextFileW(dirp->handle, &dirp->data) == FALSE) { 686 | /* End of directory stream */ 687 | return NULL; 688 | } 689 | 690 | /* Success */ 691 | return &dirp->data; 692 | } 693 | 694 | /* 695 | * Compute 31-bit hash of file name. 696 | * 697 | * See djb2 at http://www.cse.yorku.ca/~oz/hash.html 698 | */ 699 | static long 700 | dirent_hash(WIN32_FIND_DATAW *datap) 701 | { 702 | unsigned long hash = 5381; 703 | unsigned long c; 704 | const wchar_t *p = datap->cFileName; 705 | const wchar_t *e = p + MAX_PATH; 706 | while (p != e && (c = *p++) != 0) { 707 | hash = (hash << 5) + hash + c; 708 | } 709 | 710 | return (long) (hash & ((~0UL) >> 1)); 711 | } 712 | 713 | /* Open directory stream using plain old C-string */ 714 | static DIR *opendir(const char *dirname) 715 | { 716 | /* Must have directory name */ 717 | if (dirname == NULL || dirname[0] == '\0') { 718 | dirent_set_errno(ENOENT); 719 | return NULL; 720 | } 721 | 722 | /* Allocate memory for DIR structure */ 723 | struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR)); 724 | if (!dirp) 725 | return NULL; 726 | 727 | /* Convert directory name to wide-character string */ 728 | wchar_t wname[PATH_MAX + 1]; 729 | size_t n; 730 | int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1); 731 | if (error) 732 | goto exit_failure; 733 | 734 | /* Open directory stream using wide-character name */ 735 | dirp->wdirp = _wopendir(wname); 736 | if (!dirp->wdirp) 737 | goto exit_failure; 738 | 739 | /* Success */ 740 | return dirp; 741 | 742 | /* Failure */ 743 | exit_failure: 744 | free(dirp); 745 | return NULL; 746 | } 747 | 748 | /* Read next directory entry */ 749 | static struct dirent * 750 | readdir(DIR *dirp) 751 | { 752 | /* 753 | * Read directory entry to buffer. We can safely ignore the return 754 | * value as entry will be set to NULL in case of error. 755 | */ 756 | struct dirent *entry; 757 | (void) readdir_r(dirp, &dirp->ent, &entry); 758 | 759 | /* Return pointer to statically allocated directory entry */ 760 | return entry; 761 | } 762 | 763 | /* 764 | * Read next directory entry into called-allocated buffer. 765 | * 766 | * Returns zero on success. If the end of directory stream is reached, then 767 | * sets result to NULL and returns zero. 768 | */ 769 | static int 770 | readdir_r( 771 | DIR *dirp, struct dirent *entry, struct dirent **result) 772 | { 773 | /* Read next directory entry */ 774 | WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp); 775 | if (!datap) { 776 | /* No more directory entries */ 777 | *result = NULL; 778 | return /*OK*/0; 779 | } 780 | 781 | /* Attempt to convert file name to multi-byte string */ 782 | size_t n; 783 | int error = wcstombs_s( 784 | &n, entry->d_name, PATH_MAX + 1, 785 | datap->cFileName, PATH_MAX + 1); 786 | 787 | /* 788 | * If the file name cannot be represented by a multi-byte string, then 789 | * attempt to use old 8+3 file name. This allows the program to 790 | * access files although file names may seem unfamiliar to the user. 791 | * 792 | * Be ware that the code below cannot come up with a short file name 793 | * unless the file system provides one. At least VirtualBox shared 794 | * folders fail to do this. 795 | */ 796 | if (error && datap->cAlternateFileName[0] != '\0') { 797 | error = wcstombs_s( 798 | &n, entry->d_name, PATH_MAX + 1, 799 | datap->cAlternateFileName, PATH_MAX + 1); 800 | } 801 | 802 | if (!error) { 803 | /* Length of file name excluding zero terminator */ 804 | entry->d_namlen = n - 1; 805 | 806 | /* Determine file type */ 807 | DWORD attr = datap->dwFileAttributes; 808 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) 809 | entry->d_type = DT_CHR; 810 | else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) 811 | entry->d_type = DT_LNK; 812 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) 813 | entry->d_type = DT_DIR; 814 | else 815 | entry->d_type = DT_REG; 816 | 817 | /* Get offset of next file */ 818 | datap = dirent_next(dirp->wdirp); 819 | if (datap) { 820 | /* Compute 31-bit hash of the next directory entry */ 821 | entry->d_off = dirent_hash(datap); 822 | 823 | /* Push the next directory entry back to cache */ 824 | dirp->wdirp->cached = 1; 825 | } else { 826 | /* End of directory stream */ 827 | entry->d_off = (long) ((~0UL) >> 1); 828 | } 829 | 830 | /* Reset fields */ 831 | entry->d_ino = 0; 832 | entry->d_reclen = sizeof(struct dirent); 833 | } else { 834 | /* 835 | * Cannot convert file name to multi-byte string so construct 836 | * an erroneous directory entry and return that. Note that 837 | * we cannot return NULL as that would stop the processing 838 | * of directory entries completely. 839 | */ 840 | entry->d_name[0] = '?'; 841 | entry->d_name[1] = '\0'; 842 | entry->d_namlen = 1; 843 | entry->d_type = DT_UNKNOWN; 844 | entry->d_ino = 0; 845 | entry->d_off = -1; 846 | entry->d_reclen = 0; 847 | } 848 | 849 | /* Return pointer to directory entry */ 850 | *result = entry; 851 | return /*OK*/0; 852 | } 853 | 854 | /* Close directory stream */ 855 | static int 856 | closedir(DIR *dirp) 857 | { 858 | int ok; 859 | 860 | if (!dirp) 861 | goto exit_failure; 862 | 863 | /* Close wide-character directory stream */ 864 | ok = _wclosedir(dirp->wdirp); 865 | dirp->wdirp = NULL; 866 | 867 | /* Release multi-byte character version */ 868 | free(dirp); 869 | return ok; 870 | 871 | exit_failure: 872 | /* Invalid directory stream */ 873 | dirent_set_errno(EBADF); 874 | return /*failure*/-1; 875 | } 876 | 877 | /* Rewind directory stream to beginning */ 878 | static void 879 | rewinddir(DIR *dirp) 880 | { 881 | if (!dirp) 882 | return; 883 | 884 | /* Rewind wide-character string directory stream */ 885 | _wrewinddir(dirp->wdirp); 886 | } 887 | 888 | /* Get position of directory stream */ 889 | static long 890 | _wtelldir(_WDIR *dirp) 891 | { 892 | if (!dirp || dirp->handle == INVALID_HANDLE_VALUE) { 893 | dirent_set_errno(EBADF); 894 | return /*failure*/-1; 895 | } 896 | 897 | /* Read next file entry */ 898 | WIN32_FIND_DATAW *datap = dirent_next(dirp); 899 | if (!datap) { 900 | /* End of directory stream */ 901 | return (long) ((~0UL) >> 1); 902 | } 903 | 904 | /* Store file entry to cache for readdir() */ 905 | dirp->cached = 1; 906 | 907 | /* Return the 31-bit hash code to be used as stream position */ 908 | return dirent_hash(datap); 909 | } 910 | 911 | /* Get position of directory stream */ 912 | static long 913 | telldir(DIR *dirp) 914 | { 915 | if (!dirp) { 916 | dirent_set_errno(EBADF); 917 | return -1; 918 | } 919 | 920 | return _wtelldir(dirp->wdirp); 921 | } 922 | 923 | /* Seek directory stream to offset */ 924 | static void 925 | _wseekdir(_WDIR *dirp, long loc) 926 | { 927 | if (!dirp) 928 | return; 929 | 930 | /* Directory must be open */ 931 | if (dirp->handle == INVALID_HANDLE_VALUE) 932 | goto exit_failure; 933 | 934 | /* Ensure that seek position is valid */ 935 | if (loc < 0) 936 | goto exit_failure; 937 | 938 | /* Restart directory stream from the beginning */ 939 | FindClose(dirp->handle); 940 | if (!dirent_first(dirp)) 941 | goto exit_failure; 942 | 943 | /* Reset invalid flag so that we can read from the stream again */ 944 | dirp->invalid = 0; 945 | 946 | /* 947 | * Read directory entries from the beginning until the hash matches a 948 | * file name. Be ware that hash code is only 31 bits longs and 949 | * duplicates are possible: the hash code cannot return the position 950 | * with 100.00% accuracy! Moreover, the method is slow for large 951 | * directories. 952 | */ 953 | long hash; 954 | do { 955 | /* Read next directory entry */ 956 | WIN32_FIND_DATAW *datap = dirent_next(dirp); 957 | if (!datap) { 958 | /* 959 | * End of directory stream was reached before finding 960 | * the requested location. Perhaps the file in 961 | * question was deleted or moved out of the directory. 962 | */ 963 | goto exit_failure; 964 | } 965 | 966 | /* Does the file name match the hash? */ 967 | hash = dirent_hash(datap); 968 | } while (hash != loc); 969 | 970 | /* 971 | * File name matches the hash! Push the directory entry back to cache 972 | * from where next readdir() will return it. 973 | */ 974 | dirp->cached = 1; 975 | dirp->invalid = 0; 976 | return; 977 | 978 | exit_failure: 979 | /* Ensure that readdir will return NULL */ 980 | dirp->invalid = 1; 981 | } 982 | 983 | /* Seek directory stream to offset */ 984 | static void 985 | seekdir(DIR *dirp, long loc) 986 | { 987 | if (!dirp) 988 | return; 989 | 990 | _wseekdir(dirp->wdirp, loc); 991 | } 992 | 993 | /* Scan directory for entries */ 994 | static int 995 | scandir( 996 | const char *dirname, struct dirent ***namelist, 997 | int (*filter)(const struct dirent*), 998 | int (*compare)(const struct dirent**, const struct dirent**)) 999 | { 1000 | int result; 1001 | 1002 | /* Open directory stream */ 1003 | DIR *dir = opendir(dirname); 1004 | if (!dir) { 1005 | /* Cannot open directory */ 1006 | return /*Error*/ -1; 1007 | } 1008 | 1009 | /* Read directory entries to memory */ 1010 | struct dirent *tmp = NULL; 1011 | struct dirent **files = NULL; 1012 | size_t size = 0; 1013 | size_t allocated = 0; 1014 | while (1) { 1015 | /* Allocate room for a temporary directory entry */ 1016 | if (!tmp) { 1017 | tmp = (struct dirent*) malloc(sizeof(struct dirent)); 1018 | if (!tmp) 1019 | goto exit_failure; 1020 | } 1021 | 1022 | /* Read directory entry to temporary area */ 1023 | struct dirent *entry; 1024 | if (readdir_r(dir, tmp, &entry) != /*OK*/0) 1025 | goto exit_failure; 1026 | 1027 | /* Stop if we already read the last directory entry */ 1028 | if (entry == NULL) 1029 | goto exit_success; 1030 | 1031 | /* Determine whether to include the entry in results */ 1032 | if (filter && !filter(tmp)) 1033 | continue; 1034 | 1035 | /* Enlarge pointer table to make room for another pointer */ 1036 | if (size >= allocated) { 1037 | /* Compute number of entries in the new table */ 1038 | size_t num_entries = size * 2 + 16; 1039 | 1040 | /* Allocate new pointer table or enlarge existing */ 1041 | void *p = realloc(files, sizeof(void*) * num_entries); 1042 | if (!p) 1043 | goto exit_failure; 1044 | 1045 | /* Got the memory */ 1046 | files = (dirent**) p; 1047 | allocated = num_entries; 1048 | } 1049 | 1050 | /* Store the temporary entry to ptr table */ 1051 | files[size++] = tmp; 1052 | tmp = NULL; 1053 | } 1054 | 1055 | exit_failure: 1056 | /* Release allocated entries */ 1057 | for (size_t i = 0; i < size; i++) { 1058 | free(files[i]); 1059 | } 1060 | 1061 | /* Release the pointer table */ 1062 | free(files); 1063 | files = NULL; 1064 | 1065 | /* Exit with error code */ 1066 | result = /*error*/ -1; 1067 | goto exit_status; 1068 | 1069 | exit_success: 1070 | /* Sort directory entries */ 1071 | if (size > 1 && compare) { 1072 | qsort(files, size, sizeof(void*), 1073 | (int (*) (const void*, const void*)) compare); 1074 | } 1075 | 1076 | /* Pass pointer table to caller */ 1077 | if (namelist) 1078 | *namelist = files; 1079 | 1080 | /* Return the number of directory entries read */ 1081 | result = (int) size; 1082 | 1083 | exit_status: 1084 | /* Release temporary directory entry, if we had one */ 1085 | free(tmp); 1086 | 1087 | /* Close directory stream */ 1088 | closedir(dir); 1089 | return result; 1090 | } 1091 | 1092 | /* Alphabetical sorting */ 1093 | static int 1094 | alphasort(const struct dirent **a, const struct dirent **b) 1095 | { 1096 | return strcoll((*a)->d_name, (*b)->d_name); 1097 | } 1098 | 1099 | /* Sort versions */ 1100 | static int 1101 | versionsort(const struct dirent **a, const struct dirent **b) 1102 | { 1103 | return strverscmp((*a)->d_name, (*b)->d_name); 1104 | } 1105 | 1106 | /* Compare strings */ 1107 | static int 1108 | strverscmp(const char *a, const char *b) 1109 | { 1110 | size_t i = 0; 1111 | size_t j; 1112 | 1113 | /* Find first difference */ 1114 | while (a[i] == b[i]) { 1115 | if (a[i] == '\0') { 1116 | /* No difference */ 1117 | return 0; 1118 | } 1119 | ++i; 1120 | } 1121 | 1122 | /* Count backwards and find the leftmost digit */ 1123 | j = i; 1124 | while (j > 0 && isdigit(a[j-1])) { 1125 | --j; 1126 | } 1127 | 1128 | /* Determine mode of comparison */ 1129 | if (a[j] == '0' || b[j] == '0') { 1130 | /* Find the next non-zero digit */ 1131 | while (a[j] == '0' && a[j] == b[j]) { 1132 | j++; 1133 | } 1134 | 1135 | /* String with more digits is smaller, e.g 002 < 01 */ 1136 | if (isdigit(a[j])) { 1137 | if (!isdigit(b[j])) { 1138 | return -1; 1139 | } 1140 | } else if (isdigit(b[j])) { 1141 | return 1; 1142 | } 1143 | } else if (isdigit(a[j]) && isdigit(b[j])) { 1144 | /* Numeric comparison */ 1145 | size_t k1 = j; 1146 | size_t k2 = j; 1147 | 1148 | /* Compute number of digits in each string */ 1149 | while (isdigit(a[k1])) { 1150 | k1++; 1151 | } 1152 | while (isdigit(b[k2])) { 1153 | k2++; 1154 | } 1155 | 1156 | /* Number with more digits is bigger, e.g 999 < 1000 */ 1157 | if (k1 < k2) 1158 | return -1; 1159 | else if (k1 > k2) 1160 | return 1; 1161 | } 1162 | 1163 | /* Alphabetical comparison */ 1164 | return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]); 1165 | } 1166 | 1167 | /* Convert multi-byte string to wide character string */ 1168 | #if !defined(_MSC_VER) || _MSC_VER < 1400 1169 | static int 1170 | dirent_mbstowcs_s( 1171 | size_t *pReturnValue, wchar_t *wcstr, 1172 | size_t sizeInWords, const char *mbstr, size_t count) 1173 | { 1174 | /* Older Visual Studio or non-Microsoft compiler */ 1175 | size_t n = mbstowcs(wcstr, mbstr, sizeInWords); 1176 | if (wcstr && n >= count) 1177 | return /*error*/ 1; 1178 | 1179 | /* Zero-terminate output buffer */ 1180 | if (wcstr && sizeInWords) { 1181 | if (n >= sizeInWords) 1182 | n = sizeInWords - 1; 1183 | wcstr[n] = 0; 1184 | } 1185 | 1186 | /* Length of multi-byte string with zero terminator */ 1187 | if (pReturnValue) { 1188 | *pReturnValue = n + 1; 1189 | } 1190 | 1191 | /* Success */ 1192 | return 0; 1193 | } 1194 | #endif 1195 | 1196 | /* Convert wide-character string to multi-byte string */ 1197 | #if !defined(_MSC_VER) || _MSC_VER < 1400 1198 | static int 1199 | dirent_wcstombs_s( 1200 | size_t *pReturnValue, char *mbstr, 1201 | size_t sizeInBytes, const wchar_t *wcstr, size_t count) 1202 | { 1203 | /* Older Visual Studio or non-Microsoft compiler */ 1204 | size_t n = wcstombs(mbstr, wcstr, sizeInBytes); 1205 | if (mbstr && n >= count) 1206 | return /*error*/1; 1207 | 1208 | /* Zero-terminate output buffer */ 1209 | if (mbstr && sizeInBytes) { 1210 | if (n >= sizeInBytes) { 1211 | n = sizeInBytes - 1; 1212 | } 1213 | mbstr[n] = '\0'; 1214 | } 1215 | 1216 | /* Length of resulting multi-bytes string WITH zero-terminator */ 1217 | if (pReturnValue) { 1218 | *pReturnValue = n + 1; 1219 | } 1220 | 1221 | /* Success */ 1222 | return 0; 1223 | } 1224 | #endif 1225 | 1226 | /* Set errno variable */ 1227 | #if !defined(_MSC_VER) || _MSC_VER < 1400 1228 | static void 1229 | dirent_set_errno(int error) 1230 | { 1231 | /* Non-Microsoft compiler or older Microsoft compiler */ 1232 | errno = error; 1233 | } 1234 | #endif 1235 | 1236 | #ifdef __cplusplus 1237 | } 1238 | #endif 1239 | #endif /*DIRENT_H*/ 1240 | -------------------------------------------------------------------------------- /ssThinning.cxx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/ssThinning.cxx -------------------------------------------------------------------------------- /ssThinning.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vianamp/MitoGraph/70819e5f517e968fd11870b3d99764f827a7a289/ssThinning.h -------------------------------------------------------------------------------- /tools/seg2para/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | PROJECT(seg2para) 4 | 5 | include_directories('.') 6 | 7 | find_package(VTK REQUIRED) 8 | include(${VTK_USE_FILE}) 9 | 10 | add_executable(seg2para MACOSX_BUNDLE seg2para) 11 | 12 | if(VTK_LIBRARIES) 13 | target_link_libraries(seg2para ${VTK_LIBRARIES}) 14 | else() 15 | target_link_libraries(seg2para vtkHybrid vtkWidgets) 16 | endif() 17 | -------------------------------------------------------------------------------- /tools/seg2para/seg2para.cpp: -------------------------------------------------------------------------------- 1 | // ================================================================== 2 | // Liya Ding. 2016.04. 3 | // This code is developed based on the frame work of MitoGraph. 4 | // It reuses a majority part of the code of MitoGraph. 5 | // MitoGraph is written by Matheus P. Viana, 6 | // from Susanne Rafelski Lab, University of California Irvine 7 | // ================================================================== 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | bool _DebugFlag = true; 58 | double _rad = 0.150; 59 | double _dxy, _dz = -1.0; 60 | bool _export_graph_files = true; 61 | bool _export_image_resampled = true; 62 | bool _adaptive_threshold = false; 63 | bool _scale_polydata_before_save = true; 64 | bool _improve_skeleton_quality = false; 65 | bool _export_nodes_label = true; 66 | double _div_threshold = 0.1666667; 67 | bool _checkonly = false; 68 | bool _width = false; 69 | bool _resampleonly = false; 70 | bool _image_2_surface_flag = false; 71 | bool _filename_specific = false; 72 | 73 | 74 | // |------06------| 75 | // |------------------------18------------------------| 76 | // |---------------------------------------26----------------------------------| 77 | int ssdx_sort[26] = { 0,-1, 0, 1, 0, 0,-1, 0, 1, 0,-1, 1, 1,-1,-1, 0, 1, 0, -1, 1, 1,-1,-1, 1, 1,-1}; 78 | int ssdy_sort[26] = { 0, 0,-1, 0, 1, 0, 0,-1, 0, 1,-1,-1, 1, 1, 0,-1, 0, 1, -1,-1, 1, 1,-1,-1, 1, 1}; 79 | int ssdz_sort[26] = {-1, 0, 0, 0, 0, 1,-1,-1,-1,-1, 0, 0, 0, 0, 1, 1, 1, 1, -1,-1,-1,-1, 1, 1, 1, 1}; 80 | 81 | // In order to acess the voxel (x,y,z) from ImageJ, I should use 82 | // GetId(x,(Dim[1]-1)-y,z,Dim); 83 | // Or change the volume orientation... 84 | 85 | /**======================================================== 86 | Auxiliar functions 87 | =========================================================*/ 88 | 89 | 90 | // This routine returns the x of the id-th point of a 3D volume 91 | // of size Dim[0]xDim[1]xDim[2] 92 | int GetX(vtkIdType id, int *Dim); 93 | 94 | // This routine returns the y of the id-th point of a 3D volume 95 | // of size Dim[0]xDim[1]xDim[2] 96 | int GetY(vtkIdType id, int *Dim); 97 | 98 | // This routine returns the z of the id-th point of a 3D volume 99 | // of size Dim[0]xDim[1]xDim[2] 100 | int GetZ(vtkIdType id, int *Dim); 101 | 102 | // This routine returns the id of a point located at coordinate 103 | // (x,y,z) of a 3D volume of size Dim[0]xDim[1]xDim[2] 104 | vtkIdType GetId(int x, int y, int z, int *Dim); 105 | 106 | // Swap values 107 | void Swap(double *x, double *y); 108 | 109 | // Simple sorting algorithm and the output is such that 110 | // l3 >= l2 >= l3 111 | void Sort(double *l1, double *l2, double *l3); 112 | 113 | // Calculate the Frobenius norm of a given 3x3 matrix 114 | // http://mathworld.wolfram.com/FrobeniusNorm.html 115 | double FrobeniusNorm(double M[3][3]); 116 | 117 | // This routine scales the polydata points to the correct dimension 118 | // given by parameters _dxy and _dz. 119 | void ScalePolyData(vtkSmartPointer PolyData); 120 | void PolyData2XYPixelScale(vtkSmartPointer PolyData); 121 | 122 | /* ================================================================ 123 | IMAGE TRANSFORM 124 | =================================================================*/ 125 | 126 | // This routine converts 16-bit volumes into 8-bit volumes by 127 | // linearly scaling the original range of intensities [min,max] 128 | // in [0,255] (http://rsbweb.nih.gov/ij/docs/guide/146-28.html) 129 | vtkSmartPointer Convert16To8bit(vtkSmartPointer Image); 130 | 131 | // Apply a threshold to a ImageData and converts the result in 132 | // a 8-bit ImageData. 133 | vtkSmartPointer BinarizeAndConvertToDouble(vtkSmartPointer Image, double threshold); 134 | 135 | // Fill holes in the 3D image 136 | void FillHoles(vtkSmartPointer ImageData); 137 | 138 | /* ================================================================ 139 | I/O ROUTINES 140 | =================================================================*/ 141 | 142 | // Different utilities of this tool, major function 143 | int utilities(const char FileName[]); 144 | 145 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample = false); 146 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[], bool scale = _scale_polydata_before_save); 147 | 148 | /* ================================================================*/ 149 | 150 | void SaveImageData(vtkSmartPointer Image, const char FileName[], bool _resample) { 151 | 152 | if(_DebugFlag){ 153 | printf("Saving ImageData File...\n"); 154 | } 155 | 156 | vtkSmartPointer writer = vtkSmartPointer::New(); 157 | 158 | if (_resample) { 159 | if(_DebugFlag){ 160 | printf("\tResampling data...%f\t%f\n",_dxy,_dz); 161 | } 162 | vtkSmartPointer Resample = vtkSmartPointer::New(); 163 | Resample -> SetInterpolationModeToLinear(); 164 | Resample -> SetDimensionality(3); 165 | Resample -> SetInputData(Image); 166 | Resample -> SetAxisMagnificationFactor(0,1.0); 167 | Resample -> SetAxisMagnificationFactor(1,1.0); 168 | Resample -> SetAxisMagnificationFactor(2,_dz/_dxy); 169 | Resample -> Update(); 170 | 171 | vtkSmartPointer ImageResampled = Resample -> GetOutput(); 172 | ImageResampled -> SetSpacing(1,1,1); 173 | 174 | writer -> SetInputData(ImageResampled); 175 | } else { 176 | 177 | writer -> SetInputData(Image); 178 | 179 | } 180 | 181 | writer -> SetFileType(VTK_BINARY); 182 | writer -> SetFileName(FileName); 183 | writer -> Write(); 184 | 185 | if(_DebugFlag){ 186 | printf("\tFile Saved!\n"); 187 | } 188 | } 189 | 190 | void SavePolyData(vtkSmartPointer PolyData, const char FileName[], bool scale) { 191 | 192 | if(_DebugFlag){ 193 | printf("Saving PolyData from XYZ list...\n"); 194 | } 195 | 196 | if(_DebugFlag){ 197 | printf("\t#Points in PolyData file: %llu.\n",(vtkIdType)PolyData->GetNumberOfPoints()); 198 | } 199 | 200 | vtkSmartPointer Writer = vtkSmartPointer::New(); 201 | Writer -> SetFileType(VTK_BINARY); 202 | Writer -> SetFileName(FileName); 203 | Writer -> SetInputData(PolyData); 204 | Writer -> Write(); 205 | 206 | if(_DebugFlag){ 207 | printf("\tFile Saved!\n"); 208 | } 209 | } 210 | 211 | /**======================================================== 212 | Auxiliar functions 213 | =========================================================*/ 214 | 215 | int GetX(vtkIdType id, int *Dim) { 216 | return (int) ( id % (vtkIdType)Dim[0] ); 217 | } 218 | 219 | int GetY(vtkIdType id, int *Dim) { 220 | return (int) ( ( id % (vtkIdType)(Dim[0]*Dim[1]) ) / (vtkIdType)Dim[0] ); 221 | } 222 | 223 | int GetZ(vtkIdType id, int *Dim) { 224 | return (int) ( id / (vtkIdType)(Dim[0]*Dim[1]) ); 225 | } 226 | 227 | vtkIdType GetId(int x, int y, int z, int *Dim) { 228 | return (vtkIdType)(x+y*Dim[0]+z*Dim[0]*Dim[1]); 229 | } 230 | 231 | vtkIdType GetReflectedId(int x, int y, int z, int *Dim) { 232 | int rx = ceil(0.5*Dim[0]); 233 | int ry = ceil(0.5*Dim[1]); 234 | int rz = ceil(0.5*Dim[2]); 235 | int sx = (x-(rx-0.5)<0) ? -rx : Dim[0]-rx; 236 | int sy = (y-(ry-0.5)<0) ? -ry : Dim[1]-ry; 237 | int sz = (z-(rz-0.5)<0) ? -rz : Dim[2]-rz; 238 | return GetId(x-sx,y-sy,z-sz,Dim); 239 | } 240 | 241 | void Swap(double *x, double *y) { 242 | double t = *y; *y = *x; *x = t; 243 | } 244 | 245 | void Sort(double *l1, double *l2, double *l3) { 246 | if (fabs(*l1) > fabs(*l2)) Swap(l1,l2); 247 | if (fabs(*l2) > fabs(*l3)) Swap(l2,l3); 248 | if (fabs(*l1) > fabs(*l2)) Swap(l1,l2); 249 | } 250 | 251 | double FrobeniusNorm(double M[3][3]) { 252 | double f = 0.0; 253 | for (int i = 3;i--;) 254 | for (int j = 3;j--;) 255 | f += M[i][j]*M[i][j]; 256 | return sqrt(f); 257 | } 258 | 259 | void ScalePolyData(vtkSmartPointer PolyData) { 260 | double r[3]; 261 | vtkPoints *Points = PolyData -> GetPoints(); 262 | for (vtkIdType id = 0; id < Points -> GetNumberOfPoints(); id++) { 263 | Points -> GetPoint(id,r); 264 | Points -> SetPoint(id,_dxy*r[0],_dxy*r[1],_dz*r[2]); 265 | } 266 | Points -> Modified(); 267 | } 268 | 269 | 270 | void PolyData2XYPixelScale(vtkSmartPointer PolyData) { 271 | double r[3]; 272 | vtkPoints *Points = PolyData -> GetPoints(); 273 | for (vtkIdType id = 0; id < Points -> GetNumberOfPoints(); id++) { 274 | Points -> GetPoint(id,r); 275 | Points -> SetPoint(id,r[0],r[1],r[2]*_dz/_dxy); 276 | } 277 | Points -> Modified(); 278 | } 279 | 280 | 281 | /* ================================================================ 282 | I/O ROUTINES 283 | =================================================================*/ 284 | 285 | /* ================================================================ 286 | IMAGE TRANSFORM 287 | =================================================================*/ 288 | 289 | vtkSmartPointer Convert16To8bit(vtkSmartPointer Image) { 290 | 291 | // 8-Bit images 292 | if (Image -> GetScalarType() == VTK_UNSIGNED_CHAR) { 293 | 294 | return Image; 295 | 296 | // 16-Bit images 297 | } else if (Image -> GetScalarType() == VTK_UNSIGNED_SHORT) { 298 | 299 | if(_DebugFlag){ 300 | printf("Converting from 16-bit to 8-bit...\n"); 301 | } 302 | 303 | vtkSmartPointer Image8 = vtkImageData::New(); 304 | Image8 -> ShallowCopy(Image); 305 | 306 | vtkDataArray *ScalarsShort = Image -> GetPointData() -> GetScalars(); 307 | unsigned long int N = ScalarsShort -> GetNumberOfTuples(); 308 | double range[2]; 309 | ScalarsShort -> GetRange(range); 310 | 311 | if(_DebugFlag){ 312 | printf("\tOriginal intensities range: [%d-%d]\n",(int)range[0],(int)range[1]); 313 | } 314 | 315 | vtkSmartPointer ScalarsChar = vtkSmartPointer::New(); 316 | ScalarsChar -> SetNumberOfComponents(1); 317 | ScalarsChar -> SetNumberOfTuples(N); 318 | 319 | double x, y; 320 | vtkIdType register id; 321 | for ( id = N; id--; ) { 322 | x = ScalarsShort -> GetTuple1(id); 323 | y = 255.0 * (x-range[0]) / (range[1]-range[0]); 324 | ScalarsChar -> SetTuple1(id,(unsigned char)y); 325 | } 326 | ScalarsChar -> Modified(); 327 | 328 | Image8 -> GetPointData() -> SetScalars(ScalarsChar); 329 | return Image8; 330 | 331 | // Other depth 332 | } else { 333 | return NULL; 334 | } 335 | } 336 | 337 | vtkSmartPointer BinarizeAndConvertToDouble(vtkSmartPointer Image, double threshold) { 338 | 339 | vtkSmartPointer Image16 = vtkImageData::New(); 340 | Image16 -> ShallowCopy(Image); 341 | 342 | vtkDataArray *ScalarsDouble = Image -> GetPointData() -> GetScalars(); 343 | unsigned long int N = ScalarsDouble -> GetNumberOfTuples(); 344 | double range[2]; 345 | ScalarsDouble -> GetRange(range); 346 | 347 | vtkSmartPointer ScalarsChar = vtkSmartPointer::New(); 348 | ScalarsChar -> SetNumberOfComponents(1); 349 | ScalarsChar -> SetNumberOfTuples(N); 350 | 351 | double x; 352 | 353 | 354 | 355 | if (threshold > 0) { 356 | for ( vtkIdType id = N; id--; ) { 357 | x = ScalarsDouble -> GetTuple1(id); 358 | if (x< threshold-0.1) { 359 | ScalarsChar -> SetTuple1(id,0); 360 | } else { 361 | if(x< threshold+0.1) 362 | { 363 | ScalarsChar -> SetTuple1(id,40000); 364 | } 365 | else 366 | { 367 | ScalarsChar -> SetTuple1(id,0); 368 | } 369 | } 370 | } 371 | } else { 372 | for ( vtkIdType id = N; id--; ) { 373 | x = ScalarsDouble -> GetTuple1(id); 374 | ScalarsChar -> SetTuple1(id,(int)(40000*(x-range[0])/(range[1]-range[0]))); 375 | } 376 | } 377 | ScalarsChar -> Modified(); 378 | 379 | Image16 -> GetPointData() -> SetScalars(ScalarsChar); 380 | return Image16; 381 | 382 | } 383 | 384 | void FillHoles(vtkSmartPointer ImageData) { 385 | 386 | if(_DebugFlag){ 387 | printf("\tSearching for holes in the image...\n"); 388 | } 389 | 390 | int *Dim = ImageData -> GetDimensions(); 391 | vtkIdType N = ImageData -> GetNumberOfPoints(); 392 | 393 | vtkIdType i, s, ido, id; 394 | 395 | int x, y, z; 396 | double v, r[3]; 397 | bool find = true; 398 | long long int ro[3]; 399 | long int scluster, label; 400 | ro[0] = Dim[0] * Dim[1] * Dim[2]; 401 | ro[1] = Dim[0] * Dim[1]; 402 | 403 | vtkSmartPointer CurrA = vtkSmartPointer::New(); 404 | vtkSmartPointer NextA = vtkSmartPointer::New(); 405 | vtkSmartPointer CSz = vtkSmartPointer::New(); 406 | vtkSmartPointer Volume = vtkSmartPointer::New(); 407 | Volume -> SetNumberOfComponents(1); 408 | Volume -> SetNumberOfTuples(N); 409 | Volume -> FillComponent(0,0); 410 | 411 | for (x = 1; x < Dim[0]-1; x++) { 412 | for (y = 1; y < Dim[1]-1; y++) { 413 | for (z = 1; z < Dim[2]-1; z++) { 414 | id = ImageData -> FindPoint(x,y,z); 415 | if ((unsigned short int)ImageData->GetScalarComponentAsDouble(x,y,z,0)) { 416 | Volume -> SetTuple1(id,0); 417 | } else { 418 | Volume -> SetTuple1(id,1); 419 | } 420 | } 421 | } 422 | } 423 | 424 | Volume -> Modified(); 425 | 426 | label = 0; 427 | while (find) { 428 | for (s = 0; s < CurrA->GetNumberOfIds(); s++) { 429 | ido = CurrA -> GetId(s); 430 | ImageData -> GetPoint(ido,r); 431 | x = (int)r[0]; y = (int)r[1]; z = (int)r[2]; 432 | for (i = 0; i < 6; i++) { 433 | id = ImageData -> FindPoint(x+ssdx_sort[i],y+ssdy_sort[i],z+ssdz_sort[i]); 434 | v = Volume -> GetTuple1(id); 435 | if ((long int)v > 0) { 436 | NextA -> InsertNextId(id); 437 | Volume -> SetTuple1(id,-label); 438 | scluster++; 439 | } 440 | } 441 | } 442 | if (!NextA->GetNumberOfIds()) { 443 | find = false; 444 | for (id=ro[0]; id--;) { 445 | v = Volume -> GetTuple1(id); 446 | if ((long int)v > 0) { 447 | find = true; 448 | ro[0] = id; 449 | break; 450 | } 451 | } 452 | if (label) { 453 | CSz -> InsertNextTuple1(scluster); 454 | } 455 | if (find) { 456 | label++; 457 | scluster = 1; 458 | Volume -> SetTuple1(id,-label); 459 | CurrA -> InsertNextId(id); 460 | } 461 | } else { 462 | CurrA -> Reset(); 463 | CurrA -> DeepCopy(NextA); 464 | NextA -> Reset(); 465 | } 466 | } 467 | 468 | for (id = N; id--;) { 469 | if ((long int)Volume->GetTuple1(id)<-1) { 470 | ImageData -> GetPointData() -> GetScalars() -> SetTuple1(id,255); 471 | } 472 | } 473 | ImageData -> GetPointData() -> GetScalars() -> Modified(); 474 | 475 | if(_DebugFlag){ 476 | printf("\tNumber of filled holes: %ld\n",(long int)CSz->GetNumberOfTuples()-1); 477 | } 478 | 479 | } 480 | 481 | /* ================================================================ 482 | =================================================================*/ 483 | 484 | int utilities(const char FileName[]) { 485 | 486 | // Loading multi-paged TIFF file (Supported by VTK 6.2 and higher) 487 | char _fullpath[256]; 488 | sprintf(_fullpath,"%s",FileName); 489 | 490 | vtkSmartPointer TIFFReader = vtkSmartPointer::New(); 491 | int errlog = TIFFReader -> CanReadFile(_fullpath); 492 | // File cannot be opened 493 | if (!errlog) { 494 | printf("File %s cannnot be opened.\n",_fullpath); 495 | return -1; 496 | } 497 | TIFFReader -> SetFileName(_fullpath); 498 | TIFFReader -> Update(); 499 | 500 | int *Dim = TIFFReader -> GetOutput() -> GetDimensions(); 501 | 502 | if(_DebugFlag){ 503 | printf("Segmentation results to paraview volume and surfaces V1.0 [DEBUG mode]\n"); 504 | printf("File name: %s\n",_fullpath); 505 | printf("Volume dimensions: %dx%dx%d\n",Dim[0],Dim[1],Dim[2]); 506 | } 507 | 508 | // Exporting resampled images 509 | if (_export_image_resampled) { 510 | sprintf(_fullpath,"%s_resampled.vtk",FileName); 511 | SaveImageData(TIFFReader->GetOutput(),_fullpath,true); 512 | } 513 | 514 | 515 | if(_image_2_surface_flag){ 516 | vtkSmartPointer AllNucContours= vtkSmartPointer::New(); 517 | 518 | 519 | vtkSmartPointer appendFilter = 520 | vtkSmartPointer::New(); 521 | 522 | for( int objectNumber = 1; objectNumber<= TIFFReader-> GetOutput() -> GetScalarRange()[1]; objectNumber++) 523 | { 524 | 525 | vtkSmartPointer Binary = BinarizeAndConvertToDouble(TIFFReader->GetOutput(),objectNumber); 526 | 527 | 528 | //FillHoles(Binary); 529 | 530 | vtkSmartPointer SmoothImage = vtkSmartPointer::New(); 531 | SmoothImage -> SetInputData(Binary); 532 | SmoothImage -> SetStandardDeviation(2.5); 533 | SmoothImage -> Update(); 534 | 535 | // get smooth surface 536 | vtkSmartPointer Filter = vtkSmartPointer::New(); 537 | Filter -> SetInputData(SmoothImage->GetOutput()); 538 | 539 | Filter -> SetValue(1,5); 540 | Filter -> Update(); 541 | 542 | PolyData2XYPixelScale(Filter-> GetOutput() ); 543 | 544 | 545 | vtkSmartPointer ID = vtkSmartPointer::New(); 546 | ID->SetNumberOfValues(Filter -> GetOutput() -> GetNumberOfPoints() ); 547 | 548 | // Set the ID 549 | for(int ii = 0; ii GetOutput() ->GetNumberOfPoints(); ii++ ) 550 | { 551 | ID->SetValue(ii,objectNumber); 552 | } 553 | 554 | Filter -> GetOutput() -> GetPointData() -> SetScalars(ID); 555 | 556 | // append to the group of polydata surfaces 557 | vtkSmartPointer input1 = 558 | vtkSmartPointer::New(); 559 | 560 | 561 | input1->ShallowCopy(Filter->GetOutput()); 562 | 563 | 564 | appendFilter->AddInputData(input1); 565 | appendFilter->Update(); 566 | } 567 | sprintf(_fullpath,"%s_smooth_surface_all.vtk",FileName); 568 | SavePolyData(appendFilter->GetOutput(),_fullpath); 569 | } 570 | return 0; 571 | } 572 | 573 | /* ================================================================ 574 | MAIN ROUTINE 575 | =================================================================*/ 576 | 577 | int main(int argc, char *argv[]) { 578 | 579 | int i; 580 | char _impath[256]; 581 | sprintf(_impath,"./examples/"); 582 | char _filename[256]; 583 | sprintf(_filename,"0"); 584 | 585 | // Collecting input parameters 586 | for (i = 0; i < argc; i++) { 587 | printf("This argument: %s \n",argv[i]); 588 | 589 | if (!strcmp(argv[i],"-file")) { 590 | 591 | sprintf(_filename,"%s",argv[i+1]); 592 | _filename_specific = true; 593 | printf("Specified one file %s",_filename); 594 | } 595 | 596 | if (!strcmp(argv[i],"-path")) { 597 | 598 | sprintf(_impath,"%s",argv[i+1]); 599 | 600 | std::string fileString = _impath; 601 | 602 | // if not ended with /, add / 603 | if (!fileString.empty()){ 604 | char lastChar = *fileString.rbegin(); 605 | if( lastChar != '/'){ 606 | sprintf(_impath,"%s/",argv[i+1]); 607 | } 608 | } 609 | 610 | 611 | } 612 | if (!strcmp(argv[i],"-xy")) { 613 | _dxy = atof(argv[i+1]); 614 | } 615 | if (!strcmp(argv[i],"-z")) { 616 | _dz = atof(argv[i+1]); 617 | } 618 | if (!strcmp(argv[i],"-export_image_resampled")) { 619 | _export_image_resampled = true; 620 | } 621 | if (!strcmp(argv[i],"-resampleonly")) { 622 | _resampleonly = true; 623 | _export_image_resampled = true; 624 | } 625 | if (!strcmp(argv[i],"-image_2_surface_flag")) { 626 | _image_2_surface_flag = true; 627 | } 628 | if (!strcmp(argv[i],"-DebugFlag")) { 629 | _DebugFlag = true; 630 | } 631 | 632 | } 633 | 634 | 635 | if (_dz<0) { 636 | _dxy = 0.09; 637 | _dz = 0.2; 638 | _export_image_resampled = true; 639 | _improve_skeleton_quality = true; 640 | _DebugFlag = true; 641 | _div_threshold = 0.4; 642 | printf("Please, use -dxy and -dz to provide the pixel size.\n"); 643 | //return -1; 644 | } 645 | 646 | vtkSmartPointer directory = vtkSmartPointer::New(); 647 | int opened = directory->Open(_impath); 648 | if(!opened) 649 | { 650 | std::cout << "Invalid directory!" << std::endl; 651 | return EXIT_FAILURE; 652 | } 653 | 654 | vtkSmartPointer TiffFilenameIndexList = vtkSmartPointer::New(); 655 | 656 | if(_filename_specific) 657 | { 658 | int numberOfFiles = 1; 659 | std::cout << "1 file " << numberOfFiles << std::endl; 660 | 661 | TiffFilenameIndexList -> SetNumberOfComponents(1); 662 | TiffFilenameIndexList -> SetNumberOfTuples(0); 663 | std::string fileString = _impath; 664 | 665 | if (!fileString.empty()){ 666 | char lastChar = *fileString.rbegin(); 667 | if( lastChar != '/'){ 668 | fileString += "/"; 669 | } 670 | } 671 | 672 | fileString += _filename; 673 | 674 | TiffFilenameIndexList->InsertNextTuple1(1); 675 | 676 | } 677 | else 678 | { 679 | int numberOfFiles = directory->GetNumberOfFiles(); 680 | std::cout << "Number of all files: " << numberOfFiles << std::endl; 681 | 682 | TiffFilenameIndexList -> SetNumberOfComponents(1); 683 | TiffFilenameIndexList -> SetNumberOfTuples(0); 684 | 685 | for (int i = 0; i < numberOfFiles; i++) 686 | { 687 | std::string fileString = _impath; 688 | 689 | if (!fileString.empty()){ 690 | char lastChar = *fileString.rbegin(); 691 | if( lastChar != '/'){ 692 | fileString += "/"; 693 | } 694 | } 695 | 696 | 697 | fileString += directory->GetFile(i); 698 | std::string ext = vtksys::SystemTools::GetFilenameLastExtension(fileString); 699 | 700 | 701 | if( (ext == ".tif")||(ext == ".tiff")) { 702 | 703 | std::cout << "Find tiff file(s): " << std::endl; 704 | std::cout << fileString << std::endl; 705 | 706 | TiffFilenameIndexList->InsertNextTuple1(i); 707 | } 708 | } 709 | 710 | } 711 | // 712 | 713 | char _tifffilename[512]; 714 | 715 | 716 | for(int iTiffInd = 0 ; iTiffInd< TiffFilenameIndexList->GetNumberOfTuples();iTiffInd++) { 717 | std::string stdstr_tifffilename = _impath; 718 | if (!stdstr_tifffilename.empty()){ 719 | char lastChar = *stdstr_tifffilename.rbegin(); 720 | if( lastChar != '/'){ 721 | stdstr_tifffilename += "/"; 722 | } 723 | } 724 | 725 | if(_filename_specific) 726 | { 727 | stdstr_tifffilename += _filename; 728 | std::cout << "Work on tiff file: " << std::endl; 729 | std::cout << stdstr_tifffilename << std::endl; 730 | sprintf(_tifffilename,stdstr_tifffilename.c_str()); 731 | 732 | } 733 | else 734 | { 735 | stdstr_tifffilename += directory->GetFile(TiffFilenameIndexList->GetTuple1(iTiffInd)); 736 | std::cout << "Work on tiff file: " << std::endl; 737 | std::cout << stdstr_tifffilename << std::endl; 738 | 739 | sprintf(_tifffilename,stdstr_tifffilename.c_str()); 740 | } 741 | 742 | // the core function for the tool 743 | utilities(_tifffilename); 744 | 745 | printf("%s\t[done]\n",_tifffilename); 746 | } 747 | 748 | return 0; 749 | } 750 | -------------------------------------------------------------------------------- /tools/skell2img/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | PROJECT(skell2img) 5 | 6 | find_package(VTK REQUIRED) 7 | include(${VTK_USE_FILE}) 8 | 9 | add_executable(skell2img MACOSX_BUNDLE skell2img) 10 | 11 | if(VTK_LIBRARIES) 12 | target_link_libraries(skell2img ${VTK_LIBRARIES}) 13 | else() 14 | target_link_libraries(skell2img vtkHybrid vtkWidgets) 15 | endif() 16 | -------------------------------------------------------------------------------- /tools/skell2img/includes.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | -------------------------------------------------------------------------------- /tools/skell2img/skell2img.cxx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Export skeleton edges with length larger than threshold as a binary image 4 | 5 | */ 6 | 7 | #include "includes.h" 8 | 9 | int main(int argc, char *argv[]) { 10 | 11 | int i; 12 | std::string _skpath; 13 | std::string _rfpath; 14 | double _dxy, _dz, _length_threshold; 15 | 16 | // Collecting input parameters 17 | for (i = 0; i < argc; i++) { 18 | if (!strcmp(argv[i],"-skell")) { 19 | _skpath = argv[i+1]; 20 | } 21 | if (!strcmp(argv[i],"-reference")) { 22 | _rfpath = argv[i+1]; 23 | } 24 | if (!strcmp(argv[i],"-threshold")) { 25 | _length_threshold = (double)atof(argv[i+1]); 26 | } 27 | if (!strcmp(argv[i],"-xy")) { 28 | _dxy = atof(argv[i+1]); 29 | } 30 | if (!strcmp(argv[i],"-z")) { 31 | _dz = atof(argv[i+1]); 32 | } 33 | } 34 | 35 | printf("Skeleton: %s\n",_skpath.c_str()); 36 | printf("Reference Image: %s\n",_rfpath.c_str()); 37 | printf("Threshold: %1.3f\n",_length_threshold); 38 | 39 | // 40 | // Load Reference Image 41 | // 42 | 43 | vtkSmartPointer TIFFReader = vtkSmartPointer::New(); 44 | TIFFReader -> SetFileName((_rfpath+".tif").c_str()); 45 | TIFFReader -> Update(); 46 | 47 | vtkSmartPointer Image = TIFFReader -> GetOutput(); 48 | 49 | Image -> GetPointData() -> GetScalars() -> FillComponent(0,0); 50 | 51 | // 52 | // Load Skeleton 53 | // 54 | 55 | vtkSmartPointer PolyReader = vtkSmartPointer::New(); 56 | PolyReader -> SetFileName(_skpath.c_str()); 57 | PolyReader -> Update(); 58 | 59 | vtkSmartPointer Skell = PolyReader -> GetOutput(); 60 | 61 | printf("Number of Polydata Points: %d\n",(int)Skell->GetNumberOfPoints()); 62 | 63 | vtkIdType id, id2; 64 | double r[3], length; 65 | vtkSmartPointer Edge; 66 | 67 | for (id = 0; id < Skell->GetNumberOfPoints(); id++) { 68 | Skell -> GetPoint(id,r); 69 | length = Skell -> GetPointData() -> GetArray("Length") -> GetTuple1(id); 70 | 71 | if (length > _length_threshold) { 72 | Image -> GetPointData() -> GetScalars() -> SetTuple1(Image->FindPoint((int)r[0],(int)r[1],0), 255); 73 | } 74 | 75 | } 76 | 77 | vtkSmartPointer Writer = vtkSmartPointer::New(); 78 | Writer -> SetInputData(Image); 79 | Writer -> SetFileName((_rfpath+"-mask.tif").c_str()); 80 | Writer -> Write(); 81 | 82 | return 0; 83 | } 84 | --------------------------------------------------------------------------------