影象主題色的提取

liusGG發表於2018-10-18

工作時遇到一個需求:提取圖片主題色,通過某種對映關係,選取ui給出的對應顏色。腦海中浮現如果只是純前端如何實現呢?

一、思路與準備

利用canvas獲取影象畫素資訊,然後用某種演算法將主題顏色提取出來。

1.1 瞭解Canvas畫布真實畫素原理

MDN: 事實上,你可以直接通過getImageData,返回一個imageData物件,獲取場景畫素資料。

imageData物件包含下列幾個只讀屬性:

  • width:圖片寬度,單位是畫素
  • height:圖片高度,單位是畫素
  • dataUint8ClampedArray型別的一維陣列,包含著RGBA格式的整型資料,範圍在0至255之間(包括255)。

data屬性返回一個 Uint8ClampedArray,它可以被使用作為檢視初始畫素資料。每個畫素用4個 1 bytes值(按照紅,綠,藍和透明值的順序,"RGBA"格式) 來代表。每個顏色值部份用0至255來代表。每個部分被分配到一個在陣列內連續的索引,左上角畫素的紅色部分在陣列的索引0位置。畫素從左到右被處理,然後往下,遍歷整個陣列。 Uint8ClampedArray 包含高度 × 寬度 × 4 bytes資料,索引值從0到(高度×寬度×4)-1

1.2 瞭解中位切分法 (Median cut)

影象主題色的提取

中位切分法 / MMCQ演算法 是指的是 將色彩空間裡的顏色按照密集程度分組,先將整個 ColorSpace 視為一個整體A,然後通過計算顏色差值:

影象主題色的提取

找到 median point,然後切割成兩個分組A1 和 A2,然後再找到最大的一個組(比如A1),計算差值找到 median point, 繼續切割成A3,A4,現在我們有了三個分組(A2,A3,A4),繼續找到最大分組切割,直到達到所需的顏色數量 N。然後得到 N 個分組,這 N 個分組的 median point 的顏色值即為要求的顏色值。顏色比例即為 N 個分組的大小比值。

影象主題色的提取

其中color-thief庫就是基於中位切分法實現的。

Leptonica 作者在報告 Median-Cut Color Quantization 中總結了這一演算法存在的一些問題,其中主要問題是有可能存在某些條件下 VBox 體積很大但只包含少量畫素。解決的方法是,每次進行切分時,並不是對上一次切分得到的所有VBox進行切分,而是通過一個優先順序佇列進行排序,剛開始時這一佇列以VBox僅以VBox所包含的畫素數作為優先順序考量,當切分次數變多之後,將體積*包含畫素數作為優先順序。

除此之外,演算法中最重要的部分是統計色彩分佈直方圖。我們需要將三維空間中的任意一點對應到一維座標中的整數,這樣才能以最快地速度定位這一顏色。如果採用全部的24位資訊,那麼我們用於儲存直方圖的陣列長度至少要是224=16777216,既然是要提取顏色主題(或是顏色量化),我們可以將顏色由RGB各8位壓縮至5位,這樣陣列長度只有215=32768

// color-thief部分原始碼: 
var sigbits = 5,
    rshift = 8 - sigbits,
// get reduced-space color index for a pixel
function getColorIndex(r, g, b) {
    return (r << (2 * sigbits)) + (g << sigbits) + b;
}
function getHisto(pixels) {
    var histosize = 1 << (3 * sigbits),
        histo = new Array(histosize),
        index, rval, gval, bval;
    pixels.forEach(function(pixel) {
        rval = pixel[0] >> rshift;
        gval = pixel[1] >> rshift;
        bval = pixel[2] >> rshift;
        index = getColorIndex(rval, gval, bval);
        histo[index] = (histo[index] || 0) + 1;
    });
    return histo;
}
複製程式碼

參考:

Pixels and Palettes: Extracting Color Palettes From Images

Pixel_manipulation_with_canvas_By MDN

MMCQ演算法

相關文章