4ndro1d
4ndro1d

Reputation: 2976

Convert pixel matrix to variables (data frame) in R

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

Answers (1)

Parfait
Parfait

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

Related Questions