图象色彩提取

本文github项目:colorful color
我的codepen链接:图象颜色提取
the demo
原创文章,转载请说明

近来想找个小项目练练手,以便熟习React,因而想到了“图象颜色提取”这个方向,也有的说法是图象主题色提取颜色量子化,或者是叫由图象天生调色板,缘由无他,只是由于美丽!

《图象色彩提取》

“剖析”的目的有这么几个:

  • 主要颜色: main color 就是涌现频次最高的颜色,如许色颜色在设想中常常是用于背景色,供应沉醉式的体验:

《图象色彩提取》

  • 均匀颜色: average color 是一切颜色的均匀值,和主要颜色一样可以用作背景色;
  • 颜色量子化: 颜色量子化在这里相称因而在提取主题色,结果是图象中一系列主要颜色的鸠合,这些颜色可以经由历程统计剖析获得,也可以经由历程聚类算法天生。同时,主要颜色均匀颜色主题色这几个因子都可以作为图象的特性,特性可以用于图象进一步剖析,比方图象识别与检索,紧缩等;

《图象色彩提取》

  • 颜色可视化: 图象自身就是颜色的容器,这个“容器”也是一种可视化的显现,我想我们也可以从另一个角度视察颜色——去除图象内容,仅显现差别颜色的值和他们的权重,比方下面如许星星点点像星空一样可视化计划:

《图象色彩提取》

一、罕见颜色量子化算法

1.1 中位切分法

中位切分算法首先把一切像素映射到RGB空间,在这个三维的空间里反复切分出子空间,末了将切分空间的像素求均值作为提取结果。支解区块时都挑选一切区块中最大(最长的边长最大,或体积最大,或像素最多)的区块,切割点应位于边方向上,使得支解后两个区块的像素各一半的位置,以上是为中位切分法。流程以下(引荐浏览:《Color Quantization》):

1.像素映射到RGB空间:

《图象色彩提取》

2.区块盘算:

《图象色彩提取》

3.中位切分:

《图象色彩提取》

4.反复切分:

《图象色彩提取》

5.盘算区块的均匀颜色:

《图象色彩提取》

这里引荐一个采纳中位切分法完成(JavaScript)的颜色量子化项目:Color Thief

1.2 八叉树算法

八叉树算法的核心理念是用八叉树来离别颜色空间,然后兼并恭弘=叶 恭弘节点来逐渐靠拢颜色(量子化),八叉树的诠释可参考《游戏场景治理的八叉树算法是如何的?》,症结就是下面这两幅图:

1.建立历程:

《图象色彩提取》

2.兼并恭弘=叶 恭弘节点:

《图象色彩提取》

详细的诠释可参考文章:《图片主题色提取算法小结》,作者还写了一个颜色量子化的node模块: A theme color extractor module for Node.js

1.3 K-Means聚类法

K均值聚类的头脑异常简朴,可分这几步:

  1. 拔取初始的K个质心;
  2. 根据距离质心的远近对一切样本举行分类;
  3. 从新盘算质心,推断是不是退出前提:

    • 两次质心的距离充足小视为满足退出前提;
    • 不退出则从新回到步骤2;

来看js的完成:

/*
colors: 一切样本
seeds: 初始质心
max_step: 最大迭代次数
*/
kMC(colors, seeds, max_step) {
    let iteration_count = 0;
    while (iteration_count++ < max_step) {
      // divide colors into different categories with duff's device
      classifyColor(colors, seeds);

      // compute center of category
      let len = colors.length;
      let hsl_count = [];
      let category;
      while (len--) {
        category = colors[len].category;
        // ......
      }
      
      // quit or not
      let flag = hsl_count.every((ele, index) => {
        // ......
      });
      if (flag) {
        break;
      }
    }
    console.log("KMC iteration " + iteration_count);
  }

二、简朴完成

2.1 大抵流程

  1. canvas读取当地图象,做恰当缩放;
  2. 统计颜色信息:颜色需要做量子化处置惩罚(Color Quantization),RGB空间中一共有255的三次方约1600多万种颜色,除以8能降采样到32000多种。RGB值组合为键值,统计每种颜色涌现的次数:
let r_key = Math.floor(r / 8) * 1000000;
let g_key = Math.floor(g / 8) * 1000;
let b_key = Math.floor(b / 8);
let key = r_one + g_one + b_one;
if(keys.indexOf(key)<0){
  // 未找到key,则新到场key
}else{
  // 找到则涌现次数加1
}
  1. 过滤颜色:过滤伶仃的颜色(涌现次数太少)和过亮过黑的颜色;
  2. K均值聚类:拔取涌现频次最高的K种颜色所谓初始值,由算法聚类出新的稳固的颜色中间;
  3. 盘算主要颜色和均值颜色;

2.2 试验结果

《图象色彩提取》

这张图的原始区分率是 1080 x 1800 ,缩放到canvas中区分率是 216 x 360 (缩放规则是牢固最大高度为360,按原始宽高比例缩放)。挑选颜色降采样的距离为 5,一共是提取了 6251 种颜色,过滤掉涌现次数小于 4 和过黑过亮的颜色后盈余 2555 种颜色。K均值聚类的K设为 6 ,终究迭代次数是 10 ,耗时 106ms

