代码之家  ›  专栏  ›  技术社区  ›  moodymudskipper

从grDevices::colors()中查找最接近的颜色以使用ggplot复制图表

  •  -1
  • moodymudskipper  · 技术社区  · 7 年前

    假设我有一张这样的图表,作为图像:

    enter image description here

    我想提取它的颜色并找到 grDevices::colors() 这是看得出来的 here

    head(grDevices::colors())
    [1] "white"         "aliceblue"     "antiquewhite"  "antiquewhite1" "antiquewhite2" "antiquewhite3"
    

    最简单的输出是这些颜色的矢量。

    更理想的输出是数据帧对于真彩色代码,“圆形”颜色(即 grDevices::颜色() ),它覆盖的图像表面的百分比,以及覆盖区域的重心坐标。

    超级花哨的输出会将这些颜色名称覆盖在原始图表上,或者/或者构建一个新的点图,其中点位于这些中心位置,颜色名称作为文本标签。

    一个超花哨的输出将建议现有调色板之间最接近的匹配。

    1 回复  |  直到 7 年前
        1
  •  0
  •   moodymudskipper    7 年前

    tldr编号: get_named_colors("https://i.stack.imgur.com/zdyNO.png") 使用底部定义的函数。


    我们将以R格式加载图像,将其转换为长rgb格式,获取命名颜色的rgb值,并将它们放在相同的格式中,然后计算所有相关距离,并保持图像的每种颜色的最小值,从中获得输出。

    library(ggplot2)
    library(dplyr)      
    library(png)
    

    我们的候选人:

    rgb_named_colors <- t(col2rgb(grDevices::colors())/255)
    head(rgb_named_colors,3)
    #            red     green      blue
    # [1,] 1.0000000 1.0000000 1.0000000
    # [2,] 0.9411765 0.9725490 1.0000000
    # [3,] 0.9803922 0.9215686 0.8431373
    

    我们的颜色:

    img     <- readPNG("https://i.stack.imgur.com/zdyNO.png")
    dim(img) # [1] 476 746   3
    # it's a 3d matrix, let's convert it to long format
    rgb_img <- apply(img,3,c)
    colnames(rgb_img) <- c("red","green","blue")
    head(rgb_img,3)
    # red     green      blue
    # [1,] 0.9803922 0.9803922 0.9803922
    # [2,] 0.9803922 0.9803922 0.9803922
    # [3,] 0.9803922 0.9803922 0.9803922
    
    dim(unique(rgb_img)) # [1] 958   3
    

    我们有958种颜色,有点多,我们需要过滤掉那些发生率低的颜色, 我们设置了一个截止点 0.5% img像素。

    rgb_img_agg <-
      rgb_img %>%
      as_tibble %>%
      group_by_all %>%
      count %>%
      filter(n > dim(img)[1]* dim(img)[2] *0.5/100)
    

    结果如何?

    dim(rgb_img_agg) # [1] 11  4
    

    好多了。

    head(rgb_img_agg,3)
    # # A tibble: 3 x 4
    # # Groups:   red, green, blue [3]
    #          red     green      blue     n
    #        <dbl>     <dbl>     <dbl> <int>
    # 1 0.04705882 0.2627451 0.5137255  2381
    # 2 0.27843137 0.5568627 0.7803922 29353
    # 3 0.37254902 0.7450980 0.2549020  2170
    

    对于所有图像颜色,我们计算到命名颜色的距离,并保持最小值

    output <- apply(rgb_img_agg[1:3],1, function(row_img)
      grDevices::colors()[which.min(
      apply(rgb_named_colors,1,function(row_named)
        dist(rbind(row_img,row_named))))])
    
    ouput
    # [1] "dodgerblue4" "steelblue3"  "limegreen"   "olivedrab"   "gray80"      "olivedrab1"  "chocolate3"  "chocolate1" 
    # [9] "ghostwhite"  "gray98"      "white" 
    

    它起作用了!现在让我们用一个传奇来展示我们所有的颜色:

    ggplot(tibble(named_color=output),aes(named_color,fill=factor(named_color,levels=output))) + geom_bar() +
        scale_fill_manual(values = output)
    

    现在我们把所有东西都放在一个函数中:

    get_named_colors <- function(path, cutoff = 0.5){
      library(dplyr)
      library(ggplot2)
      library(png)
      # named colors
      rgb_named_colors <- t(col2rgb(grDevices::colors())/255)
    
      # colors from path
      img     <- readPNG(path)
      rgb_img <- apply(img,3,c)
      colnames(rgb_img) <- c("red","green","blue")
      rgb_img_agg <-
        rgb_img %>%
        as_tibble %>%
        group_by_all %>%
        count %>%
        filter(n > dim(img)[1]* dim(img)[2] *cutoff/100)
    
      # distances
      output <- apply(rgb_img_agg[1:3],1, function(row_img)
        grDevices::colors()[which.min(
          apply(rgb_named_colors,1,function(row_named)
            dist(rbind(row_img,row_named))))])
    
      p <- ggplot(tibble(named_color=output),aes(named_color,fill=factor(named_color,levels=output))) + geom_bar() +
        scale_fill_manual(values = output)
      print(p)
    
      output
    }
    

    如果我发现如何实现这些奇特的特性,我可能会更新。

    推荐文章