คู่มือเครื่องมือ

วิธีดึงพาเลตสีจากรูปภาพ

อ่าน 10 นาที

Every photograph is a color argument. The golden hour shot of a Kyoto temple says something specific about warmth and stillness. The moody, desaturated editorial from a fashion magazine conveys restraint and tension. The vibrant street photography from Havana asserts energy and joy. Extracting a color palette from an image is the process of translating that visual argument into a set of hex values you can use in a design.

The practical applications are everywhere: building a brand identity from a mood board image, matching a website's palette to a product photograph, creating presentation slides that harmonize with a keynote cover image, or generating dynamic UI themes from user-uploaded photos. Understanding how the extraction algorithms work — and how to control them — determines whether you get a palette that genuinely reflects the image's visual character or a list of arbitrary dominant pixels.


Why Extract Colors from Images

The most compelling reason to extract colors from an image rather than choose them independently is visual coherence. Colors that appear together in nature or photography have been filtered through real-world physics — light conditions, material properties, atmospheric perspective. They tend to relate to each other in ways that feel balanced and believable.

When a designer pulls palette values from an image, they inherit those physical relationships for free. A portrait shot in golden-hour light will yield a palette of warm ambers, soft corals, and long shadows — colors that work together because they existed together in the same light.

Additional use cases include:

Brand identity from mood board images: Art directors often start brand exploration with photography that captures the desired feeling. Extracting dominant colors from the curated reference images gives the palette a concrete starting point rooted in the visual direction.

UI theming from product photos: E-commerce sites that generate adaptive UI colors from product images create a stronger visual connection between the interface and the merchandise. A page featuring a forest-green backpack automatically shifts to green-dominant accent colors.

Accessible palette building: Starting from a photographic source and then adjusting extracted colors for WCAG contrast is often faster than constructing an accessible palette from scratch, because the source image has already established a coherent hue family.

Motion and video work: Video color grading involves matching a specific look established by reference images. Extracting the palette from a reference frame and applying it as a lut-like target accelerates the grading process.


Color Quantization Algorithms

An image with millions of pixels might contain hundreds of thousands of distinct colors. Extraction means reducing this color space to a small, representative set — typically 5 to 12 colors. This is the quantization problem: finding the best k representative colors from an arbitrarily large set.

K-Means Clustering

K-means is the most widely used quantization algorithm for palette extraction. The process:

  1. Randomly initialize k cluster centroids in 3D color space (R, G, B dimensions).
  2. Assign every pixel to its nearest centroid by Euclidean distance.
  3. Recalculate each centroid as the mean of all pixels assigned to it.
  4. Repeat steps 2–3 until centroids stop moving significantly (convergence).
  5. The final centroids are the extracted palette colors.

The strengths of k-means are that it converges to locally optimal solutions and produces perceptually distinct cluster centers. Its weaknesses are sensitivity to initialization (different random starts can produce different results), computational cost for large images, and a tendency to produce similar colors when the image has a strong dominant hue — you might get six shades of blue from an ocean photograph rather than the few accent colors that make it interesting.

In practice: k-means is the algorithm behind most online palette extractors, Python's colorgram library, and design tool color pickers. Running it multiple times and taking the most visually distinct result (or using k-means++ initialization for more consistent starts) produces better results than a single run.

Median Cut

Median cut was one of the earliest palette quantization algorithms, introduced by Paul Heckbert in 1982. The process:

  1. Find the axis (R, G, or B) along which the pixel colors have the greatest range.
  2. Sort pixels along that axis and split them at the median point into two buckets.
  3. Repeat this split recursively until you have k buckets.
  4. For each bucket, compute the representative color (usually the mean or the centroid).

Median cut is fast, deterministic (unlike k-means), and handles uniformly distributed color distributions well. It is less accurate than k-means for images with complex, non-uniform color distributions — it can produce redundant colors in dominant regions while missing subtle accent colors in smaller areas.

In practice: Median cut is used in contexts where speed matters more than palette accuracy: real-time video processing, browser-side extraction in older implementations, and image processing pipelines where determinism is required.

Octree Quantization

Octree quantization builds a tree structure where the root represents the full RGB color cube and each level subdivides it into 8 children (hence octree). Pixels are inserted into the tree, and when the node count exceeds k, the algorithm merges the nodes with the fewest pixels.

The result is a palette that tends to allocate more representative colors to regions with many pixels and fewer to sparse regions — which typically produces palettes that are dominated by the visually largest areas of the image.

In practice: GIF encoding uses octree quantization because GIF is limited to 256 colors and needs a fast, reliable reduction algorithm. It is also used in Java's built-in BufferedImage color quantization.

Perceptual vs. Uniform Color Space Quantization

All three algorithms above operate in RGB space, which is not perceptually uniform. A cluster centroid that is numerically equidistant from two colors in RGB space may appear much closer to one of them perceptually.

