Reputation: 2976
I am looking for a solution to turn each pixel of an image into a variable of a data frame.
There are ~2500 input images with a resolution 320x280px and are read into a matrix with readJPEG()
. The file name contains information about the variable at which it should be classified later.
file_list <- list.files("D:/path/to/images", full.names=TRUE)
# Extract person number and eye position from file names
file_names <- sapply(strsplit(file_list, split = '/'), "[", 8)
person_list <- substr(file_names, 1 ,3)
person_class <- as.factor(person_list)
# Read pixel matrices from image files
pixelMatrices = lapply(X=file_list, FUN= function(x) readJPEG(file_list))
entryCount <- length(file_list)
# Setting up a proper data set
eyes = data.frame(pos= numeric(entryCount))
eyes$person <- person_class
eyes$pixels <- pixelMatrices
This results in a data frame where each object has 2 variables (person, pixels). But I want to have a data frame which has 320*280 + 1 variables. One for each pixel and the factor class.
I tried different approaches like unlisting the matrix
test <- as.data.frame(x = unlist(pixelMatrices[1]))
test <- unlist(pixelMatrices[1])
test <- as.data.frame(pixelMatrices[1])
but non giving proper results. The only (nearly) working approach I have so far is a for loop over all pixels and inserting row by row into the data set which looks like this:
count <- length(file_list)
imageWidth = 320;
imageHeight = 280;
variableCount = imageHeight * imageWidth + 1
images <- as.data.frame(matrix(seq(count),nrow=count,ncol=variableCount ))
images[1] <- eyes$person
for(i in 1:count) {
img <- readJPEG(file_list[i])
image <- c(img)
images[i, 2:variableCount] <- image
}
But the for loop is extremely slow. So what is the best approach to get a resulting data frame with ~2500 obj. of 89601 variables?
Upvotes: 2
Views: 829
Reputation: 107652
Consider flattening your matrices in an mapply()
call iteratively adding the person_class to each corresponding converted data frame of pixelMatrices. Then run do.call()
to row bind into final dataframe. Mapply ensures each element in person_class will align to connected matrix:
combinedata <- function(x,y){
# FLATTEN MATRIX AND TRANSPOSE ACROSS MANY COLUMNS
temp <- data.frame(t(as.vector(x)))
temp$person_class <- y
return(temp)
}
# WIDE LIST
dfList <- mapply(combinedata, pixelMatrices, person_class)
# LONG LIST CONVERSION FOR DO.CALL()
dfList <- lapply(1:entryCount, function(i) data.frame(dfList[,i]))
# ROW BIND UNDERLYING DATA FRAMES
finaldf <- do.call(rbind, dfList)
Upvotes: 1