估计阅读时长: 5 分钟

https://github.com/xieguigang/scale_colour_genshin

在用R绘图时,颜色设置是美化过程中不可缺少的一步。在实际绘图时,一般不会一一手动寻找合适的颜色,而是通过一些R包、网站提供好的,美观的颜色组合,即调色板(palette),可供使用。在这里介绍一种通过提取图片主题色的方法来为我们自动生成画图所用的颜色板数据。

从图片上提取主题色

针对于在图片上面所出现的主题色,我们可以通过对颜色的像素点数量统计来完成。例如,某一种颜色,其在整张图片上所出现的像素点数量越多,那么其就越有可能是该图片的主题色。那现在,主题色的定义思路有了,我们就可以进行相关算法的构建了。

颜色分组

基于上面所描述的主题色的定义,我们首先会需要定义一定的方法用于判断两个颜色相等。这样子我们就可以将图片上的颜色像素点按照等价性进行分组统计。假设现在我们来观察颜色咋计算机代码中的数据结构,我们可以发现,一个颜色值通常是由RGB三个通道值构成的。那假设我们将RGB这三个通道值构建出一个三个元素的向量的话,我们就可以计算出这个向量与原点的距离。距离值相近低于一定的阈值的颜色看作为相同的颜色的话,那么我们就可以写出如下所示的主题色提取代码:

Dim buffer As BitmapBuffer = BitmapBuffer.FromBitmap(copy, ImageLockMode.ReadOnly)
Dim allColors = buffer.GetPixelsAll.ToArray
' group all colors
Dim colorGroups = allColors _
   .Where(Function(c) Not IsWhiteColor(c, excludeWhite)) _
   .Where(Function(c) Not IsBlackColor(c, excludeBlack)) _
   .GroupBy(Function(c) stdNum.Sqrt(c.A ^ 2 + c.R ^ 2 + c.G ^ 2 + c.B ^ 2), offsets:=tolerance) _
   .OrderByDescending(Function(c) c.Length) _
   .Select(Function(c) c.Average) _
   .ToArray

上面的代码思路其实就是:

  1. 首先从图片上获取其所有的像素点颜色
  2. 然后我们就可以通过欧几里得距离公式计算出像素点颜色与原点的距离值
  3. 按照一定的tolerance阈值范围,对相近欧几里得距离的颜色进行分组
  4. 对分组的颜色进行像素点数量的统计并进行颜色降序排序
  5. 降序排序越靠前的对应颜色就是所给图片的主题色

这样子,我们对上面得到的按照所出现的像素点数量进行降序排序的颜色列表,取出前6个这样子的颜色结果列表,就可以得到对应的原神角色主题色颜色版了。

R#脚本提取原神角色主题色

我将图片的主题色提取功能集成在了grDevices::colors函数之中,如果我们向这个colors函数传递进入一个图片对象的话,那么这个函数就会返回给我们在图片上所出现的主题色列表,例如:

img = readImage(file);
# list = CustomDesigns.ExtractThemeColors(CType(term, Bitmap), topN:=n) _
#    .DoCall(AddressOf CustomDesigns.Order) _
#    .ToArray
theme_colors = colors(img, n = 6, character = TRUE);

通过上面的代码,我们可以实现从文件系统上读取一个图片文件,然后通过colors函数提取出6种主题色颜色值。使用起来是不是非常的简单?!!

那,基于上面的主题色提取代码,我们就可以编写出一个R#脚本进行原神角色图片集合的批量处理操作了,示例脚本代码如下:

require(JSON);

#' extract the image theme colors
#' 
#' @return a character vector of the theme color
#' 
extract_colors = function(file) {
    img = readImage(file);
    theme_colors = colors(img, n = 6, character = TRUE);
    rect = `<div style="width: 100px; height: 25px; background-color: ${theme_colors}">
                <span style="color: white;">  ${theme_colors}</span>
            </div>`;
    rect = `
        <div style="width: 10%; min-width: 100px; float: left;">
            ${paste(rect, " ")}
        </div>
        <div style="width: 70%;">
            <img style="height: 600px;" src="./../character_posts/${basename(file, withExtensionName = TRUE)}">
        </div>
    `;
    print(theme_colors);
    writeLines(rect, con = `${pwd}/demo/${basename(file)}.html`);

    theme_colors;
}

pwd = @dir;
files = list.files(`${pwd}/character_posts/`, pattern = ".+\.((png)|(jpg))", wildcard = FALSE);
theme_colors = lapply(files, path -> extract_colors(path), names = basename(files));

print(basename(files));
str(theme_colors);

theme_colors
|> JSON::json_encode()
|> writeLines(con = `${pwd}/../data/scale_colour_genshin.json`)
;

配色列表提取示例

下面展示了通过上面的脚本所提取出来的角色主题色的结果:




谢桂纲
Latest posts by 谢桂纲 (see all)

Attachments

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *

博客文章
December 2024
S M T W T F S
1234567
891011121314
15161718192021
22232425262728
293031  
  1. 在mysql之中,针对24小时内的数据按照半个小时进行一次统计数量: ```sql SELECT DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(add_time) / 1800) * 1800), '%Y-%m-%d %H:%i') AS half_hour, COUNT(*) AS count FROM user_track.page_view WHERE add_time >=…

  2. 针对图对象进行向量化表示嵌入: 首先,通过node2vec方法,将node表示为向量 第二步,针对node向量矩阵,进行umap降维计算,对node进行排序,生成node排序序列 第三步,针对node排序序列进行SGT序列图嵌入,实现将网络图对象嵌入为一维向量