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 OpenImageR
to 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)
The whole thing is quite simple to do.
Use the colorspace
library for this.
Here is my original img.jpg file.
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:
After this mutation, the original file looks like this.
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.
Hope this is what you were looking for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With