从 4000 多个图像集中过滤出 4 个完整的组

Posted

技术标签:

【中文标题】从 4000 多个图像集中过滤出 4 个完整的组【英文标题】:Filter for complete groups of 4 out of a 4000+ image set 【发布时间】:2020-03-03 02:29:30 【问题描述】:

我有一个包含 4000 多张图像的数据集。为了弄清楚代码,我将其中的一小部分移到了另一个文件夹中。

文件如下所示:

    folder

    r01c01f01p01-ch3.tiff
    r01c01f01p01-ch4.tiff
    r01c01f02p01-ch1.tiff
    r01c01f03p01-ch2.tiff
    r01c01f03p01-ch3.tiff
    r01c01f04p01-ch2.tiff
    r01c01f04p01-ch4.tiff
    r01c01f05p01-ch1.tiff 
    r01c01f05p01-ch2.tiff
    r01c01f06p01-ch2.tiff
    r01c01f06p01-ch4.tiff
    r01c01f09p01-ch3.tiff
    r01c01f09p01-ch4.tiff
    r01c01f10p01-ch1.tiff
    r01c01f10p01-ch4.tiff
    r01c01f11p01-ch1.tiff
    r01c01f11p01-ch2.tiff
    r01c01f11p01-ch3.tiff
    r01c01f11p01-ch4.tiff
    r01c02f10p01-ch1.tiff
    r01c02f10p01-ch2.tiff
    r01c02f10p01-ch3.tiff
    r01c02f10p01-ch4.tiff

我无法删除 -ch# 之前的名称,因为该信息很重要。

我想要做的是过滤图像文件夹,并仅移动/保留具有所有四个 ch 值(ch1-4)的集合(即:r01c02f10p01)。

对于背景:我使用不同的脚本将图像合并成一个复合图像,这取决于我们在每张图像上都有完整的 ch1、ch2、ch3 和 ch4 后缀,并且它们以四个为一组。 (此代码用于名为 Fiji 的图像处理软件,而不是 R。)

在尝试过滤图像时,该集合最初包括第五个通道 (ch5)。我能够像这样从原始文件夹中删除所有带有 ch5 的图像。

    ##Create folder variable which has all image files 
     setwd("/Desktop/Nov 5/")
          folder = list.files("/Desktop/Nov5/")
    folder <- list.files(getwd())

    ##Create final2 variable which has all image files ending in ch5
    final2 <- dir(path="/Desktop/Nov5/", pattern="ch5") 

    ##Remove final2 from folder
    file.remove(folder,final2) 

在尝试解决仅过滤完整集的问题时,我认为可以这样做:

    ch1 <- dir(path="/Desktop/cp/complete//", pattern="ch1")

    ch2 <- dir(path="/Desktop/cp/complete//", pattern="ch2")

    ch3 <- dir(path="/Desktop/cp/complete//", pattern="ch3")

    ch4 <- dir(path="/Desktop/cp/complete//", pattern="ch4")

应用 file.remove 函数,类似于下面,可能会起作用。

    final2 <- dir(path="/Desktop/cp1/Images//", pattern="ch5") 
    file.remove(folder,final2) 

但是,为每个 ch 值创建新变量会分散每个文件。我不确定如何使用这些来实际区分单个图像是否具有所有四个 ch 值来有意义地过滤我在原始(或新文件夹)中的图像。我看到的其他来源的问题与这个问题不太匹配。

另一个线程建议将文件转换为 data.frame,但这实际上不允许我操作文件夹中的图像文件。我需要移动/过滤文件,而不仅仅是显示正确文件的列表。如下:

    library(dplyr)

    ch_set <- 1:4

    files_to_keep <- data.frame(filename = files, stringsAsFactors = FALSE) %>%
      tidyr::extract(filename, into = c("group", "ch"), regex = "                (^[\\w\\d]+)\\-ch(\\d)", remove = FALSE) %>%
      mutate(ch = as.numeric(ch)) %>%
      group_by(group) %>% 
      filter(all(ch_set %in% ch))

    files_to_keep

总结一下:我希望将文件从没有完整 ch 值的随机分类(即:可能只有 ch1 和 ch2,或 ch3 和 ch4)过滤到仅包含完整 ch1、ch2、ch3 的文件分类, 和 ch4 图像。

注意:我对 R 还是很陌生,所以我可以澄清一些描述问题的语言是否存在问题。

【问题讨论】:

为了使事情最小化(请参阅minimal reproducible example)并在两个问题之间分开关注点,您可以将其编辑为仅以具有您需要移动的文件名列表开始的任务,所以您可以在这里专注于该任务 我进行了编辑以尝试将其缩减,但从功能上讲,这对任务非常紧密地交织在一起。我更关心正确过滤事物,并进行了编辑以反映这一点。 【参考方案1】:

我的解决方案:

library(tidyr)
library(dplyr)
library(magrittr)
library(stringr)

