2016-04-14 3 views
-1

Ich habe ein Bild master.png und mehr als 10.000 anderer Bilder (slave_1.png, slave_2.png, ...). Sie alle haben:Was ist die beste Technik, um die Ähnlichkeit von Bildern zu vergleichen?

  • die gleichen Abmessungen
  • Das gleiche Format (PNG)
  • Das gleiche Bild Hintergrund

98% der Slaves identisch mit dem (zB 100x50 Bildpunkten.) Meister, aber 2% der Sklaven haben einen etwas anderen Inhalt:

  • Neue Farben erscheinen
  • Neue kleine Formen erscheinen in der Mitte des Bildes

Ich muss diese verschiedenen Sklaven erkennen. Ich benutze Ruby, aber ich habe kein Problem mit einer anderen Technologie.

Ich versuchte, File.binread beide Bilder und dann vergleichen mit ==. Es funktionierte für 80% der Sklaven. Bei anderen Slaves wurden Änderungen festgestellt, aber die Bilder waren visuell identisch. Es funktioniert also nicht.

Alternativen sind:

  1. Zähle die Anzahl der Farben in jeder Slave-Master vorhanden ist und mit vergleichen. Es wird in 100% der Zeit funktionieren. Aber ich weiß nicht, wie man es in Ruby "leicht" macht.
  2. Verwenden Sie einen Bildprozessor, um nach Histogrammen wie RMagick oder ruby-vips8 zu vergleichen. Dieser Weg sollte auch funktionieren, aber ich muss weniger CPU/Speicher verbrauchen.
  3. Schreiben Sie ein C++/Go/Crystal-Programm, um Pixel für Pixel zu lesen und eine Anzahl von Farben zurückzugeben. Ich denke, auf diese Weise können wir Leistung erzielen, wenn. Aber sicher ist der harte Weg.

Irgendwelche Erleuchtung? Vorschläge?

+1

Blick in [diese Frage] (http://stackoverflow.com/questions/4196453/simple-and-fast-method-to-compare-images-for -Ähnlichkeit). Viele Optionen wurden dort diskutiert. – Uzbekjon

+0

Eine weitere Anmerkung zum Vergleich mit 'File.binread'. Da Sie einfach Dateiinhalte und Ressourcen und die Leistung einer Wichtigkeit vergleichen, wäre es besser, einfach bash dafür zu verwenden.Schau dir an: 'diff',' cmp' oder 'md5'. – Uzbekjon

+0

Könnte ein Job für [Tensor Flow] sein (https://www.tensorflow.org), wenn Sie einen Klassifikator benötigen. – tadman

Antwort

0

In ruby-vips, können Sie es wie folgt tun:

require 'vips' 

# find normalised histogram of reference image 
ref = VIPS::Image.new ARGV[0], :sequential => true 
ref_hist = ref.hist.histnorm 

# trigger a GC every few loops to keep memuse down 
loop = 0 

ARGV[1..-1].each do |filename| 
    # find sample hist 
    sample = VIPS::Image.new filename, :sequential => true 
    sample_hist = sample.hist.histnorm 

    # calculate sum of squares of differences, if it's over a threshold, print 
    # the filename 
    diff_hist = ref_hist.subtract(sample_hist).pow(2) 
    diff = diff_hist.avg * diff_hist.x_size * diff_hist.y_size 

    if diff > 100 
     puts "#{filename}, #{diff}" 
    end 

    loop += 1 
    if loop % 100 == 0 
     GC.start 
    end 
end 

Die gelegentliche GC.start notwendig Ruby frei Dinge zu machen und Speicherfüllung zu verhindern. Obwohl es nur einmal alle 100 Bilder gibt, verbringt es leider immer noch viel Zeit in der Müllsammlung.

$ vips crop ~/pics/k2.jpg ref.png 0 0 100 50 
$ for i in {1..10000}; do cp ref.png $i.png; done 
$ time ../similarity.rb ref.png *.png 
real 2m44.294s 
user 7m30.696s 
sys 0m20.780s 
peak mem 270mb 

Wenn Sie bereit sind, Python zu betrachten, ist es viel schneller, da sie Referenzzählung tut und muss nicht die ganze Zeit scannen.

import sys 
from gi.repository import Vips 

# find normalised histogram of reference image 
ref = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL) 
ref_hist = ref.hist_find().hist_norm() 

for filename in sys.argv[2:]: 
    # find sample hist 
    sample = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL) 
    sample_hist = sample.hist_find().hist_norm() 

    # calculate sum of squares of difference, if it's over a threshold, print 
    # the filename 
    diff_hist = (ref_hist - sample_hist) ** 2 
    diff = diff_hist.avg() * diff_hist.width * diff_hist.height 

    if diff > 100: 
     print filename, ", ", diff 

Ich sehe:

$ time ../similarity.py ref.png *.png 
real 1m4.001s 
user 1m3.508s 
sys 0m10.060s 
peak mem 58mb 
Verwandte Themen