More sophisticated implementations run k-means in LAB or OKLCH color space, where Euclidean distance corresponds more closely to perceived color difference. This produces palettes where the extracted colors feel more visually distinct from each other, even if they are numerically closer in RGB.

When evaluating extracted palettes, converting the results to OKLCH and checking that their hue, lightness, and chroma values are meaningfully different is a fast quality check. Use ColorFYI's Color Converter to inspect extracted hex values in OKLCH space.


Online Extraction Tools

Several online tools provide image-to-palette extraction without requiring code:

Adobe Color (color.adobe.com)

Adobe Color's "Extract Theme" feature uploads an image and applies k-means clustering to extract a 5-color palette. The interface lets you choose extraction modes: Colorful (maximizes hue variety), Bright (prioritizes light colors), Muted (de-emphasizes saturated colors), Deep (emphasizes darker tones), and Dark (focuses on shadow regions).

The extracted palette integrates directly into Adobe Creative Cloud libraries, making it useful for design teams already in the Adobe ecosystem.

Coolors

Coolors provides image upload with automatic extraction. Its strength is the post-extraction workflow: once colors are extracted, the interface lets you lock individual colors, swap others, adjust individual values, and export in multiple formats (CSS, SCSS, SVG, PNG, PDF).

Canva Color Palette Generator

Canva's extractor is browser-based and client-side — the image is not uploaded to a server. It returns a 5-color palette with hex values that can be directly applied to Canva designs or copied to clipboard.

Using ColorFYI for Palette Refinement

After extracting a palette from an image using any tool, ColorFYI's Palette Generator is useful for generating complementary or analogous variations from an extracted anchor color. The Color Converter lets you inspect extracted colors in HSL and OKLCH to understand their perceptual relationships.


Programmatic Extraction

For automated workflows — bulk processing, server-side theming, or building your own extraction tool — programmatic approaches give you full control over algorithm parameters.

Python: colorgram

colorgram is a Python library that extracts colors from images using a variant of k-means:

import colorgram

# Extract 6 most prominent colors from an image
colors = colorgram.extract("photo.jpg", 6)

for color in colors:
    r, g, b = color.rgb
    # Convert to hex
    hex_code = f"#{r:02X}{g:02X}{b:02X}"
    proportion = color.proportion  # Fraction of image covered by this color
    print(f"{hex_code}{proportion:.1%}")

color.proportion tells you what fraction of the image's pixels belonged to this color cluster, which lets you rank colors by visual dominance rather than just returning them arbitrarily.

Python: Pillow + k-means (Custom)

For more control over the algorithm, use Pillow to load the image and scikit-learn for k-means:

from PIL import Image
import numpy as np
from sklearn.cluster import KMeans

def extract_palette(image_path, n_colors=6, sample_size=10000):
    img = Image.open(image_path).convert("RGB")

    # Resize for performance: work on a downsampled version
    img.thumbnail((200, 200))
    pixels = np.array(img).reshape(-1, 3)

    # Sample for large images
    if len(pixels) > sample_size:
        indices = np.random.choice(len(pixels), sample_size, replace=False)
        pixels = pixels[indices]

    # Run k-means with k-means++ initialization
    kmeans = KMeans(n_clusters=n_colors, init="k-means++", n_init=10, random_state=42)
    kmeans.fit(pixels)

    # Convert cluster centers to hex
    colors = []
    for center in kmeans.cluster_centers_:
        r, g, b = [int(c) for c in center]
        hex_code = f"#{r:02X}{g:02X}{b:02X}"
        colors.append(hex_code)

    return colors

palette = extract_palette("photo.jpg", n_colors=6)
print(palette)
# ['#2C3E50', '#E67E22', '#F39C12', '#8E44AD', '#3498DB', '#ECF0F1']

The n_init=10 parameter runs k-means 10 times with different initializations and picks the best result — this significantly reduces the chance of ending up in a poor local minimum.

JavaScript: node-vibrant

node-vibrant is the most widely used JavaScript palette extractor, with both Node.js and browser versions. It uses a custom quantization algorithm inspired by Android's Palette API:

import Vibrant from "node-vibrant";

const palette = await Vibrant.from("photo.jpg").getPalette();

// Vibrant returns named swatches, not just an array
const colors = {
  vibrant: palette.Vibrant?.hex,       // The most vivid color
  darkVibrant: palette.DarkVibrant?.hex,
  lightVibrant: palette.LightVibrant?.hex,
  muted: palette.Muted?.hex,
  darkMuted: palette.DarkMuted?.hex,
  lightMuted: palette.LightMuted?.hex
};

console.log(colors);
// { vibrant: '#E8A020', darkVibrant: '#2C5AA0', lightVibrant: '#F0C878', ... }