#Input data
dirnames <- data.frame(flenames = c("r01c01f01p01-ch3.tiff", "r01c01f01p01-ch4.tiff", "r01c01f02p01-ch1.tiff", "r01c01f03p01-ch2.tiff", 
                                    "r01c01f03p01-ch3.tiff", "r01c01f04p01-ch2.tiff", "r01c01f04p01-ch4.tiff", "r01c01f05p01-ch1.tiff", 
                                    "r01c01f05p01-ch2.tiff", "r01c01f06p01-ch2.tiff", "r01c01f06p01-ch4.tiff", "r01c01f09p01-ch3.tiff", 
                                    "r01c01f09p01-ch4.tiff", "r01c01f10p01-ch1.tiff", "r01c01f10p01-ch4.tiff", "r01c01f11p01-ch1.tiff", 
                                    "r01c01f11p01-ch2.tiff", "r01c01f11p01-ch3.tiff", "r01c01f11p01-ch4.tiff", "r01c02f10p01-ch1.tiff", 
                                    "r01c02f10p01-ch2.tiff", "r01c02f10p01-ch3.tiff", "r01c02f10p01-ch4.tiff"))

#To get actual input data in the format above
#Presuming this script is being executed from the directory where the `tiff` files are stored
dirnames <- data.frame(flenames = list.files(path = getwd(), pattern = "*.tiff"))

#Creating a column for the leading string, using which we can group the channels (stored in an accompanying column)
#Then grouping by the leading string, and nesting the channel and filename columns thereunder.
#Using the length of the nested tibble to consider files for removal.
#If the nested tibble contains 4 channels (i.e. length == 4), then keep. Else discard.
dirnames %<>% 
  mutate(fc1 = str_extract(flenames, ".+(?=\\-)")) %>% #Leading string
  mutate(fc2 = str_extract(flenames, "(?<=\\-)\\w+")) %>% #Channel string
  select(-c(flenames)) %>%
  group_by(fc1) %>%  #Grouping
  nest(fc3 = fc2) %>% #Nesting
  mutate(keep_val = if(length(unlist(fc3)) == 4)"Y" else"N") %>% #Checking to keep/discard
  unnest(fc3) %>% #Unnesting to get back original data frame
  mutate(flename = paste0(fc1, "-", fc2, ".tiff")) %>% #Getting the original filename back
  ungroup(.) %>% 
  select(flename, keep_val) #Reordering data frame

#For loop to iterate through data frame, and issue file.remove() commands as necessary
for(i in 1:nrow(dirnames))
  if(dirnames$keep_val[i] == "N")
    cat("Removing file ", paste0(dirnames$flename[i]), "\n")
    file.remove(dirnames$flename[i])
   else
    cat("Keeping file ", paste0(dirnames$flename[i]), "\n")
  


# Removing file  r01c01f01p01-ch3.tiff 
# Removing file  r01c01f01p01-ch4.tiff 
# Removing file  r01c01f02p01-ch1.tiff 
# Removing file  r01c01f03p01-ch2.tiff 
# Removing file  r01c01f03p01-ch3.tiff 
# Removing file  r01c01f04p01-ch2.tiff 
# Removing file  r01c01f04p01-ch4.tiff 
# Removing file  r01c01f05p01-ch1.tiff 
# Removing file  r01c01f05p01-ch2.tiff 
# Removing file  r01c01f06p01-ch2.tiff 
# Removing file  r01c01f06p01-ch4.tiff 
# Removing file  r01c01f09p01-ch3.tiff 
# Removing file  r01c01f09p01-ch4.tiff 
# Removing file  r01c01f10p01-ch1.tiff 
# Removing file  r01c01f10p01-ch4.tiff 
# Keeping file  r01c01f11p01-ch1.tiff 
# Keeping file  r01c01f11p01-ch2.tiff 
# Keeping file  r01c01f11p01-ch3.tiff 
# Keeping file  r01c01f11p01-ch4.tiff 
# Keeping file  r01c02f10p01-ch1.tiff 
# Keeping file  r01c02f10p01-ch2.tiff 
# Keeping file  r01c02f10p01-ch3.tiff 
# Keeping file  r01c02f10p01-ch4.tiff 

对代码的解释都包含在cmets里面。

对于实际使用,您可以获取输入文件列表,其中包含dirnames &lt;- list.files(pattern = "*.tiff") 之类的内容。

注意:我已将 file.remove() 注释掉以作为示例输出。

注意:此代码正好过滤四个文件(目前)。只需更改此行中的比较运算符 mutate(keep_val = if(length(unlist(fc3)) == 4)"Y" else"N") 和/或它后面的数字以在不同的阈值下选择(例如,所有文件至少有 4 个通道的数据可用)。

考虑到您提到您有 4000 多个文件,这可能会非常慢,具体取决于文件的大小。也许这是 shell 的任务?

希望我正确理解了您的问题,并在此提供了可行的解决方案。

【讨论】:

我认为这真的很接近!对于第一个块,我需要编辑它,因为我有实际的文件可以使用。我认为这应该由 dirnames 如果你能指出不足之处,我们应该可以进一步优化。 我编辑了我之前的评论以澄清。谢谢! 我也尝试编辑这样的目录名 我关闭了工作区只是为了确保,并在另一个包含复制图像的文件夹上进行了尝试。它似乎已经修复了自己!非常感谢!

以上是关于从 4000 多个图像集中过滤出 4 个完整的组的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV - 从灰度图像切出Mask前景区域

如何从图像的直方图中过滤出感兴趣的对象?

从大型数据集中过滤掉记录的最佳方法是什么

多重插补为啥要汇总分析

层 lstm_9 的输入 0 与层不兼容:预期 ndim=3,发现 ndim=4。收到的完整形状:[None, 2, 4000, 256]

随机抽样一致(RANSAC)原理分析