r - 计算二进制图像的圆度

标签 r image-processing binary shape geometry

我正在尝试计算给定二进制图像的圆度。经过一番研究,我很清楚圆度的公式是

4π*area/perimeter^2

范围从0到1,最圆形的为1。

给定二进制矩阵im
计算面积是微不足道的

面积=总和(im)

我正在按照以下规则计算周长:A pixel is part of the perimeter if it is nonzero and it is connected to at least one zero-valued pixel
per = matrix(0, nrow(im), ncol(im))
for(i in 2:(nrow(im)-1)){
  for(j in 2:(ncol(im)-1)){
    if(im[i,j] != 0){
      x=c(im[i-1,j],im[i+1,j],im[i,j-1], im[i,j+1])
      if(0 %in% x) per[i,j] = 1
    }
  }
}
perimeter = sum(per)

然后我像这样计算圆度:
circ = (4*pi*area)/(perimiter^2)

但是,有时我会得到大于1的值,并且事情不会累加。例如:

该图像给了我circ=1.155119
这个图片给了我circ=1.148728
知道发生了什么吗?
值不应该更像0.950.7

最佳答案

您对“二进制周长”的定义不是一个很好的近似值
的周长。

# Sample data
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)

# Shift the image in one direction
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, perimeter and circularity
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)
# [1] 1.241127

area(im)
# [1] 31417
n^2*pi
# [1] 31415.93

perimeter(im)
# [1] 564
2*pi*n
# [1] 628.3185

一个令人担忧的特征是该周长不是旋转不变的:
当您旋转边1的正方形(边与轴平行)时
乘以45度,其面积保持不变,但周长除以sqrt(2)...
square1 <- -1 <= x & x <= 1 & -1 <= y & y <= 1
c( perimeter(square1), area(square1) )
# [1]   800 40401

square2 <- abs(x) + abs(y) <= sqrt(2)
c( perimeter(square2), area(square2) )
# [1]   564 40045

这是周长的更好近似值。
对于周长上的每个点,
看看它的8个街区中的哪些点也在周边;
如果它们形成垂直或水平线段,
该对对周长的贡献为1,
如果它们是对角线,则贡献为sqrt(2)。
edge <- function(z) z & !(s1(z)&s2(z)&s3(z)&s4(z))
perimeter <- function(z) {
  e <- edge(z)
  ( 
    # horizontal and vertical segments
    sum( e & s1(e) ) + sum( e & s2(e) ) + sum( e & s3(e) ) + sum( e & s4(e) ) + 
    # diagonal segments
    sqrt(2)*( sum(e & s1(s3(e))) + sum(e & s1(s4(e))) + sum(e & s2(s3(e))) + sum(e & s2(s4(e))) )
  ) / 2  # Each segment was counted twice, once for each end
}

perimeter(im)
# [1] 661.7544
c( perimeter(square1), area(square1) )
# [1]   805.6569 40401.0000
c( perimeter(square2), area(square2) )
# [1]   797.6164 40045.0000

circularity(im)
# [1] 0.9015315
circularity(square1)
# [1] 0.7821711
circularity(square2)
# [1] 0.7909881

关于r - 计算二进制图像的圆度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15912817/

相关文章:

r - 将字符串传递到 lme/lmer 的 'contrasts' 参数中

java - Java 中的图像、绘图和操作框架?

c++ - 使用基于范围的 for 循环以相反的顺序打印 vector

c++ - a+(-a) 操作期间溢出

python - 是否可以在 OpenCV 中将图像粘贴到另一个图像之上?

python re 模块替换文本文件中的二进制数据?

R和 Shiny : Pass inputs from sliders to reactive function to compute output

r - 将空格和等号分隔的字符串拆分为不同的列

r - 使用 terra::predict 和 caret::train ranger 模型生成物种分布的预测栅格

image - MatLab - 使用 FFT 移动图像