【问题标题】:R: Count objects in a pictureR:计算图片中的对象
【发布时间】:2016-08-15 16:57:17
【问题描述】:

我目前正在研究一个问题,我使用图片构建分类器来预测结果。基本上,我在图片上有对象(一个或几个),我想识别它们。因为我可以有一个或多个对象(并不总是相同),所以我首先希望能够计算我的图片上有多少对象。我不想运行任何机器学习算法,我想有一些方法尽可能快地完成它。

运行 k-means(使用颜色)使我能够将图片分成 2 个颜色组,这已经在背景和对象之间提供了很好的分离。从这张照片中,我想找到一种方法来计算所有不同的“区域”。我尝试使用颜色和位置来运行 k-means 以尝试一步完成所有操作,但效果不佳,因为向 kmeans 添加位置会降低其结果。

下面是图片的示例,一旦使用 kmeans 将其分隔为两个颜色区域:

显然这里有 5 个对象和一个背景。或者,6 个不同的区域。

我想做的是在这张图片上运行一个算法,它会告诉我那个数字。我不熟悉图像处理,所以我想不出一种快速有效的方法。我会想到的一种解决方案是从 objects 类 中获取一个像素,并测试相邻像素是否属于同一类或实际上是 background 类 的一部分。但这将是一个痛苦的漫长过程。

我尝试过 blob 识别,但该算法似乎不适合我的需要。

我很想知道如何解决这类问题。我不介意自己编写算法代码,但我也想知道是否有 R 包可以轻松实现这种事情。

我希望一切都足够清楚。非常感谢您!

【问题讨论】:

标签: r image algorithm


【解决方案1】:

更新找到link to an implementation of bwlabel in the R image processing toolbox。所以以下可能不是必需的,但创建起来很有趣:-) 你应该看看那个包,因为它有其他对象分割算法(即分水岭),可能比你的 k-means 聚类的第一步更好.

如果您的分割在背景和对象之间正确标记,并且至少有一个背景像素将不同对象之间的边界分开,那么您可能希望在 R 中实现 matlab 的 bwlabel 函数。有关该解释,请参阅 this SO question/answer

下面是一个不执行标记的实现(尽管它很容易被采用):

find.contiguous <- function(img, x, bg) {
  ## we need to deal with a single (row,col) matrix index
  ## versus a collection of them in a two column matrix separately.
  if (length(x) > 2) {
    lbl <- img[x][1]
    img[x] <- bg
    xc <- x[,1]
    yc <- x[,2]
  } else {
    lbl <- img[x[1],x[2]]
    img[x[1],x[2]] <- bg
    xc <- x[1]
    yc <- x[2]
  }    
  ## find all neighbors of x
  x <- rbind(cbind(xc-1, yc-1),
             cbind(xc  , yc-1),
             cbind(xc+1, yc-1),
             cbind(xc-1, yc),
             cbind(xc+1, yc),
             cbind(xc-1, yc+1),
             cbind(xc  , yc+1),
             cbind(xc+1, yc+1))
  ## that have the same label as the original x
  x <- x[img[x] == lbl,]
  ## if there is none, we stop and return the updated image
  if (length(x)==0) return(img);
  ## otherwise, we call this function recursively
  find.contiguous(img,x,bg)
}

find.contiguous 是一个递归函数,对于它收到的每个调用:

  1. 图片img的工作副本。
  2. 像素(矩阵)索引x (row,col) 的集合,属于图像img 中的对象。
  3. 背景值bg

find.contiguous 然后继续:

  1. imgx 处的所有像素设置为bg 颜色。这标志着我们已经访问了像素。
  2. 查找x 中与x 具有相同标签(值)的所有相邻像素。这会扩大同一对象的区域。请注意,由于x 不一定是单个像素,x 会以几何形状增长,因此,事实上,这个函数并没有懈怠。
  3. 如果没有更多的邻居属于同一个对象,我们返回更新后的图像;否则,我们进行递归调用。

从对应于对象的单个像素开始,对find.contiguous 的调用将扩大该区域以包含对象的所有像素并返回更新的图像,其中对象被背景替换。然后可以循环重复此过程,直到图像中不再有对象,因此可以生成计数。

为了说明,我假设你的二进制图像是一个名为matriximg

## set the background pixel value
bg <- 0
## set the object pixel value
obj <- 1

## pad image so that the edge is background, this is necessary because 
## the neighborhood generated in find.contiguous must lie strictly within 
## the image
tmp <- matrix(bg,nrow=nrow(img)+2,ncol=ncol(img)+2)
tmp[2:(nrow(img)+1),2:(ncol(img)+1)] <- img
img <- tmp

## initialize the count to zero
count <- 0
## get all pixel coordinates that are objects
x <- which(img==obj, arr.ind=TRUE)
## loop until there are no more pixels that are objects
while (length(x) > 0) {
  ## choose a single (e.g., first) pixel location. This belongs to the current
  ## object that we will grow and remove from the image using find.contiguous
  if (length(x) > 2) {
    x <- x[1,]
  }
  ## increment the count
  count <- count + 1
  ## make the call to remove the object from img
  img <- find.contiguous(img, x, bg)
  ## find the remaining pixel locations belonging to objects
  x <- which(img==obj, arr.ind=TRUE)
}

您的答案在count。在上一个链接中的示例数据上运行:

img <- as.matrix(read.table(text="
0  0  0  0  0  1  1  1  0  0 
0  1  0  1  0  0  1  1  0  0
0  1  1  1  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  1
0  0  0  0  0  0  0  0  1  1
0  0  1  1  1  1  0  0  1  1", header=FALSE))

我们得到:

print(paste("number of objects: ",count))
##[1] "number of objects:  4"

【讨论】:

    【解决方案2】:

    我不是图片识别方面的专家 - 所以我的方法可能会失败。 如果您的对比度很好并且所有矩形都水平对齐,您可以尝试以下方法:

    • 找到边界 - 减少到 1D:构建图片的梯度,并获取梯度高于某个阈值的点(希望这给出了所有矩形的“边界线”)
    • 得到4个角:随机画一个点。采取一个小步长增量并找到邻居(应该有 2 - “不允许以前的邻居 => 始终朝同一个方向前进)。同时跟踪 x 和 y 的变化。重复该过程直到你回到第一个)。x 或 y 变化的点属于角点。
    • 重建矩形:从角落用一条线(Exculde area of​​ stepsize delta)拟合角落之间的点。将线条限制在两个角之间的空间内。
    • 删除找到的矩形:如果拟合足够好(例如 r 平方),请删除数据中与您的拟合接近的所有点 - 之前找到的矩形中不应保留任何内容,您可以增加找到的矩形数。
    • 重复上述操作,直到数据为空

    如果可行,您还可以得到矩形的中心。 希望对你有帮助……

    【讨论】:

      猜你喜欢
      • 2017-07-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      • 2019-11-07
      相关资源
      最近更新 更多