Biri biraz farklı kırpma / orana sahip olsa bile iki görüntünün “aynı” olduğunu nasıl tespit edebilirim?


11

İki farklı resmim var:

100 resim açıklamasını buraya girinpiksel veya 400 pikselresim açıklamasını buraya girin

ve

100 resim açıklamasını buraya girinpiksel genişlik veya 400 pikselresim açıklamasını buraya girin

Gördüğünüz gibi ikisi açıkça insan bakış açısıyla "aynı" dır. Şimdi programlı olarak aynı olduklarını tespit etmek istiyorum. Ben böyle denilen yakut mücevher aracılığıyla görüntü sihirli kullanıyorum rmagick:

img1 = Magick::Image.from_blob(File.read("image_1.jpeg")).first
img2 = Magick::Image.from_blob(File.read("image_2.jpeg")).first

if img1.difference(img2).first < 4000.0 # I have found this to be a good threshold, but does not work for cropped images
  puts "they are the same!!!"
end

Bu, aynı orana / kırpmaya sahip görüntüler için iyi çalışıyor olsa da, biraz farklı kırpmaya sahip olduklarında ve aynı genişliğe yeniden boyutlandırıldıklarında ideal değildir.

Farklı kırpma içeren görüntüler için bunu yapmanın bir yolu var mı? Şunun gibi bir şey söyleyebileceğim bir çözümle ilgileniyorum: Bir görüntü diğerinin içinde yer alıyor ve örneğin% 90'ı civarında bir yeri kapsıyor.

PS. Yardımcı olursa görüntüleri daha yüksek çözünürlükte elde edebilirim (örneğin, çift)


2
RMagick hakkında emin değilim, ancak ImageMagick'in comparekomut satırı aracında bir -subimage-searchanahtar var.
Stefan

Bu ilginç, böyle bir komut nasıl görünüyor?
Niels Kristian

2
Hiç kullanmadım, belki de yardımcı olur: stackoverflow.com/q/29062811/477037
Stefan

Teşekkürler, bu harika bir bilgi. Ancak bunu ruby'den nasıl yapacağımı anlayamıyorum ...
Niels Kristian

1
Görüntüler düşük kaliteli mi? Hayır ise, lütfen resimlerin daha büyük bir sürümünü daha kaliteli olarak paylaşın.
MH304

Yanıtlar:


6

Özellik eşleşmesine bir göz atmak isteyebilirsiniz. Fikir, iki görüntüdeki özellikleri bulmak ve bunlarla eşleşmektir. Bu yöntem, başka bir görüntüdeki bir şablonu (bir logo söyleyin) bulmak için yaygın olarak kullanılır. Bir özellik, özünde, insanların köşeler veya açık alanlar gibi bir görüntüde ilginç bulacağı şeyler olarak tanımlanabilir. Orada birçok özellik algılama tekniği vardır, ancak benim tavsiyem bir özellik algılama algoritması olarak ölçek değişmez özellik dönüşümü (SIFT) kullanmaktır. SIFT görüntü çevirisi, ölçeklendirme, döndürme, aydınlatma değişikliklerine kısmen değişmez ve yerel geometrik bozulmaya karşı dayanıklıdır. Bu, görüntülerin biraz farklı oranlara sahip olabileceği spesifikasyonunuza uyuyor gibi görünüyor.

Sağladığınız iki resim göz önüne alındığında, FLANN özellik eşleştiricisini kullanarak özellikleri eşleştirmeye çalışacağız . İki görüntünün aynı olup olmadığını belirlemek için, David G. Lowe tarafından Ölçek-Değişmez Anahtar Noktalarından Ayırt Edici Görüntü Özelliklerinde açıklanan oran testini geçen eşleşme sayısını izleyen önceden belirlenmiş bir eşiği temel alabiliriz . Testin basit bir açıklaması, oran testinin eşleşmelerin belirsiz olup olmadığını kontrol etmesi ve kaldırılması gerektiğidir, bunu bir aykırı değer kaldırma tekniği olarak ele alabilirsiniz. İki görüntünün aynı olup olmadığını belirlemek için bu testi geçen eşleşme sayısını sayabiliriz. İşte sonuç eşleşen özellik:

Matches: 42

Noktalar algılanan tüm eşleşmeleri temsil ederken yeşil çizgiler oran testini geçen "iyi eşleşmeleri" temsil eder. Oran testini kullanmazsanız tüm noktalar çizilecektir. Bu şekilde, bu filtreyi yalnızca en iyi eşleşen özellikleri korumak için bir eşik olarak kullanabilirsiniz.


Python'da uyguladım, Rails'e pek aşina değilim. Umarım bu yardımcı olur, iyi şanslar!

kod

import numpy as np
import cv2

# Load images
image1 = cv2.imread('1.jpg', 0)
image2 = cv2.imread('2.jpg', 0)

# Create the sift object
sift = cv2.xfeatures2d.SIFT_create(700)