codepen的原始例子以下:

census color

这计划实行下来会有一些问题:

  • K均值种子点的拔取对结果的影响较大;
  • 盘算聚类中间的时刻不光是RGB三个值,还到场了颜色涌现次数这个值,所以K比较小时,新的聚类中间可以不会收敛到能干标装点颜色上,这和我们的视觉觉得是不一致的,然则假如挑选K为10,关于上面的图象是可以收敛到赤色的。

三、神经网络评分

这部份采纳了brain,它应当是简朴的BP神经网络。练习数据采纳的是图虫网的热点图片。现在带评分的图象数据库比较少,而且评分往往是综合的,搀杂了别的(构图,主题,光影,人物等)要素,难以星散出只与颜色相干的评分,所以我是根据本身的喜欢对练习数据举行了评分,所以结果会异常猛烈的靠近我个人的喜欢。
别的神经网络的输入项也是比较症结的,由于它必需要正确反应颜色相干的图象信息,我提取的是:

let info = {
  colorCount: (Math.log10(colorInfo.length)),
  average:0,
  variance: 0,
  top50Count: 0,
  top50Average: 0,
  top50Variance: 0,
  top20Count: 0,
  top20Average: 0,
  top20Variance: 0,
  top10Count: 0,
  top10Average: 0,
  top10Variance: 0,
  top5Count: 0,
  top5Average: 0,
  top5Variance: 0
};

数据分为四类,评分从高到低离别是:100,85,75,65。

四、革新

4.1 颜色空间的挑选

之前是采纳的RGB空间,三个冷冰冰的数字并不能让我们很好的区分差别颜色,因而这里我试着转换到HSL空间:色相(H)、饱和度(S)、明度(L),这三个颜色通道互相之间的叠加能获得形形色色的颜色,这个颜色空间险些包含了人类目力所能感知的一切颜色,是现在应用最广的颜色体系之一。
RGB和HSL的转换可参考《javascript HEX十六进制与RGB, HSL颜色的互相转换》

转换到HSL空间关于我们提取颜色的目的有以下优点:

  • 本来的RGB中三个值一样主要,关于HSL我们可以运用差别的参数离别去处置惩罚三个通道,比方关于色相可以浓密采样,关于明度和饱和度可以恰当希罕采样;
  • 关于差别颜色的掌握越发邃密正确,原始的RGB空间中我们很难推断两个差别颜色之间他们的RGB值关联,然则关于HSL我们只需关注色相就可以了(别的两个通道也很有效,只是这里挑选疏忽它们);

4.2 二叉树与indexOf

影响全部算法运转时候的症结步骤是颜色信息的统计,而统计环节中最耗时的是key的检测,存储key的容器长度会愈来愈长,采纳indexOf的体式格局会愈来愈耗时,试考证实绝大部份的时候都是消耗在这一步上。所以无妨尝尝查找二叉树如许的数据结构,二叉树的上风在于每次查找的时候会指数级下落,以此加快顺序运转。
然则,我用js完成这类数据结构的结果并不抱负,运转时候基础与indexOf一致,以至大部份时刻还会稍微多一点。我以为缘由在于:虽然每次查找反复key的时候削减了,然则每次新到场key的步骤变得庞杂了,而且indexOf()native code ,运转效力应当比我们本身完成的js代码高。综合起来看,在肯定的样本量区间,照样运用原生的indexOf效力更高,这个区间在本文指的是 1000~3000 种颜色,固然我照样置信当颜色更多的时刻,二叉树照样有它的上风的。我完成的代码以下:

二叉树前序/中序/后序遍历

4.3 duff’s device

这是个异常有用的技能(经由我屡次考证),觉得已离不开它了!

let len = colors.length;
let count = (len / 8) ^ 0;
let start = len % 8;
while (start--) {
  // do something
}
while (count--) {
  // do something  
}

测试结果:jsprof

4.4 隐约加快

对图象举行隐约可以削减颜色的品种,从而加快提取算法,这应当是可行的,然则我还没有到场到项目中,我探究的比较快,结果比较好的隐约算法的完成以下:

canvas blur

五、SVG与canvas动画

最最先只是想熟习react,结果到背面,项目的重心就完整倾向于算法和动画了。我以为React对SVG照样比较友爱的,种种动画属性都可以放到state中。个人觉得SVG动画相干于CSS的上风在于:越发天真,越发轻易完成庞杂动画结果,兼容性更好,底层优化更流通。
canvas动画的上风是比较流通,SVG动画在挪动端照样有许多肉眼可见的掉帧卡顿的,而且SVG会让HTML变得很大很乱,可以让有洁癖的你不舒服。

SVG halo animation

不管什么动画终究都照样归结于:数学,比方:

这个动画的难点在于随机的规划算法,症结在于碰撞的检测与碰撞后的挪动,实质依赖于多少和物理中的运动定律:

bubble chart

这个动画的难点在于找到一个奇异的数学公式,虽然我本身也不知道怎么回事,然则变更数学公式,有时刻就可以完成有规律的动画,而有规律再加上颜色,很大几率就是好的动画:

canvas wave

    原文作者:方泉水很甜
    原文地址: https://segmentfault.com/a/1190000009832996
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