color_decomposition 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3a3e2459586c1089713d950211118369334dd380
4
+ data.tar.gz: 7febaebbff5ed6b25d45fff3b0a724d29ecf984a
5
+ SHA512:
6
+ metadata.gz: 786af0e7a8fb9d336f4be8aec8f6a873607ac98d150d5111576bf0f41691355f823f876dcd9b0e0793c44a1f49698c7f5b1a4315efe9019d2003b9cfa956a6e7
7
+ data.tar.gz: b5cf8c04d802782c02c262b1eb278e3453955503d5c2d684e7306b57c390d48cbcda6fa44dd8ddf2ea7663d19b0c5c6c09f52d082b84e6ef671a847300e296cc
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+ Style/Documentation:
4
+ Enabled: false
5
+ Style/FrozenStringLiteralComment:
6
+ Enabled: false
7
+ Metrics/AbcSize:
8
+ Enabled: false
9
+ Metrics/MethodLength:
10
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Jonas Bleyl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Color decomposition
2
+
3
+ <img align="left" hspace="20" src="http://i.imgur.com/PZpp3g5.gif" width="120">
4
+
5
+ A quadtree color decomposition algorithm that uses the CIELAB color space and the
6
+ CIEDE2000 color difference formula.
7
+
8
+ The generated quadtree structure contains the leaves that represent the highest node
9
+ levels containing a visually similar color for a given area.
10
+
11
+ ## Installation
12
+
13
+ This gem requires an installation of
14
+ [ImageMagick](https://legacy.imagemagick.org/script/download.php) `version 6`. Once this
15
+ is done you can install the gem:
16
+
17
+ ``` bash
18
+ gem install color_decomposition
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Generating the actual quadtree simply requires calling the `quadtree` method. This
24
+ method takes 2 parameters. The first being the path to the image and the second being
25
+ the color similarity level that the CIEDE2000 formula should use. The higher this value,
26
+ the more color loss will be allowed. This will allow the creation of larger leaf nodes
27
+ at the cost of color accuracy.
28
+
29
+ When comparing 2 colors, a CIEDE2000 value of `<= 1` will generally mean that the
30
+ difference between them will not be perceivable to the human eye.
31
+
32
+ ``` ruby
33
+ require 'color_decomposition'
34
+
35
+ quadtree = ColorDecomposition.quadtree('ruby.png', 1)
36
+ ```
37
+
38
+ This will return a quadtree object with a nested structure as shown below. Only leaf
39
+ nodes will have the RGB and CIELAB color values set.
40
+
41
+ ``` ruby
42
+ #<ColorDecomposition::Node:0x007fb707196f98
43
+ @child_nodes=
44
+ [#<ColorDecomposition::Node:0x007fb707196ef8
45
+ @child_nodes=nil,
46
+ @lab={:l=>0.0, :a=>0.0, :b=>0.0},
47
+ @rect={:left=>0, :top=>0, :right=>32, :bottom=>32},
48
+ @rgb={:r=>0, :g=>0, :b=>0}>,
49
+ #<ColorDecomposition::Node:0x007fb707196e80
50
+ @child_nodes=nil,
51
+ @lab={:l=>100.0, :a=>0.00526049995830391, :b=>-0.010408184525267927},
52
+ @rect={:left=>32, :top=>0, :right=>64, :bottom=>32},
53
+ @rgb={:r=>255, :g=>255, :b=>255}>,
54
+ #<ColorDecomposition::Node:0x007fb707196e30
55
+ @child_nodes=nil,
56
+ @lab={:l=>100.0, :a=>0.00526049995830391, :b=>-0.010408184525267927},
57
+ @rect={:left=>0, :top=>32, :right=>32, :bottom=>64},
58
+ @rgb={:r=>255, :g=>255, :b=>255}>,
59
+ #<ColorDecomposition::Node:0x007fb707196de0
60
+ @child_nodes=nil,
61
+ @lab={:l=>100.0, :a=>0.00526049995830391, :b=>-0.010408184525267927},
62
+ @rect={:left=>32, :top=>32, :right=>64, :bottom=>64},
63
+ @rgb={:r=>255, :g=>255, :b=>255}>],
64
+ @lab=nil,
65
+ @rect={:left=>0, :top=>0, :right=>64, :bottom=>64},
66
+ @rgb=nil>
67
+ ```
68
+
69
+ The color conversions and CIEDE2000 calculation can also be used on their own.
70
+
71
+ ``` ruby
72
+ require 'color_decomposition'
73
+
74
+ include ColorDecomposition
75
+
76
+ color1 = Color.new({r: 255, g: 120, b: 60})
77
+ puts color1.xyz # {:x=>48.77208180663368, :y=>35.01918603060906, :z=>8.46377233268254}
78
+ puts color1.lab # {:l=>65.76360001472788, :a=>47.86642591164642, :b=>55.61626679147632}
79
+
80
+ color2 = Color.new({r: 80, g: 49, b: 220})
81
+ puts Comparator.ciede2000(color1.lab, color2.lab) # 57.24131929494836
82
+ ```
83
+
84
+
85
+ ## Resources
86
+
87
+ * [Color space conversions paper.](http://sites.biology.duke.edu/johnsenlab/pdfs/tech/colorconversion.pdf)
88
+ * [sRGB to CIEXYZ transformation values and D65 standard.](http://web.archive.org/web/20110722134652/http://www.colour.org/tc8-05/Docs/colorspace/61966-2-1.pdf)
89
+ * [CIEDE2000 color-difference formula paper and test data.](http://www.ece.rochester.edu/~gsharma/ciede2000)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'rake/testtask'
2
+
3
+ task default: %w[test]
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs = ['lib']
7
+ t.warning = true
8
+ t.verbose = true
9
+ t.test_files = FileList['test/*_test.rb']
10
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'color_decomposition/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'color_decomposition'
9
+ spec.version = ColorDecomposition::VERSION
10
+ spec.authors = ['Jonas Bleyl']
11
+ spec.summary = 'Quadtree decomposition of images by color.'
12
+ spec.description = 'Create a quadtree by decomposing images by color using CIELAB.'
13
+ spec.homepage = 'https://github.com/jonasbleyl/color-decomposition'
14
+ spec.license = 'MIT'
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test)/})
17
+ end
18
+ spec.required_ruby_version = '~> 2.4'
19
+ spec.require_paths = ['lib']
20
+ spec.add_development_dependency 'bundler', '~> 1.13'
21
+ spec.add_development_dependency 'test-unit', '~> 3.1'
22
+ spec.add_development_dependency 'rake', '~> 12.0'
23
+ spec.add_dependency 'rmagick', '~> 2.16'
24
+ end
@@ -0,0 +1,59 @@
1
+ require 'matrix'
2
+
3
+ module ColorDecomposition
4
+ class Color
5
+ attr_reader :rgb
6
+
7
+ def initialize(rgb)
8
+ @rgb = rgb
9
+ end
10
+
11
+ def xyz
12
+ r = xyz_channel(@rgb[:r] / 255.0)
13
+ g = xyz_channel(@rgb[:g] / 255.0)
14
+ b = xyz_channel(@rgb[:b] / 255.0)
15
+
16
+ # sRGB D65 illuminant and 2 degrees observer values
17
+ s = Matrix[[0.4124, 0.3576, 0.1805],
18
+ [0.2126, 0.7152, 0.0722],
19
+ [0.0193, 0.1192, 0.9505]]
20
+
21
+ xyz = s * Matrix[[r], [g], [b]] * 100
22
+ { x: xyz[0, 0], y: xyz[1, 0], z: xyz[2, 0] }
23
+ end
24
+
25
+ def lab
26
+ xyz_to_lab(xyz)
27
+ end
28
+
29
+ private
30
+
31
+ def xyz_to_lab(xyz)
32
+ # CIEXYZ white point values (D65)
33
+ x = lab_channel(xyz[:x] / 95.047)
34
+ y = lab_channel(xyz[:y] / 100.000)
35
+ z = lab_channel(xyz[:z] / 108.883)
36
+
37
+ l = 116 * y - 16
38
+ a = 500 * (x - y)
39
+ b = 200 * (y - z)
40
+ { l: l.clamp(0, 100), a: a, b: b }
41
+ end
42
+
43
+ def xyz_channel(color)
44
+ if color > 0.04045
45
+ ((color + 0.055) / 1.055)**2.4
46
+ else
47
+ color / 12.92
48
+ end
49
+ end
50
+
51
+ def lab_channel(color)
52
+ if color > 0.008856
53
+ color**(1.0 / 3)
54
+ else
55
+ 7.787 * color + 16 / 116.0
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,88 @@
1
+ module ColorDecomposition
2
+ module Comparator
3
+ extend self
4
+
5
+ def ciede2000(lab1, lab2)
6
+ lch1, lch2 = to_lch(lab1, lab2)
7
+
8
+ l_bar = (lch1[:l] + lch2[:l]) / 2
9
+ c_bar = (lch1[:c] + lch2[:c]) / 2
10
+ h_bar = mean_hue(lch1, lch2)
11
+
12
+ l_delta = lch2[:l] - lch1[:l]
13
+ c_delta = lch2[:c] - lch1[:c]
14
+ h_delta = hue_angle(lch1, lch2)
15
+ o_delta = 30 * Math.exp(-((h_bar - 275) / 25)**2)
16
+
17
+ t = 1 - 0.17 * Math.cos(radians(h_bar - 30)) +
18
+ 0.24 * Math.cos(radians(2 * h_bar)) +
19
+ 0.32 * Math.cos(radians(3 * h_bar + 6)) -
20
+ 0.20 * Math.cos(radians(4 * h_bar - 63))
21
+
22
+ rc = 2 * Math.sqrt(c_bar**7 / (c_bar**7 + 25**7))
23
+ sl = 1 + 0.015 * (l_bar - 50)**2 / Math.sqrt(20 + (l_bar - 50)**2)
24
+ sc = 1 + 0.045 * c_bar
25
+ sh = 1 + 0.015 * c_bar * t
26
+ rt = -Math.sin(radians(2 * o_delta)) * rc
27
+
28
+ Math.sqrt((l_delta / sl)**2 + (c_delta / sc)**2 + (h_delta / sh)**2 +
29
+ rt * (c_delta / sc) * (h_delta / sh)).clamp(0, 100)
30
+ end
31
+
32
+ private
33
+
34
+ def to_lch(lab1, lab2)
35
+ c1_star = Math.sqrt(lab1[:a]**2 + lab1[:b]**2)
36
+ c2_star = Math.sqrt(lab2[:a]**2 + lab2[:b]**2)
37
+ c_bar_star = (c1_star + c2_star) / 2
38
+
39
+ g = 0.5 * (1 - Math.sqrt(c_bar_star**7 / (c_bar_star**7 + 25**7)))
40
+ [{ l: lab1[:l] }.merge(modified_hue(lab1, g)),
41
+ { l: lab2[:l] }.merge(modified_hue(lab2, g))]
42
+ end
43
+
44
+ def modified_hue(lab, g)
45
+ a = (1 + g) * lab[:a]
46
+ c = Math.sqrt(a**2 + lab[:b]**2)
47
+
48
+ h = lab[:b] != 0 || a != 0 ? degrees(Math.atan2(lab[:b], a)) : 0
49
+ h += 360 if h.negative?
50
+ { c: c, h: h }
51
+ end
52
+
53
+ def hue_angle(lch1, lch2)
54
+ h_diff = lch2[:h] - lch1[:h]
55
+ h = if (lch1[:c] * lch2[:c]).zero?
56
+ 0
57
+ elsif h_diff.abs <= 180
58
+ h_diff
59
+ elsif h_diff > 180
60
+ h_diff - 360
61
+ else
62
+ h_diff + 360
63
+ end
64
+ 2 * Math.sqrt(lch1[:c] * lch2[:c]) * Math.sin(radians(h) / 2)
65
+ end
66
+
67
+ def mean_hue(lch1, lch2)
68
+ h_sum = lch1[:h] + lch2[:h]
69
+ if (lch1[:c] * lch2[:c]).zero?
70
+ h_sum
71
+ elsif (lch1[:h] - lch2[:h]).abs <= 180
72
+ h_sum / 2
73
+ elsif (lch1[:h] - lch2[:h]).abs > 180 && h_sum < 360
74
+ (h_sum + 360) / 2
75
+ else
76
+ (h_sum - 360) / 2
77
+ end
78
+ end
79
+
80
+ def radians(num)
81
+ num * Math::PI / 180
82
+ end
83
+
84
+ def degrees(num)
85
+ num * 180 / Math::PI
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,35 @@
1
+ require 'rmagick'
2
+
3
+ module ColorDecomposition
4
+ class ImageReader
5
+ include Magick
6
+ attr_reader :height, :width
7
+
8
+ def initialize(path)
9
+ @image = ImageList.new(path)
10
+ @height = @image.rows
11
+ @width = @image.columns
12
+ end
13
+
14
+ def add_image_data(quadtree)
15
+ quadtree.base_nodes.each do |node|
16
+ pixels = export_pixel_data(node)
17
+ node.rgb = {
18
+ r: ((pixels[0] / 65_535.0) * 255).to_i,
19
+ g: ((pixels[1] / 65_535.0) * 255).to_i,
20
+ b: ((pixels[2] / 65_535.0) * 255).to_i
21
+ }
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def export_pixel_data(node)
28
+ @image.export_pixels(
29
+ node.rect[:left], node.rect[:top],
30
+ node.rect[:bottom] - node.rect[:top],
31
+ node.rect[:right] - node.rect[:left], 'RGB'
32
+ )
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,68 @@
1
+ require 'color_decomposition/color/color'
2
+ require 'color_decomposition/color/comparator'
3
+
4
+ module ColorDecomposition
5
+ class Node
6
+ include Comparator
7
+ attr_accessor :rgb
8
+ attr_reader :rect, :child_nodes
9
+
10
+ def initialize(rect, rgb = nil, lab = nil, child_nodes = nil)
11
+ @rect = rect
12
+ @rgb = rgb
13
+ @lab = lab
14
+ @child_nodes = child_nodes
15
+ end
16
+
17
+ def leaf?
18
+ @child_nodes.nil?
19
+ end
20
+
21
+ def child_leaves?
22
+ @child_nodes.all?(&:leaf?)
23
+ end
24
+
25
+ def split
26
+ center_x = (rect[:left] + rect[:right]) * 0.5
27
+ center_y = (rect[:top] + rect[:bottom]) * 0.5
28
+ @child_nodes = [
29
+ new_child_node(rect[:left], rect[:top], center_x, center_y),
30
+ new_child_node(center_x, rect[:top], rect[:right], center_y),
31
+ new_child_node(rect[:left], center_y, center_x, rect[:bottom]),
32
+ new_child_node(center_x, center_y, rect[:right], rect[:bottom])
33
+ ]
34
+ end
35
+
36
+ def merge
37
+ @rgb = @child_nodes[0].rgb
38
+ @lab = @child_nodes[0].lab
39
+ @child_nodes = nil
40
+ end
41
+
42
+ def similar?(amount)
43
+ v1 = ciede2000(@child_nodes[0].lab, @child_nodes[1].lab)
44
+ v2 = ciede2000(@child_nodes[2].lab, @child_nodes[3].lab)
45
+ v3 = ciede2000(@child_nodes[0].lab, @child_nodes[2].lab)
46
+ v1 < amount && v2 < amount && v3 < amount
47
+ end
48
+
49
+ def lab
50
+ @lab ||= Color.new(@rgb).lab
51
+ end
52
+
53
+ def rgb_hex
54
+ "##{hex(rgb[:r])}#{hex(rgb[:g])}#{hex(rgb[:b])}"
55
+ end
56
+
57
+ private
58
+
59
+ def new_child_node(left, top, right, bottom)
60
+ Node.new(left: left.floor, top: top.floor,
61
+ right: right.ceil, bottom: bottom.ceil)
62
+ end
63
+
64
+ def hex(num)
65
+ format('%02X', num)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,60 @@
1
+ require 'color_decomposition/quadtree/node'
2
+
3
+ module ColorDecomposition
4
+ class Quadtree
5
+ attr_reader :root
6
+
7
+ def initialize(width, height)
8
+ @root = Node.new(left: 0, top: 0, right: width, bottom: height)
9
+ end
10
+
11
+ def base_nodes
12
+ generate_to_base(nodes = [], max_level)
13
+ nodes
14
+ end
15
+
16
+ def generate_similarity_tree(similarity)
17
+ level = max_level - 1
18
+ level.times do
19
+ nodes_from_level(nodes = [], level)
20
+ nodes.each do |node|
21
+ node.merge if node.child_leaves? && node.similar?(similarity)
22
+ end
23
+ level -= 1
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def nodes_from_level(nodes, desired_level, node = @root, level = 0)
30
+ if level == desired_level
31
+ nodes.push(node)
32
+ else
33
+ unless node.leaf?
34
+ node.child_nodes.each do |inner_node|
35
+ nodes_from_level(nodes, desired_level, inner_node, level + 1)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ def generate_to_base(nodes, desired_level, node = @root, level = 0)
42
+ if level == desired_level
43
+ nodes.push(node)
44
+ else
45
+ node.split if node.leaf?
46
+ node.child_nodes.each do |inner_node|
47
+ generate_to_base(nodes, desired_level, inner_node, level + 1)
48
+ end
49
+ end
50
+ end
51
+
52
+ def max_level
53
+ level = 0
54
+ num = [@root.rect[:right] - @root.rect[:left],
55
+ @root.rect[:bottom] - @root.rect[:top]].max
56
+ level += 1 while num / 2**(level + 1) >= 1
57
+ level
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module ColorDecomposition
2
+ VERSION = '0.0.1'.freeze
3
+ end
@@ -0,0 +1,21 @@
1
+ require 'color_decomposition/quadtree/quadtree'
2
+ require 'color_decomposition/image/image_reader'
3
+ require 'color_decomposition/version'
4
+
5
+ module ColorDecomposition
6
+ module_function
7
+
8
+ def quadtree(path, similarity)
9
+ unless similarity.between?(0, 100)
10
+ raise ArgumentError, 'Similarity value must be between 0 and 100'
11
+ end
12
+ image = ImageReader.new(path)
13
+ puts 'Generating initial quadtree structure'
14
+ quadtree = Quadtree.new(image.width, image.height)
15
+ image.add_image_data(quadtree)
16
+ puts 'Checking quadtree levels'
17
+ quadtree.generate_similarity_tree(similarity)
18
+ puts 'Quadtree complete'
19
+ quadtree.root
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: color_decomposition
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jonas Bleyl
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: test-unit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rmagick
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.16'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.16'
69
+ description: Create a quadtree by decomposing images by color using CIELAB.
70
+ email:
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - ".gitignore"
76
+ - ".rubocop.yml"
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - color_decomposition.gemspec
82
+ - lib/color_decomposition.rb
83
+ - lib/color_decomposition/color/color.rb
84
+ - lib/color_decomposition/color/comparator.rb
85
+ - lib/color_decomposition/image/image_reader.rb
86
+ - lib/color_decomposition/quadtree/node.rb
87
+ - lib/color_decomposition/quadtree/quadtree.rb
88
+ - lib/color_decomposition/version.rb
89
+ homepage: https://github.com/jonasbleyl/color-decomposition
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '2.4'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.6.11
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Quadtree decomposition of images by color.
113
+ test_files: []