您对“二进制周长”的定义并不能很好地近似平滑周长。
n <- 100
im <- matrix(0, 3*n, 3*n+1)
x <- ( col(im) - 1.5*n ) / n
y <- ( row(im) - 1.5*n ) / n
im[ x^2 + y^2 <= 1 ] <- 1
image(im)
s1 <- function(z) cbind(rep(0,nrow(z)), z[,-ncol(z)] )
s2 <- function(z) cbind(z[,-1], rep(0,nrow(z)) )
s3 <- function(z) rbind(rep(0,ncol(z)), z[-nrow(z),] )
s4 <- function(z) rbind(z[-1,], rep(0,ncol(z)) )
area <- function(z) sum(z)
perimeter <- function(z) sum( z != 0 & s1(z)*s2(z)*s3(z)*s4(z) == 0)
circularity <- function(z) 4*pi*area(z) / perimeter(z)^2
circularity(im)
area(im)
n^2*pi
perimeter(im)
2*pi*n
一个令人担忧的特性是其周长不具备旋转不变性:当你将一个边长为1(与坐标轴平行)的正方形旋转45度时,它的面积保持不变,但其周长被除以sqrt(2)...
square1 <- -1 <= x & x <= 1 & -1 <= y & y <= 1
c( perimeter(square1), area(square1) )
square2 <- abs(x) + abs(y) <= sqrt(2)
c( perimeter(square2), area(square2) )
这里是更好的周长近似值。
对于周长上的每个点,
查看其8邻域中哪些点也在周长上;
如果它们形成一个垂直或水平线段,
则该对点对周长的贡献为1,
如果它们在对角线上,则贡献为sqrt(2)。
edge <- function(z) z & !(s1(z)&s2(z)&s3(z)&s4(z))
perimeter <- function(z) {
e <- edge(z)
(
sum( e & s1(e) ) + sum( e & s2(e) ) + sum( e & s3(e) ) + sum( e & s4(e) ) +
sqrt(2)*( sum(e & s1(s3(e))) + sum(e & s1(s4(e))) + sum(e & s2(s3(e))) + sum(e & s2(s4(e))) )
) / 2
}
perimeter(im)
c( perimeter(square1), area(square1) )
c( perimeter(square2), area(square2) )
circularity(im)
circularity(square1)
circularity(square2)