pHash 1.0.2 → 1.1.0
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.
- data/lib/phash.rb +23 -3
- data/lib/phash/audio.rb +29 -17
- data/lib/phash/image.rb +8 -14
- data/lib/phash/text.rb +4 -12
- data/lib/phash/video.rb +4 -11
- data/pHash.gemspec +1 -1
- metadata +3 -3
data/lib/phash.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
require 'ffi'
|
2
2
|
|
3
3
|
module Phash
|
4
|
-
class
|
4
|
+
class Data
|
5
5
|
attr_reader :data, :length
|
6
6
|
def initialize(data, length = nil)
|
7
7
|
@data, @length = data, length
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
class HashData < Data
|
12
|
+
def similarity(other, *args)
|
13
|
+
Phash.send("#{self.class.hash_type}_similarity", self, other, *args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.hash_type
|
17
|
+
@hash_type ||= self.name.split('::').last.sub(/Hash$/, '').downcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
11
21
|
class FileHash
|
12
22
|
attr_reader :path
|
13
23
|
|
@@ -28,8 +38,18 @@ module Phash
|
|
28
38
|
@phash ||= compute_phash
|
29
39
|
end
|
30
40
|
|
31
|
-
def
|
32
|
-
|
41
|
+
def compute_phash
|
42
|
+
Phash.send("#{self.class.hash_type}_hash", @path)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Similarity with other phash
|
46
|
+
def similarity(other, *args)
|
47
|
+
phash.similarity(other.phash, *args)
|
48
|
+
end
|
49
|
+
alias_method :%, :similarity
|
50
|
+
|
51
|
+
def self.hash_type
|
52
|
+
@hash_type ||= self.name.split('::').last.downcase
|
33
53
|
end
|
34
54
|
end
|
35
55
|
|
data/lib/phash/audio.rb
CHANGED
@@ -49,23 +49,38 @@ module Phash
|
|
49
49
|
#
|
50
50
|
attach_function :ph_audio_distance_ber, [:pointer, :int, :pointer, :int, :float, :int, :pointer], :pointer, :blocking => true
|
51
51
|
|
52
|
-
class AudioHash < HashData; end
|
53
52
|
class << self
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
DEFAULT_SAMPLE_RATE = 8000
|
54
|
+
|
55
|
+
# Read audio file specified by path and optional length using <tt>ph_readaudio</tt>
|
56
|
+
def audio_data(path, length = 0, sample_rate = nil)
|
57
|
+
sample_rate ||= DEFAULT_SAMPLE_RATE
|
57
58
|
audio_data_length_p = FFI::MemoryPointer.new :int
|
58
59
|
if audio_data = ph_readaudio(path.to_s, sample_rate, 1, nil, audio_data_length_p, length.to_f)
|
59
60
|
audio_data_length = audio_data_length_p.get_int(0)
|
60
61
|
audio_data_length_p.free
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
Data.new(audio_data, audio_data_length)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get hash of audio data using <tt>ph_audiohash</tt>
|
68
|
+
def audio_data_hash(audio_data, sample_rate = nil)
|
69
|
+
sample_rate ||= DEFAULT_SAMPLE_RATE
|
70
|
+
hash_data_length_p = FFI::MemoryPointer.new :int
|
71
|
+
if hash_data = ph_audiohash(audio_data.data, audio_data.length, sample_rate, hash_data_length_p)
|
72
|
+
hash_data_length = hash_data_length_p.get_int(0)
|
73
|
+
hash_data_length_p.free
|
74
|
+
|
75
|
+
AudioHash.new(hash_data, hash_data_length)
|
76
|
+
end
|
77
|
+
end
|
66
78
|
|
67
|
-
|
68
|
-
|
79
|
+
# Use <tt>audio_data</tt> and <tt>audio_data_hash</tt> to compute hash for file at path, specify max length in seconds to read
|
80
|
+
def audio_hash(path, length = 0, sample_rate = nil)
|
81
|
+
sample_rate ||= DEFAULT_SAMPLE_RATE
|
82
|
+
if audio_data = audio_data(path, length, sample_rate)
|
83
|
+
audio_data_hash(audio_data, sample_rate)
|
69
84
|
end
|
70
85
|
end
|
71
86
|
|
@@ -92,6 +107,10 @@ module Phash
|
|
92
107
|
end
|
93
108
|
end
|
94
109
|
|
110
|
+
# Class to store audio hash and compare to other
|
111
|
+
class AudioHash < HashData
|
112
|
+
end
|
113
|
+
|
95
114
|
# Class to store audio file hash and compare to other
|
96
115
|
class Audio < FileHash
|
97
116
|
attr_reader :length
|
@@ -101,13 +120,6 @@ module Phash
|
|
101
120
|
@path, @length = path, length
|
102
121
|
end
|
103
122
|
|
104
|
-
# Similarity with other audio
|
105
|
-
def similarity(other, *args)
|
106
|
-
Phash.audio_similarity(phash, other.phash, *args)
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
123
|
def compute_phash
|
112
124
|
Phash.audio_hash(@path, @length)
|
113
125
|
end
|
data/lib/phash/image.rb
CHANGED
@@ -25,16 +25,16 @@ module Phash
|
|
25
25
|
hash = hash_p.get_uint64(0)
|
26
26
|
hash_p.free
|
27
27
|
|
28
|
-
hash
|
28
|
+
ImageHash.new(hash)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
# Get distance between two image hashes using <tt>ph_hamming_distance</tt>
|
33
33
|
def image_hamming_distance(hash_a, hash_b)
|
34
|
-
hash_a.is_a?(
|
35
|
-
hash_b.is_a?(
|
34
|
+
hash_a.is_a?(ImageHash) or raise ArgumentError.new('hash_a is not an ImageHash')
|
35
|
+
hash_b.is_a?(ImageHash) or raise ArgumentError.new('hash_b is not an ImageHash')
|
36
36
|
|
37
|
-
ph_hamming_distance(hash_a, hash_b)
|
37
|
+
ph_hamming_distance(hash_a.data, hash_b.data)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Get similarity from hamming_distance
|
@@ -43,17 +43,11 @@ module Phash
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
# Class to store image hash and compare to other
|
47
|
+
class ImageHash < HashData
|
48
|
+
end
|
49
|
+
|
46
50
|
# Class to store image file hash and compare to other
|
47
51
|
class Image < FileHash
|
48
|
-
# Similarity with other image
|
49
|
-
def similarity(other)
|
50
|
-
Phash.image_similarity(phash, other.phash)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def compute_phash
|
56
|
-
Phash.image_hash(@path)
|
57
|
-
end
|
58
52
|
end
|
59
53
|
end
|
data/lib/phash/text.rb
CHANGED
@@ -35,7 +35,6 @@ module Phash
|
|
35
35
|
#
|
36
36
|
attach_function :ph_compare_text_hashes, [:pointer, :int, :pointer, :int, :pointer], :pointer, :blocking => true
|
37
37
|
|
38
|
-
class TextHash < HashData; end
|
39
38
|
class << self
|
40
39
|
# Get text file hash using <tt>ph_texthash</tt>
|
41
40
|
def text_hash(path)
|
@@ -66,7 +65,6 @@ module Phash
|
|
66
65
|
|
67
66
|
def text_similarity(hash_a, hash_b)
|
68
67
|
matches = text_hash_matches(hash_a, hash_b)
|
69
|
-
# p [hash_a.length, hash_b.length, matches.length]
|
70
68
|
matched_a = Array.new(hash_a.length)
|
71
69
|
matched_b = Array.new(hash_b.length)
|
72
70
|
matches.each do |match|
|
@@ -83,17 +81,11 @@ module Phash
|
|
83
81
|
end
|
84
82
|
end
|
85
83
|
|
84
|
+
# Class to store text hash and compare to other
|
85
|
+
class TextHash < HashData
|
86
|
+
end
|
87
|
+
|
86
88
|
# Class to store text file hash and compare to other
|
87
89
|
class Text < FileHash
|
88
|
-
# Distance from other file, for now bit useless thing
|
89
|
-
def similarity(other)
|
90
|
-
Phash.text_similarity(phash, other.phash)
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def compute_phash
|
96
|
-
Phash.text_hash(@path)
|
97
|
-
end
|
98
90
|
end
|
99
91
|
end
|
data/lib/phash/video.rb
CHANGED
@@ -13,7 +13,6 @@ module Phash
|
|
13
13
|
#
|
14
14
|
attach_function :ph_dct_videohash_dist, [:pointer, :int, :pointer, :int, :int], :double, :blocking => true
|
15
15
|
|
16
|
-
class VideoHash < HashData; end
|
17
16
|
class << self
|
18
17
|
# Get video hash using <tt>ph_dct_videohash</tt>
|
19
18
|
def video_hash(path)
|
@@ -38,17 +37,11 @@ module Phash
|
|
38
37
|
alias_method :video_similarity, :video_dct_distance
|
39
38
|
end
|
40
39
|
|
40
|
+
# Class to store video hash and compare to other
|
41
|
+
class VideoHash < HashData
|
42
|
+
end
|
43
|
+
|
41
44
|
# Class to store video file hash and compare to other
|
42
45
|
class Video < FileHash
|
43
|
-
# Similarity with other video
|
44
|
-
def similarity(other, *args)
|
45
|
-
Phash.video_similarity(phash, other.phash, *args)
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def compute_phash
|
51
|
-
Phash.video_hash(@path)
|
52
|
-
end
|
53
46
|
end
|
54
47
|
end
|
data/pHash.gemspec
CHANGED
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.2
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ivan Kuchin
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-12-
|
18
|
+
date: 2011-12-27 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rspec
|