# Find keypoints and descriptors directly
kp1, des1 = sift.detectAndCompute(image2, None)
kp2, des2 = sift.detectAndCompute(image1, None)

# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary
flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]

count = 0
# Ratio test as per Lowe's paper (0.7)
# Modify to change threshold 
for i,(m,n) in enumerate(matches):
    if m.distance < 0.15*n.distance:
        count += 1
        matchesMask[i]=[1,0]

# Draw lines
draw_params = dict(matchColor = (0,255,0),
                   # singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

# Display the matches
result = cv2.drawMatchesKnn(image2,kp1,image1,kp2,matches,None,**draw_params)
print('Matches:', count)
cv2.imshow('result', result)
cv2.waitKey()

2
Süper ilginç bir yaklaşım, bir spin vereceğim ve geri döneceğim ...
Niels Kristian

PS. Resimleri daha büyük ölçekte güncelledim
Niels Kristian

1
@nathancy Örneğinizde yeşil noktalar eşleşiyor, ancak mavi olanlar eşleşmiyor mu? Görünüşe göre çok fazla benzersiz nokta var mı?
Draco Ater

2
İyi bir soru, mavi noktalar tüm eşleşmeleri temsil ederken sadece oran testini yeşil renkle geçen "iyi eşleşmeler" çizeriz. Oran testini kullanmazsanız tüm noktalar çizilir ancak "daha iyi" eşleşmeleri çizmek için oran testini kullanarak filtreleriz. Bu şekilde OP bu testi sadece en iyi eşleşen özellikleri korumak için bir eşik olarak kullanabilir. Bu yüzden tüm mavi noktalar SIFT'in bulduğu özelliklerdir, ancak yeşil olarak çizilen iyi olanları tutmak için filtreliyoruz
nathancy

Teşekkürler. rekabet cevaplar zor, birçok harika olanlar :-)
Niels Kristian

4

ImageMagick çok eski, gelişmiş ve çok özellikli bir araç olduğundan, özelliklerin çoğunu kapsayan bir arayüz oluşturmak zor olacaktır. Ne kadar büyük olursa olsun, rmagick tüm özellikleri kapsamaya yaklaşmaz (ve python'un yaptığı pek çok girişimde bulunmaz).

Birçok kullanım durumu için, sadece bir komut satırı yöntemi yürütmek ve bundan okumak daha yeterli ve daha kolay olacak. Yakutta böyle görünecek;

require 'open3'

def check_subimage(large, small)
    stdin, stdout, stderr, wait_thr = Open3.popen3("magick compare -subimage-search -metric RMSE #{large} #{small} temp.jpg")
    result = stderr.gets
    stderr.close
    stdout.close
    return result.split[1][1..-2].to_f < 0.2
end

if check_subimage('a.jpg', 'b.jpg')
    puts "b is a crop of a"
else
    puts "b is not a crop of a"
end

Önemli şeyleri ele alacağım ve sonra ek notlar hakkında konuşacağım.

Komut, ikinci görüntünün ( small) first ( large) öğesinin bir alt öğesi olup olmadığını kontrol etmek için magick Compare'i kullanır . Bu işlev, küçük boyutun kesinlikle büyükten (hem yükseklik hem de genişlik) daha küçük olduğunu kontrol etmez. Benzerlik için koyduğum sayı 0,2 (% 20 hata) ve sağladığınız görüntüler için değer yaklaşık 0,15. Buna ince ayar yapmak isteyebilirsiniz! Sıkı bir alt küme olan resimlerin 0.01'den az olduğunu düşünüyorum.

  • % 90 çakışma olan ancak ikinci görüntünün ilkinde fazladan bir şeyler olmadığı durumlarda daha az hata (daha küçük sayılar) istiyorsanız, bir kez çalıştırabilir, ardından alt resmin bulunduğu ilk büyük görüntüyü kırpabilirsiniz , daha sonra kırpılan görüntüyü "küçük" bir resim olarak ve orijinal "küçük" görüntüyü büyük olan olarak tekrar çalıştırın.
  • Gerçekten Ruby'de güzel bir nesne yönelimli arayüz istiyorsanız, rmagick MagicCore API'sini kullanır. Bu (dokümanlara bağlantı) komutu muhtemelen onu uygulamak için kullanmak istediğiniz komuttur ve ipucunu kendiniz rmagick veya paketlemek için bir pr açabilirsiniz.
  • Open3 kullanıldığında bir konu başlatılır ( bkz. Dokümanlar ). Kapanış stderrve stdout"gerekli" değil ama yapmanız gerekiyor.
  • Üçüncü argüman olan "temp" görüntüsü, üzerine analiz çıktısı alınacak dosyayı belirtir. Hızlı bir bakışla, istememenin bir yolunu bulamadım, ancak otomatik olarak üzerine yazıyor ve hata ayıklama için kaydetmek iyi olabilir. Örneğin, şöyle görünecektir;

resim açıklamasını buraya girin

  • Tam çıktı 10092.6 (0.154003) @ 0,31 biçimindedir. İlk sayı 655535'in rmse değeri, ikincisi (kullandığım) normalleştirilmiş yüzde. Son iki sayı, küçük görüntünün başladığı orijinal görüntünün konumunu temsil eder.
  • "Benzer" görüntülerdir nasıl gerçeğin objektif bir kaynak olmadığı için, ben RMSE aldı (daha metrik seçenekleri görmek burada ). Değerler arasındaki farkların oldukça yaygın bir ölçüsüdür. Mutlak Hata sayısı (AE) iyi bir fikir gibi görünebilir, ancak bazı kırpma yazılımlarının pikselleri mükemmel bir şekilde koruyamadığı için fuzz'ı ayarlamanız gerekebilir ve bu normalleştirilmiş bir değer değildir, bu nedenle hata sayısını karşılaştırmanız gerekir görüntünün boyutu ve ne ile.

1
Bu gerçekten harika bir bilgi var Carol. Thanks
Niels Kristian

Bunun diğer vakalarınız için nasıl çalıştığını bilmek ister misiniz?
Carol Chen

1
Süper harika cevap için teşekkürler. Yapabilseydim, sana bunun için de 100p ödül verdim :-)
Niels Kristian