The swatch naming convention (Vibrant, DarkVibrant, Muted) maps directly to common UI color roles: vibrant colors for accents and CTAs, dark colors for text and backgrounds, muted colors for secondary elements.

Browser-Side Extraction with Canvas API

For client-side extraction without a library:

function extractDominantColor(imgElement) {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  canvas.width = 50;  // Small size for performance
  canvas.height = 50;
  ctx.drawImage(imgElement, 0, 0, 50, 50);

  const data = ctx.getImageData(0, 0, 50, 50).data;
  let r = 0, g = 0, b = 0, count = 0;

  for (let i = 0; i < data.length; i += 4) {
    // Skip near-white and near-black pixels (often backgrounds)
    const brightness = (data[i] + data[i+1] + data[i+2]) / 3;
    if (brightness > 20 && brightness < 235) {
      r += data[i];
      g += data[i+1];
      b += data[i+2];
      count++;
    }
  }

  r = Math.round(r / count);
  g = Math.round(g / count);
  b = Math.round(b / count);

  return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
}

This is a simple mean-color approach rather than true clustering — it gives a single dominant color, not a full palette. For a full palette in the browser, use node-vibrant's browser build or a Canvas-based k-means implementation.


Using Extracted Palettes in Design

Extracting raw colors from an image is the beginning, not the end. The extracted values require curation and adjustment before they become a usable design palette.

Audit for Perceptual Distinction

Run extracted colors through ColorFYI's Color Converter and check their OKLCH values. Colors with similar hue and lightness values are visually redundant — they may look different in the image context but will appear nearly identical on UI elements. Cull redundant values and keep the set to 5–8 colors with clear perceptual differences.

Check Contrast Before Committing

Raw extracted colors may not meet WCAG contrast requirements for text use. Before assigning an extracted color as a text color or button background, verify it produces adequate contrast against its intended pairing. Adjust lightness in OKLCH space (which preserves hue and saturation) to reach the required 4.5:1 ratio for normal text without dramatically changing the visual character.

Identify Roles, Not Just Values

Assign each extracted color a semantic role: background, surface, primary text, secondary text, accent, and danger/success/warning. An extracted palette from a landscape photo might yield a deep forest green #1A4A2E (good for primary text on light backgrounds), a warm sand #D4B896 (good for surface colors), and a sky blue #6BAED6 (good for accents and links).

Extend the Palette with Shades

Extracted colors are typically single values — they do not include the lighter and darker variants needed for hover states, disabled states, and depth. Use ColorFYI's Palette Generator to generate complementary harmonics from an extracted anchor color, building a complete working palette from the photographic starting point.


Common Pitfalls

Extracting from JPEG artifacts: JPEG compression introduces color noise, especially in smooth gradients. The extractor picks up compression block colors rather than the intended image colors. Use PNG or high-quality JPEG sources (quality 90+) for palette extraction.

Ignoring the proportion values: An extractor might return a bright red as one of six colors, but if that red covers only 0.3% of the image (a small detail), using it as the primary brand color misrepresents the image's visual weight. Weight extracted colors by their proportion values and prefer colors that cover significant image area.

Over-representing backgrounds: Wide, low-saturation backgrounds (white walls, overcast skies, neutral floors) tend to dominate k-means results because they cover the most pixels. Many extractors offer a background-ignore mode, or you can crop the image to focus on the subject before extracting.

Forgetting the image context: Extracted colors exist in relationship to each other in the original image, viewed against its specific lighting and surroundings. Isolated on a white interface background, they may look different — often more saturated or lighter than expected. Always evaluate extracted colors in your target design context, not just as swatches.


Key Takeaways

  • Color extraction reduces an image's millions of pixel colors to a representative set using quantization algorithms. The three dominant approaches are k-means clustering, median cut, and octree quantization, each with distinct tradeoffs between accuracy, speed, and determinism.
  • K-means clustering with k-means++ initialization produces the most perceptually distinct palette for general photography, especially when run multiple times to avoid poor local minima.
  • Running quantization in LAB or OKLCH color space rather than RGB produces palettes where extracted colors are more perceptually distinct — numerically equidistant colors in OKLCH look more equally different to the human eye.
  • colorgram (Python) and node-vibrant (JavaScript) are the standard library choices for programmatic extraction, with node-vibrant offering named swatches that map directly to common UI color roles.
  • After extraction, audit colors for perceptual redundancy, verify WCAG contrast requirements, assign semantic roles, and extend single values to shade scales using tools like ColorFYI's Palette Generator.
  • Common pitfalls include over-representing large neutral backgrounds, extracting from compressed JPEG artifacts, ignoring proportion values, and failing to evaluate extracted colors in the target design context.

สีที่เกี่ยวข้อง

แบรนด์ที่เกี่ยวข้อง

เครื่องมือที่เกี่ยวข้อง