Фильтр для полных групп из 4 из 4000+ наборов изображений - PullRequest
1 голос
/ 06 ноября 2019

У меня есть набор данных из 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 #, поскольку эта информация важна.

Что я хочу сделать, это отфильтровать папку изображений и переместить / сохранить только наборы (т. Е. R01c02f10p01), которые имеют все четыре значения ch (ch1-4).

Для фона: я использую другой сценарий для объединения изображений в составной, опираясь на тот факт, что у нас есть полный суффикс ch1, ch2, ch3 и ch4 для каждого изображения, и что они в пакетахчетыре. (Этот код используется в программном обеспечении для обработки изображений под названием «Фиджи», а не «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, поэтому я могу уточнить, выключен ли какой-либо язык, описывающий проблему.

1 Ответ

0 голосов
/ 06 ноября 2019

Мое решение:

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 

Пояснения к коду включены в комментарии внутри.

Для реального использования вы можете получить список входных файлов с чем-то вроде dirnames <- list.files(pattern = "*.tiff").

Примечание : Я закомментировал file.remove() для моего примера вывода.

Примечание : этот код фильтрует для четырех файлов точно (вмомент). Просто измените оператор сравнения в этой строке mutate(keep_val = if(length(unlist(fc3)) == 4){"Y"} else{"N"}) и / или число после него, чтобы выбрать его с разными пороговыми значениями (например, для всех файлов, в которых имеются данные как минимум для 4 каналов).

Вероятно, это будеточень медленно в зависимости от размера файлов, учитывая, что вы упомянули, что у вас более 4000 файлов. Может быть, это задача для оболочки?

Надеюсь, я правильно понял ваш вопрос и предоставил здесь работоспособное решение.

...