palettor

package module
v0.0.0-...-cc458b0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2020 License: MIT Imports: 8 Imported by: 0

README

Palettor

Yet another way to extract dominant colors from an image using k-means clustering.

Build Status GoDoc Coverage

Tests

Unit tests
make test
Benchmarks
make benchmark

Usage as a library

go get -u github.com/mccutchen/palettor
package main

import (
    "image"
    _ "image/gif"
    _ "image/jpeg"
    _ "image/png"
    "log"
    "os"

    "github.com/mccutchen/palettor"
    "github.com/nfnt/resize"
)

func main() {
    // Read an image from STDIN
    originalImg, _, err := image.Decode(os.Stdin)
    if err != nil {
        log.Fatal(err)
    }

    // Reduce it to a manageable size
    img := resize.Thumbnail(200, 200, originalImg, resize.Lanczos3)

    // Extract the 3 most dominant colors, halting the clustering algorithm
    // after 100 iterations if the clusters have not yet converged.
    k := 3
    maxIterations := 100
    palette, err := palettor.Extract(k, maxIterations, img)

    // Err will only be non-nil if k is larger than the number of pixels in the
    // input image.
    if err != nil {
        log.Fatalf("image too small")
    }

    // Palette is a mapping from color to the weight of that color's cluster,
    // which can be used as an approximation for that color's relative
    // dominance
    for _, color := range palette.Colors() {
        log.Printf("color: %v; weight: %v", color, palette.Weight(color))
    }

    // Example output:
    // 2015/07/19 10:27:52 color: {44 120 135}; weight: 0.17482142857142857
    // 2015/07/19 10:27:52 color: {140 103 150}; weight: 0.39558035714285716
    // 2015/07/19 10:27:52 color: {189 144 118}; weight: 0.42959821428571426
}

The palettor command line application

An example command line application is provided, which reads an input image and either a) overlays the dominant palette on the bottom of the image or b) generates a JSON representation of the dominant color palette:

$ go get -u github.com/mccutchen/palettor/cmd/palettor

$ palettor -help
Usage: palettor [OPTIONS] [INPUT]

  -json
        Output color palette in JSON format
  -k int
        Palette size (default 3)
  -max int
        Maximum k-means iterations (default 500)

$ cat /Library/Desktop\ Pictures/Beach.jpg | palettor -json | jq .
[
  {
    "color": {
      "R": 70,
      "G": 134,
      "B": 154,
      "A": 255
    },
    "weight": 0.19080357142857143
  },
  {
    "color": {
      "R": 175,
      "G": 187,
      "B": 183,
      "A": 255
    },
    "weight": 0.26852678571428573
  },
  {
    "color": {
      "R": 210,
      "G": 208,
      "B": 199,
      "A": 255
    },
    "weight": 0.5406696428571428
  }
]

Documentation

Overview

Package palettor provides a way to extract the color palette from an image using k-means clustering.

Example
// cat testdata/example.png | base64
var exampleData = []byte("iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAACMGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BY29ybiB2ZXJzaW9uIDQuNS44PC94bXA6Q3JlYXRvclRvb2w+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjU8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyPC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CkPIGwAAAAAUSURBVAgdY/zPAAb/QTQThE2IBACKLAMB3J9gzQAAAABJRU5ErkJggg==")

decoder := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(exampleData))
img, err := png.Decode(decoder)
if err != nil {
	log.Fatal(err)
}

// For a real-world use case, it's best to use something like
// github.com/nfnt/resize to transform images into a manageable size before
// extracting colors:
//
//     img = resize.Thumbnail(200, 200, img, resize.Lanczos3)
//
// In this example, we're already starting from a tiny image.

// Extract the 3 most dominant colors, halting the clustering algorithm
// after 100 iterations if the clusters have not yet converged.
palette, _ := Extract(3, 100, img)

// Palette is a mapping from color to the weight of that color's cluster,
// which can be used as an approximation for that color's relative
// dominance
for _, color := range palette.Colors() {
	fmt.Printf("color: %v; weight: %v\n", color, palette.Weight(color))
}

// Example output:
// color: {255 0 0 255}; weight: 0.25
// color: {255 255 255 255}; weight: 0.25
// color: {0 0 0 255}; weight: 0.5
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ColorEq

func ColorEq(th uint32, a, b color.Color) bool

ColorEq ...

func ColorsToImage

func ColorsToImage(src []color.Color) image.Image

ColorsToImage ...

func ColorsXor

func ColorsXor(th uint32, src, space []color.Color) []color.Color

ColorsXor ...

func GetColors

func GetColors(img image.Image) []color.Color

GetColors from an image

func ReadImage

func ReadImage(path string) (image.Image, error)

ReadImage ...

func WriteImage

func WriteImage(path string, img image.Image) error

WriteImage ...

Types

type Entry

type Entry struct {
	Color  color.Color `json:"color"`
	Weight float64     `json:"weight"`
}

Entry is a color and its weight in a Palette

type Palette

type Palette struct {
	// contains filtered or unexported fields
}

A Palette represents the dominant colors extracted from an image, as a mapping from color to the weight of that color's cluster. The weight can be used as an approximation for that color's relative dominance in an image.

func ClusterColors

func ClusterColors(k, maxIterations int, colors []color.Color) (*Palette, error)

ClusterColors finds k clusters in the given colors using the "standard" k-means clustering algorithm. It returns a Palette, after running the algorithm up to maxIterations times.

Note: in terms of the standard algorithm1, an observation in this implementation is simply a color, and we use the RGB channels as Euclidean coordinates for the purposes of finding the distance between two colors.

func Extract

func Extract(k, maxIterations int, img image.Image) (*Palette, error)

Extract finds the k most dominant colors in the given image using the "standard" k-means clustering algorithm. It returns a Palette, after running the algorithm up to maxIterations times.

func (*Palette) Colors

func (p *Palette) Colors() []color.Color

Colors returns a slice of the colors that comprise a Palette.

func (*Palette) Converged

func (p *Palette) Converged() bool

Converged returns a bool indicating whether a stable set of dominant colors was found before the maximum number of iterations was reached.

func (*Palette) Count

func (p *Palette) Count() int

Count returns the number of colors in a Palette.

func (*Palette) Entries

func (p *Palette) Entries() []Entry

Entries returns a slice of Entry structs, sorted by weight

func (*Palette) Iterations

func (p *Palette) Iterations() int

Iterations returns the number of iterations required to extract the colors of a Palette.

func (*Palette) Weight

func (p *Palette) Weight(c color.Color) float64

Weight returns the weight of a color in a Palette as a float in the range [0, 1], or 0 if a given color is not found.

type PaletteCentroid

type PaletteCentroid struct {
	// contains filtered or unexported fields
}

PaletteCentroid ...

func ExtractByCentroids

func ExtractByCentroids(th int, img image.Image, centroids map[string][]color.Color) (*PaletteCentroid, error)

ExtractByCentroids ...

func (*PaletteCentroid) Colors

func (p *PaletteCentroid) Colors() []string

Colors returns a slice of the colors that comprise a Palette.

func (*PaletteCentroid) Weight

func (p *PaletteCentroid) Weight(c string) float64

Weight returns the weight of a color in a Palette as a float in the range [0, 1], or 0 if a given color is not found.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL