class PH
Constants
- IncorrectDimensionsError
- NotGreyscaleError
Attributes
pixels[R]
size[R]
Public Class Methods
hash(pixels_2d)
click to toggle source
# File lib/ph.rb, line 10 def hash(pixels_2d) new(pixels_2d).hash end
new(pixels_2d)
click to toggle source
# File lib/ph.rb, line 19 def initialize(pixels_2d) @pixels = pixels_2d @size = pixels_2d.size raise NotGreyscaleError if pixels_2d.flatten.count != @size**2 raise IncorrectDimensionsError if !(Math.sqrt(size) % 8).zero? end
vector(pixels_2d)
click to toggle source
# File lib/ph.rb, line 14 def vector(pixels_2d) new(pixels_2d).vector end
Public Instance Methods
hash()
click to toggle source
# File lib/ph.rb, line 27 def hash # Binary to hex string vector.join.to_i(2).to_s(16) end
vector()
click to toggle source
# File lib/ph.rb, line 32 def vector @_vector ||= begin # Get DCT2D of the pixels dct_pixels = dct2d(pixels) # Get high frequency corner sqrt = Math.sqrt(size).to_i coords = Array.new(2, sqrt) corner = flat1d(coords, dct_pixels) corner_size = corner.length # Median values med = median(corner) result = Array.new(size, 0) corner.each.with_index do |f, i| # Compare each value to the median result[i] = 1 if f > med end result end end
Private Instance Methods
dct(vector)
click to toggle source
1984 Lee DCT implementation
# File lib/ph.rb, line 113 def dct(vector) n = vector.size return vector if n == 1 raise StandardError, "Must be nxn" if n.zero? || n.odd? half = n / 2 alpha = [] beta = [] Array.new(half).each.with_index do |_, i| alpha << (vector[i] + vector[-(i + 1)]) beta << (vector[i] - vector[-(i + 1)]) / (Math.cos((i + 0.5) * Math::PI / n) * 2.0) end alpha = dct(alpha) beta = dct(beta) result = [] Array.new(half - 1).each.with_index do |_, i| result << alpha[i] result << beta[i] + beta[i + 1] end result << alpha[-1] result << beta[-1] result end
dct2d(pixels_2d)
click to toggle source
DCT on a bidimensional plane Thank you matlab forum for explaining that it's just transpositions www.mathworks.com/matlabcentral/answers/405088-how-to-implement-dct2-in-matlab-coder
# File lib/ph.rb, line 61 def dct2d(pixels_2d) dct_fn = -> (px) { dct(px) } pixels_2d .map(&dct_fn).transpose .map(&dct_fn).transpose end
flat1d(coords, pixels_2d)
click to toggle source
Slices 2D vector into a 1D version
# File lib/ph.rb, line 71 def flat1d(coords, pixels_2d) slice = [] x, y = coords Array.new(x) do |i| Array.new(y) do |j| slice << pixels_2d[i][j] end end slice end
median(vector)
click to toggle source
Quickselect median. rcoh.me/posts/linear-time-median-finding/
# File lib/ph.rb, line 87 def median(vector) return nil if vector.empty? n = vector.size return quickselect(vector, n / 2) if n.odd? 0.5 * (quickselect(vector, n / 2 - 1) + quickselect(vector, n / 2)) end
quickselect(vector, pos)
click to toggle source
# File lib/ph.rb, line 96 def quickselect(vector, pos) return vector.first if vector.size == 1 && pos.zero? pivot = vector.sample lows = vector.select { |i| i < pivot } highs = vector.select { |i| i > pivot } pivots = vector.select { |i| i == pivot } return quickselect(lows, pos) if pos < lows.size return pivots.first if pos < pivots.size + lows.size quickselect(highs, pos - lows.size - pivots.size) end