Class: LogoSoup::Core::BackgroundDetector
- Inherits:
-
Object
- Object
- LogoSoup::Core::BackgroundDetector
- Defined in:
- lib/logosoup/core/background_detector.rb
Overview
Detects whether background should be treated as transparent and estimates background RGB from the image perimeter.
Constant Summary collapse
- QUANTIZATION_SHIFT =
5- ALPHA_TRANSPARENCY_THRESHOLD =
128- TRANSPARENT_PERIMETER_RATIO_THRESHOLD =
0.1
Class Method Summary collapse
-
.call(bytes, width, height) ⇒ Array(Boolean, Integer, Integer, Integer)
[alpha_only, bg_r, bg_g, bg_b].
Class Method Details
.call(bytes, width, height) ⇒ Array(Boolean, Integer, Integer, Integer)
Returns [alpha_only, bg_r, bg_g, bg_b].
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/logosoup/core/background_detector.rb', line 16 def self.call(bytes, width, height) levels = 1 << (8 - QUANTIZATION_SHIFT) bucket_count = levels * levels * levels bucket_counts = Array.new(bucket_count, 0) bucket_r = Array.new(bucket_count, 0) bucket_g = Array.new(bucket_count, 0) bucket_b = Array.new(bucket_count, 0) opaque_count = 0 transparent_count = 0 sample = lambda do |x, y| idx = ((y * width) + x) * 4 a = bytes[idx + 3] return if a.nil? if a < ALPHA_TRANSPARENCY_THRESHOLD transparent_count += 1 return end opaque_count += 1 r = bytes[idx] g = bytes[idx + 1] b = bytes[idx + 2] key = ((((r >> QUANTIZATION_SHIFT) * levels) + (g >> QUANTIZATION_SHIFT)) * levels) + (b >> QUANTIZATION_SHIFT) bucket_counts[key] += 1 bucket_r[key] += r bucket_g[key] += g bucket_b[key] += b end width.times do |x| sample.call(x, 0) sample.call(x, height - 1) if height > 1 end (1...(height - 1)).each do |y| sample.call(0, y) sample.call(width - 1, y) if width > 1 end total_perimeter = opaque_count + transparent_count transparent = total_perimeter.positive? && transparent_count > total_perimeter * TRANSPARENT_PERIMETER_RATIO_THRESHOLD return [true, 0, 0, 0] if transparent best_idx = 0 best_count = 0 bucket_counts.each_with_index do |count, i| next unless count > best_count best_count = count best_idx = i end if best_count.positive? bg_r = (bucket_r[best_idx].to_f / best_count).round bg_g = (bucket_g[best_idx].to_f / best_count).round bg_b = (bucket_b[best_idx].to_f / best_count).round [false, bg_r, bg_g, bg_b] else [false, 255, 255, 255] end end |