module PNG_Comparison::Comparator

Public Class Methods

compare_images(img1:, img2:, diff_file:, threshold:) click to toggle source
# File lib/png_comparison.rb, line 51
def self.compare_images(img1:, img2:, diff_file:, threshold:)
  read_start = Time.now
  puts 'Reading images...'
  if !(img1.is_a?(ChunkyPNG::Image) && img2.is_a?(ChunkyPNG::Image) && diff_file.is_a?(ChunkyPNG::Image))
    image1 = ChunkyPNG::Image.from_file(img1)
    image2 = ChunkyPNG::Image.from_file(img2)
    output_file = ChunkyPNG::Image.new(image1.width, image1.height, WHITE)
  else
    image1 = img1
    image2 = img2
    output_file = diff_file
    diff_file = 'diff_file'
  end

  read_end = Time.now
  puts "Finished reading images in #{read_end - read_start} seconds"

  image_length = image1.pixels.length
  diff = []
  perceptual_diff = 0

  if !image1.eql?(image2) && (image1.dimension == image2.dimension)
    diff, output_file = img_diff(image1: image1, image2: image2, output_file: output_file)
    perceptual_diff = (diff.inject { |sum, value| sum + value } / image_length) * 100
  else if image1.dimension != image2.dimension
         puts 'Images have different dimensions!'
         return false
    end
  end

  absolute_change = show_statistics(image_length, diff, perceptual_diff, threshold)
  # you can use here "if absolute_change > perceptual_diff"
  if absolute_change > threshold
    puts 'Images are not identical.'
    output_file.save(diff_file)
    return false
  else
    puts 'Images are identical or differ within threshold.'
    output_file.save(diff_file) unless image1.eql?(image2)
    return true
  end
end

Private Class Methods

img_diff(image1:, image2:, output_file:) click to toggle source

Main color difference algorithm, kind of CIE76 metric

# File lib/png_comparison.rb, line 97
def self.img_diff(image1:, image2:, output_file:)
  diff = []
  image1.height.times do |y|
    image1.row(y).each_with_index do |pixel, x|
      next if pixel == image2[x, y]
      score = Math.sqrt((r(image2[x, y]) - r(pixel))**2 + (g(image2[x, y]) - g(pixel))**2 +
                                   (b(image2[x, y]) - b(pixel))**2) / Math.sqrt(MAX**2 * 3)
      output_file[x, y] = grayscale(MAX - (score * MAX).round)
      diff << score
    end
  end
  [diff, output_file]
end
show_statistics(image_length, diff, perceptual_diff, threshold) click to toggle source
# File lib/png_comparison.rb, line 111
def self.show_statistics(image_length, diff, perceptual_diff, threshold)
  total_pixels = image_length
  non_matching_pixels = diff.length
  absolute_change = (non_matching_pixels.to_f / total_pixels.to_f) * 100
  puts "Pixels processed: #{total_pixels}"
  puts "Differing Pixels: #{non_matching_pixels}"
  puts "Perceptual image difference: #{perceptual_diff} (%)"
  puts "Absolute image difference: #{absolute_change} (%), threshold is #{threshold}(%)"
  absolute_change
end