5.11. Çerçeve farkı alma

Çerçeve farkı alma, sahnenin değişen kısımlarını bulmak için her yeni çerçeveyi saklanan bir referans çerçeveyle karşılaştırır. Bir şeyin olmasını izleyen kamera uygulamalarının temel taşıdır – hareketle tetiklenen yakalama, izinsiz giriş uyarıları, “bir şey hareket ettiğinde video kaydet” – ve tamamen daha önce ele alınan piksel bazlı işlemlerden oluşur: mutlak fark, bir eşik ve her çerçevede çalıştırılan bir bölge araması.

5.11.1. Temel işlem hattı

İlk aşama bir referans elde etmektir. Başlangıca yakın bir noktada – ideal olarak sahne “değişiklik yok” anlamına gelen durumdayken – uygulama bir çerçeve yakalar ve onu saklar. Bu çerçeve, sonraki her yakalamanın karşılaştırılacağı temel hale gelir.

reference = csi0.snapshot().copy()

.copy() önemlidir. csi0.snapshot() tek başına, arabelleği çerçeve arabelleğinde (frame buffer) bulunan ve snapshot çağrısının bir sonrakinin üzerine yazacağı bir Image döndürür. .copy() referans için ayrı bir arabellek ayırır ve bu çerçevenin piksellerinin bir sonraki yakalamadan sonra da var olmasını sağlar.

İkinci aşama her çerçevede çalışır: yeni bir görüntü yakalanır, ardından bu görüntü ile referans arasındaki mutlak fark hesaplanır. difference() tam olarak bunu yapar:

current = csi0.snapshot()
current.difference(reference)

Bu çağrıdan sonra current, sıfır olmayan pikselleri referansın alındığı andan bu yana sahnenin değiştiği her konumu işaretleyen bir görüntü tutar; her pikselin büyüklüğü o konumda ne kadar değiştiğiyle orantılıdır.

Üçüncü aşama fark görüntüsünü eşikler. Ham fark her zaman bir miktar gürültü içerir: sensör atış gürültüsünden kaynaklanan küçük parlaklık değişimleri, aydınlatma kaymasından kaynaklanan gradyan değişiklikleri, hafif kamera hareketinden kaynaklanan piksel altı titreşimler. Bir eşikleme adımı – bu gürültü tabanının üzerine ayarlanmış bir eşikle binary() – yalnızca gerçek hareket sayılacak kadar büyük değişiklikleri korur ve geri kalanını atar; sıfır olmayan pikselleri gerçekten değişmiş konumlar olan ikili bir görüntü üretir.

Dördüncü aşama bu ikili maskenin bağlı bölgelerini – bitişik parçalar oluşturan komşu sıfır olmayan piksel gruplarını – çıkarır. find_blobs() bunu tek bir çağrıda yapar ve her biri bir sınırlayıcı kutuya ve bir piksel sayısına sahip, uygulamanın geri kalanının üzerinde işlem yapabileceği bir hareket bölgeleri listesi döndürür.

Yatay bir işlem hattı diyagramı. En soldaki iki panel, aralarında bir artı işareti bulunan, yan yana bir referans çerçevesi ve bir mevcut çerçevedir. Bir ok bu çiftten, koyu bir arka plana karşı birkaç parçanın parlak olduğu fark etiketli üçüncü bir panele yönlenir. Bir ok oradan, farkın ikili eşiklenmiş bir sürümünü gösteren dördüncü bir panele yönlenir; aynı parçalar artık tamamen beyazdır. Son bir ok, her parçanın etrafına çizilmiş dikdörtgen sınırlayıcı kutularla işaretlenmiş ikili maskeyi gösteren beşinci bir panele yönlenir.

Çerçeve farkı alma işlem hattı: bir referans çerçevesi ile bir mevcut çerçeve bir fark görüntüsüne dönüşür; eşikleme, farkı değişen konumların ikili maskesine çevirir; bir bağlı bölge adımı maskeyi bir hareket bölgeleri listesine çevirir.

5.11.2. Bellek içi ve disk üzerindeki referanslar

Temel işlem hattı referans çerçevesini RAM’de tutar. Referans betiğin bu çalışmasında yakalandığında ve yalnızca betik çalıştığı sürece var olması gerektiğinde doğru yanıt budur.

Uzun süre çalışan bir uygulama için – güç döngüsünden sonra değişiklik algılamayı sürdürmesi gereken bir kamera, daha önceki bir andan bu yana herhangi bir değişikliği algılaması gereken aralıklı bir betik – referans çerçevesinin çalışan betikten daha uzun ömürlü olması gerekir. Bunun yöntemi referansı diske kaydetmektir:

csi0.snapshot().save("/sdcard/reference.bmp")

ve her çalışmanın başında onu geri yüklemektir:

reference = image.Image("/sdcard/reference.bmp")

Fark alma mantığı değişmez; yalnızca referansın yakalamalar arasında nerede yaşadığı değişir. Birkaç iyileştirme bu disk üzerindeki varyantı doğal olarak genişletir – bir zamanlayıcıyla referansın otomatik olarak yeniden yakalanması, yavaş aydınlatma kaymasını izlemek için isteğe bağlı hareketli ortalamalar – ancak merkezdeki yerine koyma işlemi aynıdır.

5.11.3. Işık kaynağı yalıtımı

Aynı çıkarma yöntemi biraz farklı bir ortamda da karşımıza çıkar: bir ışık kaynağını sahnenin geri kalanına karşı yalıtmak. Püf noktası bir “ışıklar kapalı” referansı yakalamaktır – algılanan şey (bir IR işaret vericisi, bir ekran pikseli, bir durum göstergesi) aydınlatılmadığında alınan bir çerçeve – ve bu referansı sonraki her çerçeveden çıkarmaktır. Sonuç, her iki yakalamada da sahnenin aynı olduğu her yerde sıfır parlaklığa, yalnızca ışık kaynağının gerçekten yandığı yerde sıfır olmayan parlaklığa sahiptir.

5.11.4. difference mi yoksa sub mu seçilmeli

Hangi aritmetik işlemin seçileceğine dair pratik bir not. difference(), değişimin mutlak değerini döndürür – işaretsiz – bu da onu her iki yöndeki değişime (parlaklaşma veya kararma) duyarlı hale getirir, ancak uygulamaya değişimin hangi yönde gittiğini söylememe pahasına. Saf hareket algılama için doğru yanıt budur: hareket eden her şey ilginçtir, parlaklığın hangi yöne kaydığından bağımsız olarak.

Işık kaynağı algılama için, yanan piksel her zaman ışıklar kapalı referansından daha parlaktır, bu yüzden sub() (sıfırda kırpmasıyla) daha dürüst seçimdir. Mevcut çerçevenin referanstan daha karanlık olduğu her yer (ki bu, yanmamış değer etrafındaki sensör gürültüsü olurdu) yanlış bir “ışık açıktı” sinyali bildirmek yerine sıfıra kırpılır.