将图像数组转换为 RGB 到 HSL/HSV 并返回?

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

我使用 jpeg 包中的 readJPEG() 读取彩色 jpg 图像。现在我在 R 中将图像作为三维数组(宽度、高度、通道)

我想将这些图像数组转换成 HSL 或 HSV 颜色 space,对图像进行变异并再次将它们保存为 RGB 格式的 JPG。但是,由于图像非常大 (5000 x 8000),遍历每个单元格太耗时。我发现包 OpenImageR 可以快速将图像转换为 HSV 颜色 space,但是,我对“饱和度”通道中的大负值感到困惑。此外,该软件包不包含将图像转换回来的功能。

是否有任何包可以执行从 RGB 到 HSL 或 HSV(以及返回)的快速转换?或者有没有其他快速转换的方法?

这些是我目前尝试转换为单向元素的尝试:

# 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)

整个事情做起来很简单。 为此使用 colorspace 库。

这是我的原始 img.jpg 文件。

这是代码。

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")

请注意,要获取单独的 H、S、V(或 R、G、B)组件,您必须使用 coords 属性。

如您所见,我对组件 H、S、V 的修改如下:

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

经过这次突变,原来的文件看起来是这样的。

但是,如果您更喜欢在 HLS 调色板上进行突变,也是可以的。

#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")

这是经过 H/2、L/2 和 S/2 转换后的图像。

希望这就是您要找的。

Github repository 提出问题是明智的(以防 HSV 转换的错误案例有快速修复)。作为记录,我是 OpenImageR 包的作者和维护者。

我再次查看了 RGB_to_HSV 函数的代码,正如我在 Rcpp 代码函数顶部提到的那样,实现基于论文

Analytical Study of Colour Spaces for Plant Pixel Detection, Pankaj Kumar and Stanley J. Miklavcic, 2018, Journal of Imaging (page 3 of 12) or section 2.1.3,

饱和通道的负值极有可能与下面一行的错误有关,

 S(i) = 1.0 - (3.0 * s_val) * (R(i) + G(i) + B(i));

实际上(根据论文)应该是:

 S(i) = 1.0 - (3.0 * s_val) / (R(i) + G(i) + B(i));

(最后一项的除法而不是乘法)

我已将更新版本上传到 Github,您可以使用

安装它
remotes::install_github('mlampros/OpenImageR')

如果有效请反馈,以便我可以将新版本上传到 CRAN。

该包不包括从 HSV 到 RGB 的转换(根据我的理解,您想修改像素值然后转换为 RGB)。