Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting image array to RGB to HSL/HSV and back?

Tags:

r

rgb

hsl

hsv

I read in colored jpg images using readJPEG() from the jpeg package. Now I have my images as three-dimensional arrays (width, height, channels) in R.

I want to convert these image arrays into the HSL or HSV color space, mutate the images and save them as JPGs in the RGB format again. However, as the images are quite large (5000 x 8000), it would be too time consuming to loop through every single cell. I found the package OpenImageRto convert the image to the HSV color space quickly, however, I am confused by large negative values in the "saturation" channel. Also, the package contains no functions to convert the image back.

Is there any package to perform fast conversions from RGB to HSL or HSV (and back)? Or is there any other way to perform the converison quickly?

These are my current attempts for converting into one direction, element-wise:

# load packages
library(jpeg)
library(plotwidgets)    

# load image
img <- readJPEG(img_path)
img <- img * 255
  
# new empty image
img_new <- array(NA, dim = dim(img))

# this takes way too long
for (img_row in 1:dim(img)[1]) {
  for (img_col in 1:dim(img)[2]) {
    img_new[img_row,img_col,] <- round(rgb2hsl(as.matrix(img[img_row,img_col,])))
  }
}

# this takes also way too long
for (img_row in 1:dim(img)[1]) {
  img_new[img_row,,] <- t(round(rgb2hsl(t(matrix(img[img_row,,], ncol = 3)))))
}

# this takes also ages
rgb_hsl_fun <- function(x) {
  as.numeric(rgb2hsl(matrix(x)))
}
img_hsl <- apply(X = img, MARGIN = c(1,2), FUN = rgb_hsl_fun)
like image 683
Zoe Avatar asked Oct 15 '22 19:10

Zoe


1 Answers

The whole thing is quite simple to do. Use the colorspace library for this.

Here is my original img.jpg file. enter image description here

Here is the code.

library(jpeg)
library(colorspace)

#Reading a jpg file
img = readJPEG("img.jpg") * 255

#Row-by-row conversion
for(i in 1:dim(img)[1]){
  
  #Convert to HSV format
  hsv = RGB(img[i,,1], img[i,,2], img[i,,3]) |> as("HSV")
  
  #Mutation of H, S, V components
  attributes(hsv)$coords[,"H"] = attributes(hsv)$coords[,"H"]/2 
  attributes(hsv)$coords[,"S"] = attributes(hsv)$coords[,"S"]*.998 
  attributes(hsv)$coords[,"V"] = attributes(hsv)$coords[,"V"]-1 
  
  #Convert to RGB format and save to the current line.
  rgb = as(hsv, "RGB")
  img[i,,1] = attributes(rgb)$coords[,"R"]
  img[i,,2] = attributes(rgb)$coords[,"G"]
  img[i,,3] = attributes(rgb)$coords[,"B"]
}

#Save to JPG file
writeJPEG(img / 255, "img_hsv.jpg")

Just note that to get to the individual H, S, V (or R, G, B) components you have to use the coords attribute.

As you can see, my mutation of the components H, S, V was as follows:

  • H = H / 2
  • S = S * 0.998
  • V = V-1

After this mutation, the original file looks like this. enter image description here

However, if you prefer to carry out the mutation on the HLS palette, it is possible.

#Reading a jpg file
img = readJPEG("img.jpg") * 255

#Row-by-row conversion
for(i in 1:dim(img)[1]){
  
  #Convert to HLS format
  hls = RGB(img[i,,1], img[i,,2], img[i,,3]) |> as("HLS")
  
  #Mutation of H, S, V components
  attributes(hls)$coords[,"H"] = attributes(hls)$coords[,"H"]/2 
  attributes(hls)$coords[,"L"] = attributes(hls)$coords[,"L"]/2 
  attributes(hls)$coords[,"S"] = attributes(hls)$coords[,"S"]/2 
  
  #Convert to RGB format and save to the current line.
  rgb = as(hls, "RGB")
  img[i,,1] = attributes(rgb)$coords[,"R"]
  img[i,,2] = attributes(rgb)$coords[,"G"]
  img[i,,3] = attributes(rgb)$coords[,"B"]
}

#Save to JPG file
writeJPEG(img / 255, "img_hls.jpg")

Here is the image with H/2, L/2 and S/2 conversion. enter image description here

Hope this is what you were looking for.

like image 136
Marek Fiołka Avatar answered Oct 20 '22 19:10

Marek Fiołka