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 +7 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +89 -0
- data/Rakefile +10 -0
- data/color_decomposition.gemspec +24 -0
- data/lib/color_decomposition/color/color.rb +59 -0
- data/lib/color_decomposition/color/comparator.rb +88 -0
- data/lib/color_decomposition/image/image_reader.rb +35 -0
- data/lib/color_decomposition/quadtree/node.rb +68 -0
- data/lib/color_decomposition/quadtree/quadtree.rb +60 -0
- data/lib/color_decomposition/version.rb +3 -0
- data/lib/color_decomposition.rb +21 -0
- metadata +113 -0
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
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
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,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,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: []
|