ph 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Makefile +3 -0
  4. data/README.md +60 -0
  5. data/lib/ph.rb +18 -2
  6. data/ph.gemspec +1 -1
  7. data/spec/ph_spec.rb +22 -20
  8. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88a7e900bca90ab2c70029559c46848add5f8384a2c60040f012b1ac16691024
4
- data.tar.gz: 4f38f845987a7c33e6d8adb70766e0ea0a0f9758a0efe0e01655370f488f0b96
3
+ metadata.gz: 24b368462e37a0884ab35c35b3fee219c3463e051c4b51a543678412938c46e2
4
+ data.tar.gz: 6e91f21c7e6c1d59259b5eb45e67b4c6e6716346d2c1389ca6a221d80fe216b3
5
5
  SHA512:
6
- metadata.gz: 47c53e0c8a34d0a5c1cbde470000b5de32a246dae9d3f15582ed024b9aaed938fdfcb8b141d5ec845b505765a2ccbab1b46f31b6173886d00c3ff3fcfc1fd7e2
7
- data.tar.gz: 76d82783e82eb7f8d321a79dd21e6a72cafc5014381a6498dcb217f3a29c3c9ab3f1ec9fbf8b4099e31677e1919b4ee1f836e10f520c574a966f06c3762dea86
6
+ metadata.gz: afb8a6f5f61b52a041934f1bb71764b6067665f8f0b505f8772d6a3a11d25565e313d1cb03fb3ff77ab436be379353275fe163241238f0b145c94eb074334e07
7
+ data.tar.gz: e2eeeb235206cc887f3f303702faf11443f8b3e5127fdcd77c21fa6477847bf29ee02ad24a2c64133e74d784f0a5252288ab896a85a4e155a506c14d8e1b7918
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Makefile CHANGED
@@ -9,5 +9,8 @@ build:
9
9
  publish: build
10
10
  gem push *.gem
11
11
 
12
+ console:
13
+ irb -Ilib -rph
14
+
12
15
  test:
13
16
  ruby -Ilib:spec spec/*_spec.rb
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # PH
2
+ _Perceptual Hashing_
3
+
4
+ ## Install
5
+
6
+ ```bash
7
+ gem install ph
8
+ ```
9
+
10
+ ## Usage
11
+
12
+ `PH` Generates a perceptual hash from an array of pixels.
13
+ The way you get that pixel data is up to you. Different techniques can shield different values.
14
+ Hashes exist on a similar space but different reads could yield different (subtle) hashes.
15
+
16
+ ### Distance
17
+
18
+ Since hashes exist on a metric space you can measure how far a hash is from another.
19
+ You can use the hamming gem for calculations if needed
20
+
21
+ ```ruby
22
+ Hamming.distance(hash_a, hash_b)
23
+
24
+ # You can also transform hashes based on your storage:
25
+ Hamming.vector_to_hash(hash)
26
+ Hamming.hash_to_vector(vector)
27
+ ```
28
+
29
+ ### Vips
30
+
31
+ ```ruby
32
+ size = 64
33
+ img = Vips::Image.new_from_file(file)
34
+ width, height = img.width, img.height
35
+ w_scale, v_scale = size.fdiv(width), size.fdiv(height)
36
+
37
+ img = img
38
+ .resize(w_scale, vscale: v_scale)
39
+ .colourspace(:grey16)
40
+
41
+ pixels_2d = img.to_a.map(&:flatten)
42
+
43
+ PH.hash(pixels_2d)
44
+ # => "859091ce633aaebb"
45
+ ```
46
+
47
+ ### RMagick
48
+
49
+ ```ruby
50
+ img = Magick::ImageList.new(file)
51
+ size = 64
52
+ img = img
53
+ .scale(size, size)
54
+ .dispatch(0, 0, size, size, "I")
55
+ .each_slice(size)
56
+ .to_a
57
+
58
+ PH.new(img).vector
59
+ # => [1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1]
60
+ ```
data/lib/ph.rb CHANGED
@@ -3,9 +3,25 @@
3
3
  class PH
4
4
  attr_reader :pixels, :size
5
5
 
6
- def initialize(pixels_2d, size: 64)
6
+ NotGreyscaleError = Class.new(StandardError)
7
+ IncorrectDimensionsError = Class.new(StandardError)
8
+
9
+ class << self
10
+ def hash(pixels_2d)
11
+ new(pixels_2d).hash
12
+ end
13
+
14
+ def vector(pixels_2d)
15
+ new(pixels_2d).vector
16
+ end
17
+ end
18
+
19
+ def initialize(pixels_2d)
7
20
  @pixels = pixels_2d
8
- @size = size
21
+ @size = pixels_2d.size
22
+
23
+ raise NotGreyscaleError if pixels_2d.flatten.count != @size**2
24
+ raise IncorrectDimensionsError if !(Math.sqrt(size) % 8).zero?
9
25
  end
10
26
 
11
27
  def hash
data/ph.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "ph"
5
- s.version = "0.0.1"
5
+ s.version = "0.1.0"
6
6
  s.summary = "Perceptual Hashing"
7
7
  s.authors = ["elcuervo"]
8
8
  s.licenses = %w[MIT]
data/spec/ph_spec.rb CHANGED
@@ -4,30 +4,32 @@ describe PH do
4
4
  let(:file) { "spec/image.jpg" }
5
5
  let(:size) { 64 }
6
6
 
7
- before do
8
- img = Vips::Image.new_from_file(file)
9
- width, height = img.width, img.height
10
- w_scale, v_scale = size.fdiv(width), size.fdiv(height)
7
+ describe "hashing an image" do
8
+ before do
9
+ img = Vips::Image.new_from_file(file)
10
+ width, height = img.width, img.height
11
+ w_scale, v_scale = size.fdiv(width), size.fdiv(height)
11
12
 
12
- # Rescale to 64x64 and greyscale
13
- img = img.resize(w_scale, vscale: v_scale).colourspace(:grey16)
14
- # Ensure a 2D plane
15
- @pixels_2d = img.to_a.map(&:flatten)
16
- end
13
+ # Rescale to 64x64 and greyscale
14
+ img = img.resize(w_scale, vscale: v_scale).colourspace(:grey16)
15
+ # Ensure a 2D plane
16
+ @pixels_2d = img.to_a.map(&:flatten)
17
+ end
17
18
 
18
- subject { PH.new(@pixels_2d) }
19
+ subject { PH.new(@pixels_2d) }
19
20
 
20
- it "#hash" do
21
- assert_equal "859091ce633aaebb", subject.hash
22
- end
21
+ it "#hash" do
22
+ assert_equal "859091ce633aaebb", subject.hash
23
+ end
23
24
 
24
- it "#vector" do
25
- vector = [
26
- 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,
27
- 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0,
28
- 1, 1
29
- ]
25
+ it "#vector" do
26
+ vector = [
27
+ 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,
28
+ 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0,
29
+ 1, 1
30
+ ]
30
31
 
31
- assert_equal vector, subject.vector
32
+ assert_equal vector, subject.vector
33
+ end
32
34
  end
33
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - elcuervo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-02 00:00:00.000000000 Z
11
+ date: 2021-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: vips
@@ -31,7 +31,9 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
+ - ".gitignore"
34
35
  - Makefile
36
+ - README.md
35
37
  - lib/ph.rb
36
38
  - ph.gemspec
37
39
  - spec/image.jpg