3

Her iki görüntünün histogramını alın ve karşılaştırın. Bu, çok fazla değişiklik olmadığı sürece kırpma ve yakınlaştırma için çok işe yarar.

Bu, görüntüleri doğrudan çıkardığınız mevcut yaklaşımdan daha iyidir. Ancak bu yaklaşımın hâlâ çok azı var.


Tavsiye için teşekkürler ben bir göz atacağım.
Niels Kristian

Hedefe nasıl ulaşılacağını göstermediği için bu çok yararlı bir cevap değil. "Bu terimi Google ve kendiniz anlayın" ifadesine eşdeğerdir.
anothermh

Histogram, insanların görüntü işlemede öğrendikleri ilk şeylerden biridir. Bazıları google gerekir, o zaman derin özür dilerim.
Raviteja Narra

3

Genellikle şablon eşleştirme bu durumlarda iyi sonuç verir. Şablon eşleme, bir görüntünün şablon görüntüsüyle (ikinci görüntü) eşleşen (benzer) alanlarını bulma tekniğidir. Bu algoritma, kaynak görüntüdeki (ikincisi) en iyi makro pozisyonu için bir puan verir.

TM_CCOEFF_NORMED yöntemini kullanan opencv'de , 0 ile 1 arasında puan verir. Puan 1 ise, şablon görüntüsü tam olarak kaynak görüntünün bir parçası (Rect) demektir, ancak arasındaki aydınlatma veya perspektifte küçük bir değişiklik varsa iki görüntü, skor 1'den düşük olacaktır.

Şimdi benzerlik puanı için bir eşik düşünerek, bunların aynı olup olmadıklarını öğrenebilirsiniz. Bu eşik birkaç örnek görüntü üzerinde bazı deneme yanılma yöntemleriyle elde edilebilir. Resimlerinizi denedim ve 0.823863 puanı aldım . Kod (opencv C ++) ve iki resim arasındaki ortak alan, eşleştirme ile elde edilen:

resim açıklamasını buraya girin

Mat im2 = imread("E:/1/1.jpg", 1);
//Mat im2;// = imread("E:/1/1.jpg", 1);
Mat im1 = imread("E:/1/2.jpg", 1);

//im1(Rect(0, 0, im1.cols - 5, im1.rows - 5)).copyTo(im2);

int result_cols = im1.cols - im2.cols + 1;
int result_rows = im1.rows - im2.rows + 1;

Mat result = Mat::zeros(result_rows, result_cols, CV_32FC1);

matchTemplate(im1, im2, result, TM_CCOEFF_NORMED);

double minVal; double maxVal;
Point minLoc; Point maxLoc;
Point matchLoc;

minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

cout << minVal << " " << maxVal << " " << minLoc << " " << maxLoc << "\n";
matchLoc = maxLoc;

rectangle(im1, matchLoc, Point(matchLoc.x + im2.cols, matchLoc.y + im2.rows), Scalar::all(0), 2, 8, 0);
rectangle(result, matchLoc, Point(matchLoc.x + im2.cols, matchLoc.y + im2.rows), Scalar::all(0), 2, 8, 0);

imshow("1", im1);
imshow("2", result);
waitKey(0);

Süper harika cevap için teşekkürler. Yapabilseydim, sana bunun için de 100p ödül verdim :-)
Niels Kristian

2

Find_slike_region yöntemini düşünün . Hedef görüntü olarak iki görüntüden daha küçük olanını kullanın. Görüntü ve hedef görüntüdeki fuzz özellikleri için çeşitli değerler deneyin.


Teşekkürler, ancak çalıştıramam - değil mi?
Niels Kristian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.