Genel fikir
Seçenek 1: Her iki görüntüyü de diziler ( scipy.misc.imread
) olarak yükleyin ve öğe bazında (piksel piksel) bir fark hesaplayın. Farkın normunu hesaplayın.
Seçenek 2: Her iki görüntüyü de yükleyin. Her biri için bir özellik vektörü hesaplayın (histogram gibi). Görüntüler yerine özellik vektörleri arasındaki mesafeyi hesaplayın.
Ancak, ilk olarak alınacak bazı kararlar vardır.
Sorular
Önce bu soruları cevaplamalısınız:
Görüntüler aynı şekil ve boyutta mı?
Değilse, yeniden boyutlandırmanız veya kırpmanız gerekebilir. PIL kütüphanesi Python'da bunu yapmanıza yardımcı olacaktır.
Aynı ayarlarla ve aynı cihazla alınırlarsa, muhtemelen aynıdırlar.
Görüntüler iyi hizalanmış mı?
Değilse, önce en iyi hizalamayı bulmak için önce çapraz korelasyonu çalıştırmak isteyebilirsiniz. SciPy'nin bunu yapacak işlevleri vardır.
Kamera ve sahne hala hareket ediyorsa, görüntüler iyi hizalanmış olabilir.
Görüntülerin pozlanması her zaman aynı mıdır? (Hafiflik / kontrast aynı mıdır?)
Değilse, görüntüleri normalleştirmek isteyebilirsiniz .
Ancak dikkatli olun, bazı durumlarda bu iyi olmaktan daha yanlış olabilir. Örneğin, karanlık bir arka plandaki tek bir parlak piksel normalleştirilmiş görüntüyü çok farklı hale getirir.
Renk bilgisi önemli mi?
Renk değişikliklerini fark etmek istiyorsanız, gri tonlamalı görüntüdeki gibi bir skaler değer yerine nokta başına bir renk değerleri vektörünüz olacaktır. Bu kodu yazarken daha fazla dikkat etmeniz gerekir.
Görüntüde farklı kenarlar var mı? Hareket etmeleri muhtemel mi?
Evetse, önce kenar algılama algoritmasını uygulayabilirsiniz (örneğin, Sobel veya Prewitt dönüşümü ile degradeyi hesaplayın, bir miktar eşik uygulayın), ardından ilk görüntüdeki kenarları ikinci kenarlarla karşılaştırın.
Görüntüde parazit var mı?
Tüm sensörler görüntüyü bir miktar gürültü ile kirletir. Düşük maliyetli sensörler daha fazla gürültüye sahiptir. Görüntüleri karşılaştırmadan önce biraz gürültü azaltma uygulamak isteyebilirsiniz. Bulanıklık, buradaki en basit (ancak en iyi değil) yaklaşımdır.
Ne tür değişiklikler fark etmek istiyorsunuz?
Bu, görüntüler arasındaki fark için kullanılacak norm seçimini etkileyebilir.
Görüntünün ne kadar değiştiğini ölçmek için Manhattan normu (mutlak değerlerin toplamı) veya sıfır normu (sıfıra eşit olmayan öğe sayısı) kullanmayı düşünün. Birincisi görüntünün ne kadar kapalı olduğunu söyleyecek, ikincisi sadece kaç pikselin farklı olduğunu söyleyecektir.
Misal
Resimlerinizin muhtemelen farklı pozlamayla iyi hizalanmış, aynı boyut ve şekilde olduğunu varsayıyorum. Basit olması için renkli (RGB) görüntüler olsalar bile gri tonlamaya dönüştürürüm.
Bu ithalatlara ihtiyacınız olacak:
import sys
from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average
Ana işlev, iki görüntüyü okuyun, gri tonlamaya dönüştürün, sonuçları karşılaştırın ve yazdırın:
def main():
file1, file2 = sys.argv[1:1+2]
# read images as 2D arrays (convert to grayscale for simplicity)
img1 = to_grayscale(imread(file1).astype(float))
img2 = to_grayscale(imread(file2).astype(float))
# compare
n_m, n_0 = compare_images(img1, img2)
print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size
Nasıl karşılaştırılır. img1
ve img2
2D SciPy dizileri burada:
def compare_images(img1, img2):
# normalize to compensate for exposure difference, this may be unnecessary
# consider disabling it
img1 = normalize(img1)
img2 = normalize(img2)
# calculate the difference and its norms
diff = img1 - img2 # elementwise for scipy arrays
m_norm = sum(abs(diff)) # Manhattan norm
z_norm = norm(diff.ravel(), 0) # Zero norm
return (m_norm, z_norm)
Dosya renkli bir görüntü ise, imread
yoğunluk elde etmek için 3B dizi, ortalama RGB kanalları (son dizi ekseni) döndürür. Gri tonlamalı görüntüler için buna gerek yoktur (örn. .pgm
):
def to_grayscale(arr):
"If arr is a color image (3D array), convert it to grayscale (2D array)."
if len(arr.shape) == 3:
return average(arr, -1) # average over the last axis (color channels)
else:
return arr
Normalleştirme önemsizdir, [0,255] yerine [0,1] olarak normalleştirmeyi seçebilirsiniz. arr
burada bir SciPy dizisidir, bu nedenle tüm işlemler element bazındadır:
def normalize(arr):
rng = arr.max()-arr.min()
amin = arr.min()
return (arr-amin)*255/rng
main
İşlevi çalıştırın :
if __name__ == "__main__":
main()
Şimdi bunları bir senaryoya koyabilir ve iki görüntüye karşı koşabilirsiniz. Görüntüyü kendisiyle karşılaştırırsak, fark yoktur:
$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0
Görüntüyü bulanıklaştırır ve orijinalle karşılaştırırsak, bazı farklar vardır:
$ python compare.py one.jpg one-blurred.jpg
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0
PS Tüm karşılaştırma.py betiği.
Güncelleme: ilgili teknikler
Soru, karelerin neredeyse aynı olacağı ve sıra dışı bir şey aradığınız bir video dizisiyle ilgili olduğundan, alakalı olabilecek bazı alternatif yaklaşımlardan bahsetmek istiyorum:
- arka plan çıkarma ve bölümleme (ön plandaki nesneleri algılamak için)
- seyrek optik akış (hareketi algılamak için)
- görüntüler yerine histogramları veya diğer istatistikleri karşılaştırma
“OpenCV'yi Öğrenme” kitabına, Bölüm 9'a (Görüntü parçaları ve segmentasyon) ve 10'a (İzleme ve hareket) bir göz atmanızı şiddetle tavsiye ederim. Birincisi Arkaplan çıkartma yöntemini kullanmayı öğretir, ikincisi optik akış yöntemleri hakkında bilgi verir. Tüm yöntemler OpenCV kütüphanesinde uygulanır. Python kullanıyorsanız, OpenCV ≥ 2.3 ve cv2
Python modülünü kullanmanızı öneririm .
Arka plan çıkarmanın en basit sürümü:
- arka planın her pikseli için ortalama değer μ ve standart sapma σ öğrenin
- geçerli piksel değerlerini (μ-2σ, μ + 2σ) veya (μ-σ, μ + σ) aralıklarıyla karşılaştırın
Daha gelişmiş sürümler, her piksel için zaman serilerini dikkate alır ve statik olmayan sahneleri (hareketli ağaçlar veya çim gibi) işler.
Optik akış fikri, iki veya daha fazla kare almak ve her piksele (yoğun optik akış) veya bazılarına (seyrek optik akış) hız vektörü atamaktır. Seyrek optik akışı tahmin etmek için Lucas-Kanade yöntemini kullanabilirsiniz ( OpenCV'de de uygulanır). Açıkçası, çok fazla akış varsa (hız alanının maksimum değerlerinden yüksek ortalama), o zaman çerçevede bir şey hareket eder ve sonraki görüntüler daha farklıdır.
Histogramları karşılaştırmak, ardışık kareler arasındaki ani değişiklikleri tespit etmeye yardımcı olabilir. Bu yaklaşım Courbon ve ark., 2010'da kullanılmıştır :
Ardışık çerçevelerin benzerliği. Birbirini takip eden iki kare arasındaki mesafe ölçülür. Çok yüksekse, ikinci karenin bozuk olduğu ve böylece görüntünün ortadan kaldırıldığı anlamına gelir. Kullback-Leibler mesafesi iki kare histogramda veya karşılıklı entropi:
burada p ve q , çerçevelerin histogramlarıdır. Eşik 0,2 ile sabitlenmiştir.