2B dizide pik algılama


874

Bir köpek pençesinin altındaki basıncı ölçen bir veteriner kliniğine yardım ediyorum. Veri analizim için Python kullanıyorum ve şimdi pençeleri (anatomik) alt bölgelere ayırmaya çalışıyorum.

Zaman içinde pençe tarafından yüklenen her sensör için maksimum değerlerden oluşan her bir pençenin 2B dizisini yaptım. Burada, 'tespit etmek' istediğim alanları çizmek için Excel kullandığım bir pençe örneği var. Bunlar, birlikte en büyük miktara sahip yerel maksimumlara sahip sensörün etrafında 2 x 2 kutu.

alternatif metin

Bu yüzden biraz deneme yaptım ve her sütun ve satırın maksimumlarını aramaya karar verdim (pençenin şekli nedeniyle bir yöne bakamıyorum). Bu, ayrı ayak parmaklarının konumunu oldukça iyi 'tespit ediyor' gibi görünüyor, ancak aynı zamanda komşu sensörleri de işaret ediyor.

alternatif metin

Peki Python'a bu maksimumlardan hangilerini istediğimi söylemenin en iyi yolu ne olurdu?

Not: 2x2 kareler üst üste binemez, çünkü ayrı ayak parmakları olmalıdır!

Ayrıca 2x2'yi kolaylık olarak aldım, daha gelişmiş bir çözüm hoş geldiniz, ama ben sadece bir insan hareketi bilim insanıyım, bu yüzden ne gerçek bir programcı ya da matematikçiyim, bu yüzden lütfen 'basit' tutun.

İşte yüklenebilecek bir sürümnp.loadtxt


Sonuçlar

Bu yüzden @ jextee'nin çözümünü denedim (aşağıdaki sonuçlara bakın). Gördüğünüz gibi, ön pençelerde çok çalışıyor, ancak arka ayaklar için daha az çalışıyor.

Daha spesifik olarak, dördüncü ayak parmağı olan küçük zirveyi tanıyamaz. Bu, halkanın, nerede olduğunu hesaba katmadan, en düşük değere doğru yukarıdan baktığı gerçeğinin doğasında açıktır.

4. ayak parmağını da bulabilmek için @ jextee'nin algoritmasını nasıl ayarlayacağını bilen var mı?

alternatif metin

Henüz başka bir deneme işlemediğim için başka örnek veremiyorum. Ama daha önce verdiğim veriler her bir pençenin ortalamalarıydı. Bu dosya, plaka ile temas ettikleri sırayla 9 pençelik maksimum verilere sahip bir dizidir.

Bu görüntü plaka üzerinde nasıl uzamsal olarak yayıldıklarını göstermektedir.

alternatif metin

Güncelleme:

İlgilenen herkes için bir blog oluşturdum ve tüm ham ölçümlerle bir SkyDrive kurduk. Daha fazla veri isteyen herkese: daha fazla güç!


Yeni güncelleme:

Bu yüzden pençe tespiti ve pençe sıralama ile ilgili sorularımdan sonra yardımımdan sonra , sonunda her pençe için ayak parmağı tespitini kontrol edebildim! Görünen o ki, kendi örneğiminki gibi büyüklükteki pençelerden başka hiçbir şeyde iyi çalışmıyor. Gezinti dışında, 2x2'yi çok keyfi olarak seçmek benim hatam.

İşte nerede yanlış gittiğine güzel bir örnek: bir çivi ayak parmağı olarak kabul ediliyor ve 'topuk' çok geniş, iki kez tanınıyor!

alternatif metin

Pençe çok büyük, bu nedenle üst üste binmeden 2x2 boyutunda almak, bazı ayak parmaklarının iki kez tespit edilmesine neden oluyor. Diğer taraftan, küçük köpeklerde genellikle 2x2 alanın çok büyük olmasından kaynaklandığından şüphelenilen 5. ayak parmağını bulamıyor.

Tüm ölçümlerimde mevcut çözümü denedikten sonra , neredeyse tüm küçük köpeklerim için 5. ayak parmağı bulamadığı ve büyük köpekler için etkilerin% 50'sinden fazlasında daha fazla bulacağı sonucuna vardım.

Açıkça değiştirmem gerekiyor. Kendi tahminim boyutunu neighborhoodküçük köpekler için daha küçük ve büyük köpekler için daha büyük bir şey değiştiriyordu . Ama generate_binary_structuredizinin boyutunu değiştirmeme izin vermedi.

Bu nedenle, belki de pençe boyutu ile ayak bölgesi ölçeği sahip, başka birinin ayak parmaklarını bulmak için daha iyi bir öneri var umuyoruz?


Virgüllerin değer ayırıcılardan ziyade ondalık basamaklar olduğunu düşünüyorum.
MattH

Evet, virgül. Ve @Christian, kolay okunabilir bir dosyaya yapıştırmaya çalışıyorum, ama bu bile benim için başarısız oluyor :(
Ivo Flipse

3
Bir fizibilite çalışması yaparken, her şey gerçekten gidiyor. Bu yüzden, alt bölgeler de dahil olmak üzere baskıyı tanımlamak için birçok yol arıyorum. Ayrıca oryantasyonu tahmin etmek için 'ayak başparmağı' ve 'ayak başparmağı' tarafları arasında ayrım yapabilmem gerekiyor. Ama bu daha önce yapılmadığından, ne bulabileceğimizi söyleyemeyiz :-)
Ivo Flipse

2
@Ron: Bu çalışmanın amaçlarından biri, sistemin hangi köpek büyüklüğünün / ağırlığının uygun olduğunu görmektir, bu yüzden evet, bu köpek yaklaşık 20 kg iken. Oldukça küçük (ve daha büyük) bazı var ve gerçek küçük olanlar için aynısını yapamayacağım bekliyoruz.
Ivo Flipse

2
@ pençeler zamanla ölçülür, bu nedenle 3. boyut. Ancak, noktalarından (göreceli olarak) hareket etmiyorlar, bu yüzden çoğunlukla ayak parmaklarının 2D'de nerede bulunduğuyla ilgileniyorum. 3D yönü bundan sonra ücretsiz olarak geliyor
Ivo Flipse

Yanıtlar:


331

Maksimum bir yerel filtre kullanarak zirveleri tespit ettim . İlk 4 paws veri kümenizdeki sonuç: Zirve tespit sonucu

Ayrıca 9 pençenin ikinci veri kümesinde koştum ve de çalıştı .

Bunu nasıl yapacağınız aşağıda açıklanmıştır:

import numpy as np
from scipy.ndimage.filters import maximum_filter
from scipy.ndimage.morphology import generate_binary_structure, binary_erosion
import matplotlib.pyplot as pp

#for some reason I had to reshape. Numpy ignored the shape header.
paws_data = np.loadtxt("paws.txt").reshape(4,11,14)

#getting a list of images
paws = [p.squeeze() for p in np.vsplit(paws_data,4)]


def detect_peaks(image):
    """
    Takes an image and detect the peaks usingthe local maximum filter.
    Returns a boolean mask of the peaks (i.e. 1 when
    the pixel's value is the neighborhood maximum, 0 otherwise)
    """

    # define an 8-connected neighborhood
    neighborhood = generate_binary_structure(2,2)

    #apply the local maximum filter; all pixel of maximal value 
    #in their neighborhood are set to 1
    local_max = maximum_filter(image, footprint=neighborhood)==image
    #local_max is a mask that contains the peaks we are 
    #looking for, but also the background.
    #In order to isolate the peaks we must remove the background from the mask.

    #we create the mask of the background
    background = (image==0)

    #a little technicality: we must erode the background in order to 
    #successfully subtract it form local_max, otherwise a line will 
    #appear along the background border (artifact of the local maximum filter)
    eroded_background = binary_erosion(background, structure=neighborhood, border_value=1)

    #we obtain the final mask, containing only peaks, 
    #by removing the background from the local_max mask (xor operation)
    detected_peaks = local_max ^ eroded_background

    return detected_peaks


#applying the detection and plotting results
for i, paw in enumerate(paws):
    detected_peaks = detect_peaks(paw)
    pp.subplot(4,2,(2*i+1))
    pp.imshow(paw)
    pp.subplot(4,2,(2*i+2) )
    pp.imshow(detected_peaks)

pp.show()

Daha sonra yapmanız gereken tek şey, scipy.ndimage.measurements.labeltüm farklı nesneleri etiketlemek için maske üzerinde kullanmaktır . Sonra onlarla bireysel olarak oynayabileceksiniz.

Arka plan gürültülü olmadığından yöntemin iyi çalıştığını unutmayın . Eğer öyleyse, arka planda bir sürü başka istenmeyen zirve tespit edersiniz. Bir diğer önemli faktör mahallenin büyüklüğüdür . Tepe boyutu değişirse ayarlamanız gerekecektir (kabaca orantılı kalmalıdır).


1
(Eroded_background ^ local_peaks) 'den daha basit bir çözüm var. Just do (ön plan & yerel zirveler)
Ryan Soklaski

53

Çözüm

Veri dosyası: paw.txt . Kaynak kodu:

from scipy import *
from operator import itemgetter

n = 5  # how many fingers are we looking for

d = loadtxt("paw.txt")
width, height = d.shape

# Create an array where every element is a sum of 2x2 squares.

fourSums = d[:-1,:-1] + d[1:,:-1] + d[1:,1:] + d[:-1,1:]

# Find positions of the fingers.

# Pair each sum with its position number (from 0 to width*height-1),

pairs = zip(arange(width*height), fourSums.flatten())

# Sort by descending sum value, filter overlapping squares

def drop_overlapping(pairs):
    no_overlaps = []
    def does_not_overlap(p1, p2):
        i1, i2 = p1[0], p2[0]
        r1, col1 = i1 / (width-1), i1 % (width-1)
        r2, col2 = i2 / (width-1), i2 % (width-1)
        return (max(abs(r1-r2),abs(col1-col2)) >= 2)
    for p in pairs:
        if all(map(lambda prev: does_not_overlap(p,prev), no_overlaps)):
            no_overlaps.append(p)
    return no_overlaps

pairs2 = drop_overlapping(sorted(pairs, key=itemgetter(1), reverse=True))

# Take the first n with the heighest values

positions = pairs2[:n]

# Print results

print d, "\n"

for i, val in positions:
    row = i / (width-1)
    column = i % (width-1)
    print "sum = %f @ %d,%d (%d)" % (val, row, column, i)
    print d[row:row+2,column:column+2], "\n"

Çıktı üste binmeyen kareler olmadan . Örneğinizde olduğu gibi aynı alanların seçildiği anlaşılıyor.

Bazı yorumlar

Zor kısım, tüm 2x2 karelerin toplamlarını hesaplamaktır. Hepsine ihtiyacın olduğunu varsaydım, bu yüzden bazı örtüşmeler olabilir. İlk / son sütunları ve satırları orijinal 2B diziden kesmek ve daha sonra hepsini bir araya getirmek ve toplamları hesaplamak için dilimleri kullandım.

Daha iyi anlamak için bir 3x3 dizisi görüntüleyin:

>>> a = arange(9).reshape(3,3) ; a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

Sonra dilimlerini alabilirsin:

>>> a[:-1,:-1]
array([[0, 1],
       [3, 4]])
>>> a[1:,:-1]
array([[3, 4],
       [6, 7]])
>>> a[:-1,1:]
array([[1, 2],
       [4, 5]])
>>> a[1:,1:]
array([[4, 5],
       [7, 8]])

Şimdi onları üst üste yığtığınızı ve elemanları aynı pozisyonlarda topladığınızı düşünün. Bu toplamlar, sol üst köşenin aynı konumda olduğu 2x2 kareler üzerindeki toplamlarla aynı olacaktır:

>>> sums = a[:-1,:-1] + a[1:,:-1] + a[:-1,1:] + a[1:,1:]; sums
array([[ 8, 12],
       [20, 24]])

Eğer 2x2 kareler üzerinde meblağlar varsa, kullanabilirsiniz maxmaksimum bulmak için, ya sort, veya sortedmeydana getirilir.

Piklerin konumlarını hatırlamak için her değeri (toplamı) düzleştirilmiş bir dizideki sıralı konumu ile birleştiriyorum (bkz. zip ). Sonra sonuçları yazdırdığımda satır / sütun konumunu tekrar hesaplıyorum.

notlar

2x2 karelerin çakışmasına izin verdim. Düzenlenmiş sürüm, bazılarında, sonuçlarda yalnızca çakışmayan kareler görünecek şekilde filtreler.

Parmak seçimi (bir fikir)

Başka bir sorun, tüm zirvelerden parmak olması muhtemel olanın nasıl seçileceğidir. Çalışabilecek veya çalışmayabilecek bir fikrim var. Şu anda uygulamak için zamanım yok, bu yüzden sadece sözde kod.

Ön parmaklar neredeyse mükemmel bir dairede kalırsa, arka parmağın o dairenin içinde olması gerektiğini fark ettim. Ayrıca, ön parmaklar aşağı yukarı eşit aralıklıdır. Parmakları tespit etmek için bu sezgisel özellikleri kullanmaya çalışabiliriz.

Sahte kod:

select the top N finger candidates (not too many, 10 or 12)
consider all possible combinations of 5 out of N (use itertools.combinations)
for each combination of 5 fingers:
    for each finger out of 5:
        fit the best circle to the remaining 4
        => position of the center, radius
        check if the selected finger is inside of the circle
        check if the remaining four are evenly spread
        (for example, consider angles from the center of the circle)
        assign some cost (penalty) to this selection of 4 peaks + a rear finger
        (consider, probably weighted:
             circle fitting error,
             if the rear finger is inside,
             variance in the spreading of the front fingers,
             total intensity of 5 peaks)
choose a combination of 4 peaks + a rear peak with the lowest penalty

Bu kaba-kuvvet yaklaşımıdır. N nispeten küçükse, bence yapılabilir. N = 12 için, C_12 ^ 5 = 792 kombinasyonu, arka parmağı seçmek için 5 kez yol vardır, bu nedenle her pençe için değerlendirilecek 3960 vaka.


Sonuç listeniz göz önüne alındığında pençeleri manuel olarak filtrelemek zorunda kalacak ... en üstteki dört sonucu seçmek, ona maksimum değeri 6.8 olan 2x2 kare oluşturmak için dört olasılık kazandıracak
Johannes Charra

2x2 kutuları üst üste binemiyor, çünkü istatistik yapmak istiyorsam, aynı bölgeyi kullanmak istemiyorum, bölgeleri karşılaştırmak istiyorum :-)
Ivo Flipse

Cevabı düzenledim. Artık sonuçlarda örtüşen kareler yok.
sastanin

1
Ben denedim ve ön pençeler için çalışıyor gibi görünüyor, ama arka olanlar için daha az. Nereye bakacağımızı bilen bir şey denemek zorundayız
Ivo Flipse

1
Sahte kodda parmakların nasıl tespit edilebileceği fikrimi açıkladım. Eğer hoşuna giderse, yarın akşam uygulamaya çalışabilirim.
sastanin

34

Bu bir görüntü kayıt problemidir . Genel strateji:

  • Bilinen bir örneğiniz veya veriler üzerinde bir tür öneriniz var.
  • Verilerinizi örneğe veya örneği verilerinize sığdırın.
  • İlk etapta verilerinizin kabaca hizalanması yardımcı olur .

İşte kaba ve hazır bir yaklaşım , "muhtemelen işe yarayabilecek en aptalca şey":

  • Beklediğiniz yerde beş parmak koordinatıyla başlayın.
  • Her biri ile tekrar tekrar tepenin üstüne tırmanıyor. yani geçerli konum verildiğinde, değeri geçerli pikselden büyükse maksimum komşu piksele geçin. Ayak parmağı koordinatlarınızın hareketi durduğunda durun.

Oryantasyon problemine karşı koymak için, temel yönler için (Kuzey, Kuzey Doğu, vb.) 8 veya daha fazla başlangıç ​​ayarınız olabilir. Her birini ayrı ayrı çalıştırın ve iki veya daha fazla parmağın aynı pikselde bittiği tüm sonuçları atın. Bunu biraz daha düşüneceğim, ancak görüntü işlemede bu tür şeyler hala araştırılıyor - doğru cevap yok!

Biraz daha karmaşık bir fikir: (ağırlıklı) K-kümeleme anlamına gelir. O kadar da kötü değil.

  • Beş ayak parmağı koordinatı ile başlayın, ancak şimdi bunlar "küme merkezleri" dir.

Sonra yakınsama kadar tekrarlayın:

  • Her pikseli en yakın kümeye atayın (sadece her küme için bir liste yapın).
  • Her kümenin kütle merkezini hesaplayın. Her küme için bu: Toplam (koordinat * yoğunluk değeri) / Toplam (koordinat)
  • Her kümeyi yeni kütle merkezine taşıyın.

Bu yöntem neredeyse kesinlikle çok daha iyi sonuçlar verecektir ve her kümenin ayak parmaklarını tanımlamaya yardımcı olabilecek kütlesini alırsınız.

(Yine, öndeki kümelerin sayısını belirttiniz. Kümeleme ile yoğunluğu şu veya bu şekilde belirtmelisiniz: Ya bu durumda uygun küme sayısını seçin veya bir küme yarıçapı seçin ve kaç tane sona erdirdiğinizi görün İkincisinin bir örneği ortalama kaydırmadır .)

Uygulama ayrıntılarının veya diğer özelliklerin eksikliğinden dolayı özür dileriz. Bunu kodlarým ama son teslim tarihim var. Gelecek hafta başka bir şey işe yaramadıysa bana bildirin, ben de denemek istiyorum.


1
Sorun, pençelerin yönlerini değiştirmeleri ve başlamak için doğru bir pençenin kalibrasyonu / taban çizgisi olmaması. Artı, görüntü tanıma algoritmalarının birçoğunun ligimin dışında kalmasından korkuyorum.
Ivo Flipse

"Kaba ve hazır" yaklaşım oldukça basit - belki de iyi bir fikir vermedim. Göstermek için bir sahte kod koyacağım.
CakeMaster

Önerinin arka pençelerin tanınmasını düzeltmeye yardımcı olacağına dair bir his var, sadece 'nasıl' bilmiyorum
Ivo Flipse

Bir fikir daha ekledim. Bu arada, iyi bir veri yükünüz varsa, bir yere çevrimiçi koymak harika olurdu. Görüntü işleme / makine öğrenimi okuyan insanlar için yararlı olabilir ve bundan biraz daha kod alabilirsiniz ...
CakeMaster

1
Sadece veri işlemimi basit bir Wordpress blogunda yazmayı düşünüyordum, sadece başkaları için kullanıyordum ve yine de yazmalıyım. Tüm önerilerinizi beğeniyorum, ama son teslim tarihi olmayan birini beklemek zorunda kalacağımdan korkuyorum ;-)
Ivo Flipse

18

Veri kümenizi analiz etmek için kalıcı homoloji kullanarak aşağıdaki sonucu alıyorum (büyütmek için tıklayın):

Sonuç

Bu, bu SO cevabında açıklanan pik tespit yönteminin 2D versiyonudur . Yukarıdaki şekil, kalıcılığa göre sıralanmış 0 boyutlu kalıcı homoloji sınıflarını göstermektedir.

Orijinal veri kümesini scipy.misc.imresize () kullanarak 2 kat büyüttüm. Ancak, dört pençeyi bir veri kümesi olarak gördüğümü unutmayın; onu dörde bölmek sorunu kolaylaştırır.

Metodoloji. Bunun oldukça basit arkasındaki fikir: Her pikseli seviyesini atayan fonksiyonun fonksiyon grafiğini düşünün. Şöyle görünüyor:

3D fonksiyon grafiği

Şimdi 255 yükseklikte, sürekli olarak daha düşük seviyelere inen bir su seviyesi düşünün. Yerel maxima adalarında açılır (doğum). Eyer noktalarında iki ada birleşir; alt adanın yüksek adaya (ölüm) birleştirileceğini düşünüyoruz. Kalıcılık diyagramı (0. boyutsal homoloji sınıflarının, adalarımız), tüm adaların doğumdan ölüm değerlerini tasvir eder:

Kalıcılık diyagramı

sebat , bir ada daha sonra doğum ve ölüm seviyesi arasındaki fark; bir noktanın gri ana köşegen ile dikey mesafesi. Şekilde adalar kalıcılığı azaltarak etiketleniyor.

İlk resim, adaların doğum yerlerini gösterir. Bu yöntem sadece yerel azami değerleri vermekle kalmaz, aynı zamanda bunların "önemlerini" yukarıda belirtilen kalıcılıkla ölçmektedir. Daha sonra kalıcılığı çok düşük olan tüm adalar filtrelenir. Ancak, örneğinizde her ada (yani her yerel maksimum) aradığınız bir zirve.

Python kodu burada bulunabilir .


16

Bu problem fizikçiler tarafından derinlemesine incelenmiştir. KÖK'de iyi bir uygulama vardır . Bak TSpectrum sınıfları (özellikle TSpectrum2 dava için) ve onlar için dokümantasyon.

Referanslar:

  1. M.Morhac ve diğerleri: Çok boyutlu tesadüf gama ışını spektrumları için arka plan eliminasyon yöntemleri. Fizik Araştırmalarında Nükleer Enstrümanlar ve Yöntemler A 401 (1997) 113-132.
  2. M.Morhac ve ark .: Etkin bir ve iki boyutlu Altın dekonvolüsyonu ve gama ışını spektrumlarının ayrışmasına uygulanması. Fizik Araştırmalarında Nükleer Enstrümanlar ve Yöntemler A 401 (1997) 385-408.
  3. M.Morhac ve diğerleri: Çok boyutlu tesadüf gama ışını spektrumlarında piklerin tanımlanması. Araştırma Fiziğinde Nükleer Enstrümanlar ve Yöntemler A 443 (2000), 108-125.

... ve NIM aboneliğine erişimi olmayanlar için:


Makaleye göz atmak için burada çalıştığımla aynı veri işlemeyi tarif ediyor gibi görünüyor, ancak programlama becerilerimi büyük ölçüde aştığından korkuyorum :(
Ivo Flipse

@Ivo: Bunu asla kendim uygulamaya çalışmadım. Sadece ROOT kullanıyorum. Python bağlamaları var, hiç yok, ama ROOT'un oldukça ağır bir paket olduğunu unutmayın.
dmckee --- ex-moderator kitten

@Ivo Flipse: dmckee'ye katılıyorum. Diğer cevaplarda umut vaat eden birçok ipucunuz var. Eğer hepsi başarısız olursa ve biraz zaman ayırmak istiyorsanız, KÖK'e girebilirsiniz ve muhtemelen (muhtemelen) ihtiyacınız olanı yapacaktır. Python bağları üzerinden (doğal C ++ yerine) ROOT öğrenmeye çalışan birini hiç tanımadım, bu yüzden size şans diliyorum.
physicsmichael

13

İşte bir fikir: görüntünün (ayrık) Laplacianını hesaplarsınız. Orijinal görüntülerde olduğundan daha dramatik bir şekilde, maxima'da (negatif ve) büyük olmasını beklerdim. Böylece, maxima'yı bulmak daha kolay olabilir.

Başka bir fikir: yüksek basınçlı noktaların tipik boyutunu biliyorsanız, önce aynı boyutta bir Gaussian ile kıvrım yaparak görüntünüzü yumuşatabilirsiniz. Bu size işlenecek daha basit görüntüler verebilir.


11

Kafamın üstünden birkaç fikir:

  • taramanın gradyanını (türevini) alın, bunun yanlış çağrıları ortadan kaldırıp gidermediğine bakın
  • yerel maksimumu maksimuma çıkarmak

Ayrıca OpenCV'ye bir göz atmak isteyebilirsiniz , oldukça iyi bir Python API'sı var ve yararlı bulacağınız bazı işlevler olabilir.


Gradyan ile, yamaçların dikliğini hesaplamalıyım, bu belirli bir değerin üzerine çıktığında 'tepe' olduğunu biliyorum? Bunu denedim, ancak ayak parmaklarının bazıları diğerlerine (8 N / cm) kıyasla sadece çok düşük piklere (1.2 N / cm) sahiptir. Peki, çok düşük bir eğim ile zirveleri nasıl ele almalıyım?
Ivo Flipse

2
Degradeyi doğrudan kullanamıyorsam, geçmişte benim için işe yarayan degrade ve maxima'ya bakmaktı, örneğin degrade yerel bir ekstrema ise ve yerel bir maximadayım, o zaman faiz.
ChrisC

11

Şimdiye kadar devam edebileceğinizden eminim, ancak k-means clustering methodunu kullanmanızı önermiyorum. k-means, sizi (herhangi bir boyutta - bunu 3 boyutlu olarak yapıyorum) veri alacak ve farklı sınırlara sahip k kümeleri halinde düzenleyecek denetimsiz bir kümeleme algoritmasıdır. Burada güzel çünkü bu köpeklerin tam olarak kaç tane parmağı olması gerektiğini biliyorsunuz.

Buna ek olarak, gerçekten güzel olan Scipy'de uygulanmaktadır ( http://docs.scipy.org/doc/scipy/reference/cluster.vq.html ).

3D kümeleri mekansal olarak çözmek için neler yapabileceğine bir örnek: resim açıklamasını buraya girin

Yapmak istediğiniz şey biraz farklı (2D ve basınç değerleri içeriyor), ancak yine de bir şans verebileceğinizi düşünüyorum.


10

Ham veriler için teşekkürler. Ben trendeyim ve bu kadarıyla aldım (durağım geliyor). Ben txt dosyanızı regexps ile masaj ve görselleştirme için bazı javascript ile bir html sayfasına plopped var. Burada paylaşıyorum, çünkü benim gibi, bazıları da python'dan daha kolay hacklenebilir olabilir.

Bence iyi bir yaklaşım ölçek ve rotasyon değişmez olacak ve bir sonraki adımım gaussianların karışımlarını araştırmak olacak. (her pençe pedi bir gaussian merkezidir).

    <html>
<head>
    <script type="text/javascript" src="http://vis.stanford.edu/protovis/protovis-r3.2.js"></script> 
    <script type="text/javascript">
    var heatmap = [[[0,0,0,0,0,0,0,4,4,0,0,0,0],
[0,0,0,0,0,7,14,22,18,7,0,0,0],
[0,0,0,0,11,40,65,43,18,7,0,0,0],
[0,0,0,0,14,61,72,32,7,4,11,14,4],
[0,7,14,11,7,22,25,11,4,14,65,72,14],
[4,29,79,54,14,7,4,11,18,29,79,83,18],
[0,18,54,32,18,43,36,29,61,76,25,18,4],
[0,4,7,7,25,90,79,36,79,90,22,0,0],
[0,0,0,0,11,47,40,14,29,36,7,0,0],
[0,0,0,0,4,7,7,4,4,4,0,0,0]
],[
[0,0,0,4,4,0,0,0,0,0,0,0,0],
[0,0,11,18,18,7,0,0,0,0,0,0,0],
[0,4,29,47,29,7,0,4,4,0,0,0,0],
[0,0,11,29,29,7,7,22,25,7,0,0,0],
[0,0,0,4,4,4,14,61,83,22,0,0,0],
[4,7,4,4,4,4,14,32,25,7,0,0,0],
[4,11,7,14,25,25,47,79,32,4,0,0,0],
[0,4,4,22,58,40,29,86,36,4,0,0,0],
[0,0,0,7,18,14,7,18,7,0,0,0,0],
[0,0,0,0,4,4,0,0,0,0,0,0,0],
],[
[0,0,0,4,11,11,7,4,0,0,0,0,0],
[0,0,0,4,22,36,32,22,11,4,0,0,0],
[4,11,7,4,11,29,54,50,22,4,0,0,0],
[11,58,43,11,4,11,25,22,11,11,18,7,0],
[11,50,43,18,11,4,4,7,18,61,86,29,4],
[0,11,18,54,58,25,32,50,32,47,54,14,0],
[0,0,14,72,76,40,86,101,32,11,7,4,0],
[0,0,4,22,22,18,47,65,18,0,0,0,0],
[0,0,0,0,4,4,7,11,4,0,0,0,0],
],[
[0,0,0,0,4,4,4,0,0,0,0,0,0],
[0,0,0,4,14,14,18,7,0,0,0,0,0],
[0,0,0,4,14,40,54,22,4,0,0,0,0],
[0,7,11,4,11,32,36,11,0,0,0,0,0],
[4,29,36,11,4,7,7,4,4,0,0,0,0],
[4,25,32,18,7,4,4,4,14,7,0,0,0],
[0,7,36,58,29,14,22,14,18,11,0,0,0],
[0,11,50,68,32,40,61,18,4,4,0,0,0],
[0,4,11,18,18,43,32,7,0,0,0,0,0],
[0,0,0,0,4,7,4,0,0,0,0,0,0],
],[
[0,0,0,0,0,0,4,7,4,0,0,0,0],
[0,0,0,0,4,18,25,32,25,7,0,0,0],
[0,0,0,4,18,65,68,29,11,0,0,0,0],
[0,4,4,4,18,65,54,18,4,7,14,11,0],
[4,22,36,14,4,14,11,7,7,29,79,47,7],
[7,54,76,36,18,14,11,36,40,32,72,36,4],
[4,11,18,18,61,79,36,54,97,40,14,7,0],
[0,0,0,11,58,101,40,47,108,50,7,0,0],
[0,0,0,4,11,25,7,11,22,11,0,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
],[
[0,0,4,7,4,0,0,0,0,0,0,0,0],
[0,0,11,22,14,4,0,4,0,0,0,0,0],
[0,0,7,18,14,4,4,14,18,4,0,0,0],
[0,4,0,4,4,0,4,32,54,18,0,0,0],
[4,11,7,4,7,7,18,29,22,4,0,0,0],
[7,18,7,22,40,25,50,76,25,4,0,0,0],
[0,4,4,22,61,32,25,54,18,0,0,0,0],
[0,0,0,4,11,7,4,11,4,0,0,0,0],
],[
[0,0,0,0,7,14,11,4,0,0,0,0,0],
[0,0,0,4,18,43,50,32,14,4,0,0,0],
[0,4,11,4,7,29,61,65,43,11,0,0,0],
[4,18,54,25,7,11,32,40,25,7,11,4,0],
[4,36,86,40,11,7,7,7,7,25,58,25,4],
[0,7,18,25,65,40,18,25,22,22,47,18,0],
[0,0,4,32,79,47,43,86,54,11,7,4,0],
[0,0,0,14,32,14,25,61,40,7,0,0,0],
[0,0,0,0,4,4,4,11,7,0,0,0,0],
],[
[0,0,0,0,4,7,11,4,0,0,0,0,0],
[0,4,4,0,4,11,18,11,0,0,0,0,0],
[4,11,11,4,0,4,4,4,0,0,0,0,0],
[4,18,14,7,4,0,0,4,7,7,0,0,0],
[0,7,18,29,14,11,11,7,18,18,4,0,0],
[0,11,43,50,29,43,40,11,4,4,0,0,0],
[0,4,18,25,22,54,40,7,0,0,0,0,0],
[0,0,4,4,4,11,7,0,0,0,0,0,0],
],[
[0,0,0,0,0,7,7,7,7,0,0,0,0],
[0,0,0,0,7,32,32,18,4,0,0,0,0],
[0,0,0,0,11,54,40,14,4,4,22,11,0],
[0,7,14,11,4,14,11,4,4,25,94,50,7],
[4,25,65,43,11,7,4,7,22,25,54,36,7],
[0,7,25,22,29,58,32,25,72,61,14,7,0],
[0,0,4,4,40,115,68,29,83,72,11,0,0],
[0,0,0,0,11,29,18,7,18,14,4,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
]
];
</script>
</head>
<body>
    <script type="text/javascript+protovis">    
    for (var a=0; a < heatmap.length; a++) {
    var w = heatmap[a][0].length,
    h = heatmap[a].length;
var vis = new pv.Panel()
    .width(w * 6)
    .height(h * 6)
    .strokeStyle("#aaa")
    .lineWidth(4)
    .antialias(true);
vis.add(pv.Image)
    .imageWidth(w)
    .imageHeight(h)
    .image(pv.Scale.linear()
        .domain(0, 99, 100)
        .range("#000", "#fff", '#ff0a0a')
        .by(function(i, j) heatmap[a][j][i]));
vis.render();
}
</script>
  </body>
</html>

alternatif metin


1
Bu, sadece Gaytian tekniklerinin işe yarayabileceğine dair bir kavram kanıtı olduğunu düşünüyorum, şimdi sadece bir kişi Python ;-) ile kanıtlayabilirse
Ivo Flipse

8

Fizikçinin çözümü:
Pozisyonları X_iile tanımlanan 5 pençe markörünü tanımlayın ve rastgele pozisyonlarla başlatın. Pençelerin pozisyonlarındaki belirteçlerin yeri için bir miktar ödülü, belirteçlerin üst üste binmesi için bir miktar ceza ile birleştiren bir enerji işlevi tanımlayın; diyelimki:

E(X_i;S)=-Sum_i(S(X_i))+alfa*Sum_ij (|X_i-Xj|<=2*sqrt(2)?1:0)

( S(X_i)2x2 etrafında kare ortalama güç X_i, alfadeneysel zirve gereken bir parametredir)

Şimdi Metropolis-Hastings büyüsü yapma zamanı:
1. Rasgele işaretleyiciyi seçin ve rastgele yönde bir piksel hareket ettirin.
2. dE, bu hareketin neden olduğu enerji farkını hesaplayın.
3. 0-1 arasında tekdüze rastgele bir sayı alın ve bunu r olarak adlandırın.
4. dE<0Veya ise exp(-beta*dE)>r, hareketi kabul edin ve 1'e gidin; değilse, hareketi geri alın ve 1'e gidin.
İşaretçiler pençelere yakınlaşana kadar bu tekrarlanmalıdır. Beta, dengeyi optimize etmek için taramayı kontrol eder, bu nedenle deneysel olarak da optimize edilmelidir; aynı zamanda simülasyon zamanıyla (simüle tavlama) sürekli olarak arttırılabilir.


Bunun benim örneğimde nasıl işe yarayacağını göstermeyi umuyor musunuz? Gerçekten üst düzey matematik içine değilim, bu yüzden zaten önerdiğin formülü çözmek için zor bir zaman var :(
Ivo Flipse

1
Bu lise matematiği, muhtemelen benim gösterim sadece gizlenmiş. Kontrol etmek için bir planým var, bizi izlemeye devam edin.
mbq

4
Ben bir parçacık fizikçisiyim. Uzun bir süre disiplinimizdeki go-to-yazılım aracına PAW adı verildi ve "marker" adı verilen grafiklerle ilgili bir varlığı vardı. Bu cevabı ilk birkaç kez bulduğum kadar kafa karıştırıcı olabilir ...
dmckee --- eski moderatör kedi yavrusu

6

Heres, büyük bir teleskop için benzer bir şey yaparken kullandığım başka bir yaklaşım:

1) En yüksek pikseli arayın. Bunu elde ettikten sonra, 2x2 için en iyi uyumu arayın (belki 2x2 toplamını en üst düzeye çıkarın) veya en yüksek pikselde ortalanmış 4x4 alt bölgesinin içinde 2d gauss uyumu yapın.

Ardından, tepe merkezinin etrafında sıfır (veya belki 3x3) bulduğunuz 2x2 pikseli ayarlayın

1'e geri dönün) ve en yüksek zirve bir gürültü eşiğinin altına düşene veya ihtiyacınız olan tüm ayak parmaklarına sahip olana kadar tekrarlayın.


Bunu yapan bir kod örneği paylaşmak ister misiniz? Ne yapmaya çalıştığınızı takip edebilirim, ama kendim nasıl
kodlayacağımı

Aslında Matlab ile çalışmaktan geliyorum, bu yüzden evet zaten yardımcı olurdu. Ama gerçekten yabancı işlevler kullanıyorsanız, bunu Python
Ivo Flipse

6

Bazı eğitim verileri oluşturabiliyorsanız, sinir ağlarını denemeye değer ... ama bunun elle açıklamalı birçok örneğe ihtiyacı var.


Eğer zahmete değerse, büyük bir örneği elle açıklama yapmayı düşünmezdim. Benim sorunum şu olurdu: Sinir ağlarını programlama hakkında hiçbir şey bilmediğim için bunu nasıl uygularım
Ivo Flipse

6

kaba bir taslak ...

muhtemelen her bir pençe bölgesini izole etmek için bağlı bir bileşenler algoritması kullanmak istersiniz. wiki'nin burada (bazı kodlarla) iyi bir açıklaması var: http://en.wikipedia.org/wiki/Connected_Component_Labeling

4 veya 8 bağlantılılık kullanıp kullanmayacağınıza karar vermeniz gerekir. şahsen, çoğu problem için 6 bağlantılılığı tercih ederim. Her neyse, her "pençe baskısını" bağlı bir bölge olarak ayırdıktan sonra, bölgeyi yineleyip maksimumu bulmak yeterince kolay olmalıdır. maxima'yı bulduktan sonra, belirli bir "ayak" olarak tanımlamak için önceden belirlenmiş bir eşiğe ulaşana kadar bölgeyi tekrar tekrar büyütebilirsiniz.

Buradaki ince bir sorun, bir şeyi sağ / sol / ön / arka pençe olarak tanımlamak için bilgisayar görme tekniklerini kullanmaya başlar başlamaz ve ayak parmaklarına bakmaya başlar başlamaz, rotasyonları, eğrileri ve çevirileri dikkate almaya başlamanız gerektiğidir. bu, "momentler" denilen analizle gerçekleştirilir. görme uygulamalarında dikkate alınması gereken birkaç farklı an vardır:

merkezi anlar: çeviri değişmezi normalleştirilmiş anlar: ölçekleme ve çeviri değişmezi hu momentleri: çeviri, ölçek ve dönme değişmezi

anları hakkında daha fazla bilgiyi wiki'de "görüntü anları" arayarak bulabilirsiniz.



4

Görünüşe göre jetxee'nin algoritmasını kullanarak biraz hile yapabilirsiniz. İlk üç parmağı iyi buluyor ve dördüncünün buna dayandığını tahmin edebilmelisin.


4

İlginç bir sorun. Deneyeceğim çözüm şudur.

  1. 2D gaussian maske ile kıvrım gibi düşük geçişli bir filtre uygulayın. Bu size bir grup (muhtemelen, ancak mutlaka kayan nokta) değerler verecektir.

  2. Her bir pençe pedinin (veya ayak parmağının) bilinen yaklaşık yarıçapını kullanarak 2B maksimal olmayan baskılama gerçekleştirin.

Bu, birbirine yakın birden fazla adayınız olmadan size maksimum pozisyonları vermelidir. Açıklığa kavuşturmak için, 1. adımdaki maskenin yarıçapı 2. adımda kullanılan yarıçapa benzer olmalıdır. Bu yarıçap seçilebilir veya veteriner önceden açık bir şekilde ölçebilir (yaş / cins / vb. İle değişecektir).

Önerilen çözümlerin bazıları (ortalama kayma, sinir ağları vb.) Muhtemelen bir dereceye kadar çalışacaktır, ancak aşırı derecede karmaşıktır ve muhtemelen ideal değildir.


Evrişim matrisleri ve Gauss filtreleri ile ilgili 0 deneyimim var, bu yüzden örneğimde nasıl çalışacağını göstermek ister misiniz?
Ivo Flipse

3

İşte basit ve çok verimli olmayan bir kod, ancak bu veri kümesinin boyutu için iyi.

import numpy as np
grid = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
              [0,0,0,0,0,0,0,0,0.4,0.4,0.4,0,0,0],
              [0,0,0,0,0.4,1.4,1.4,1.8,0.7,0,0,0,0,0],
              [0,0,0,0,0.4,1.4,4,5.4,2.2,0.4,0,0,0,0],
              [0,0,0.7,1.1,0.4,1.1,3.2,3.6,1.1,0,0,0,0,0],
              [0,0.4,2.9,3.6,1.1,0.4,0.7,0.7,0.4,0.4,0,0,0,0],
              [0,0.4,2.5,3.2,1.8,0.7,0.4,0.4,0.4,1.4,0.7,0,0,0],
              [0,0,0.7,3.6,5.8,2.9,1.4,2.2,1.4,1.8,1.1,0,0,0],
              [0,0,1.1,5,6.8,3.2,4,6.1,1.8,0.4,0.4,0,0,0],
              [0,0,0.4,1.1,1.8,1.8,4.3,3.2,0.7,0,0,0,0,0],
              [0,0,0,0,0,0.4,0.7,0.4,0,0,0,0,0,0]])

arr = []
for i in xrange(grid.shape[0] - 1):
    for j in xrange(grid.shape[1] - 1):
        tot = grid[i][j] + grid[i+1][j] + grid[i][j+1] + grid[i+1][j+1]
        arr.append([(i,j),tot])

best = []

arr.sort(key = lambda x: x[1])

for i in xrange(5):
    best.append(arr.pop())
    badpos = set([(best[-1][0][0]+x,best[-1][0][1]+y)
                  for x in [-1,0,1] for y in [-1,0,1] if x != 0 or y != 0])
    for j in xrange(len(arr)-1,-1,-1):
        if arr[j][0] in badpos:
            arr.pop(j)


for item in best:
    print grid[item[0][0]:item[0][0]+2,item[0][1]:item[0][1]+2]

Temelde sadece sol üst konum ve her 2x2 karenin toplamı ile bir dizi yapmak ve toplamına göre sıralamak. Daha sonra çekişme dışında en yüksek toplamı olan 2x2 karesini alıyorum, bestdiziye koyuyorum ve bu 2x2 karesinin herhangi bir bölümünü kullanan diğer tüm 2x2 karelerini kaldırıyorum.

Son pençe (ilk resminizde en sağdaki en küçük toplamı olan) hariç, iyi çalışıyor gibi görünüyor, daha büyük bir toplamı olan iki uygun 2x2 kare var (ve eşit bir toplamı var) herbiri). Bunlardan biri hala 2x2 karenizden bir kare seçiyor, ancak diğeri solda. Neyse ki, şans eseri istediğinizi seçtiğimizi görüyoruz, ancak bu her zaman istediğinizi elde etmek için başka fikirlerin kullanılmasını gerektirebilir.


Sonuçlarınızın @ Jextee'nin cevabındaki sonuçlarla aynı olduğunu düşünüyorum. Ya da en azından öyle deniyor benden test ediyorum.
Ivo Flipse


1

Belki burada naif bir yaklaşım yeterlidir: Uçağınızdaki tüm 2x2 karelerin bir listesini oluşturun, toplamlarına göre (azalan sırada) sıralayın.

İlk olarak, "paw listenizden" en değerli kareyi seçin. Ardından, daha önce bulunan karelerden herhangi biriyle kesişmeyen en iyi 4 kareyi tekrar tekrar seçin.


Aslında tüm 2x2 toplamları ile bir liste yaptım, ama onları sipariş ettiğimde, bunları tekrar tekrar nasıl karşılaştıracağım konusunda hiçbir fikrim yoktu. Benim sorunum, onu sıraladığımda koordinatların izini kaybetmemdi. Belki onları sözlükte, koordinatlar anahtar olarak yapıştırabilirdim.
Ivo Flipse

Evet, bir tür sözlük gerekli olacaktır. Izgarayı temsil etmenizin zaten bir çeşit sözlük olduğunu varsayardım.
Johannes Charra

Yukarıda gördüğünüz görüntü nümerik bir dizidir. Gerisi şu anda çok boyutlu listelerde saklanmaktadır. Sözlükleri yinelemeye aşina olmadığım halde bunu yapmayı bırakmak daha iyi olurdu
Ivo Flipse

1

Astronomi ve kozmoloji topluluğundan temin edilebilen birkaç ve kapsamlı yazılımlar vardır - bu hem tarihsel hem de şu anda önemli bir araştırma alanıdır.

Bir gökbilimci değilseniz endişelenmeyin - bazılarının tarla dışında kullanımı kolaydır. Örneğin, astropi / photutils kullanabilirsiniz:

https://photutils.readthedocs.io/en/stable/detection.html#local-peak-detection

[Burada kısa örnek kodlarını tekrarlamak biraz kaba görünüyor.]

İlginizi çekebilecek tekniklerin / paketlerin / bağlantıların eksik ve biraz taraflı bir listesi aşağıda verilmiştir - yorumlara daha fazlasını ekleyin ve bu yanıtı gerektiği gibi güncelleyeceğim. Tabii ki hesaplama kaynaklarına karşı doğruluk değiş tokuşu var. [Dürüst olmak gerekirse, böyle tek bir cevapta kod örnekleri vermek için çok fazla var, bu yüzden bu cevabın uçup uçmayacağından emin değilim.]

Kaynak Çıkarıcı https://www.astromatic.net/software/sextractor

MultiNest https://github.com/farhanferoz/MultiNest [+ pyMultiNest]

ASKAP / DAÜ kaynak bulma zorluğu: https://arxiv.org/abs/1509.03931

Planck ve / veya WMAP kaynak çıkarma zorluklarını da arayabilirsiniz.

...


0

Ya adım adım ilerlerseniz: önce global maksimum değeri bulursanız, gerekirse değerlerini çevreleyen noktaları işlersiniz, sonra bulunan bölgeyi sıfıra ayarlar ve bir sonrakini tekrarlarsınız.


Hmmm, sıfıra ayarlamanın en azından onu başka hesaplamalardan kaldıracaktır, bu yararlı olacaktır.
Ivo Flipse

Sıfıra ayarlamak yerine, elle toplanan parametrelerle bir gauss fonksiyonunu hesaplayabilir ve bulunan değerleri orijinal basınç değerlerinden çıkarabilirsiniz. Eğer ayak parmaklarınızı sensörlere bastırıyorsa, en yüksek basma noktasını bularak, ayak parmağının sensörler üzerindeki etkisini azaltmak, böylece yüksek basınç değerlerine sahip komşu hücreleri ortadan kaldırmak için kullanırsınız. en.wikipedia.org/wiki/File:Gaussian_2d.png
Daniyar

@Daniyar örnek verilerime dayalı bir örnek göstermek ister misiniz? Bu tür bir veri işlemeye gerçekten aşina olmadığım için
Ivo Flipse

0

Bunun soruyu cevapladığından emin değilim, ancak sadece komşuları olmayan en yüksek zirveleri arayabileceğiniz anlaşılıyor.

İşte özü. Ruby'de olduğunu unutmayın, ancak fikir açık olmalıdır.

require 'pp'

NUM_PEAKS = 5
NEIGHBOR_DISTANCE = 1

data = [[1,2,3,4,5],
        [2,6,4,4,6],
        [3,6,7,4,3],
       ]

def tuples(matrix)
  tuples = []
  matrix.each_with_index { |row, ri|
    row.each_with_index { |value, ci|
      tuples << [value, ri, ci]
    }
  }
  tuples
end

def neighbor?(t1, t2, distance = 1)
  [1,2].each { |axis|
    return false if (t1[axis] - t2[axis]).abs > distance
  }
  true
end

# convert the matrix into a sorted list of tuples (value, row, col), highest peaks first
sorted = tuples(data).sort_by { |tuple| tuple.first }.reverse

# the list of peaks that don't have neighbors
non_neighboring_peaks = []

sorted.each { |candidate|
  # always take the highest peak
  if non_neighboring_peaks.empty?
    non_neighboring_peaks << candidate
    puts "took the first peak: #{candidate}"
  else
    # check that this candidate doesn't have any accepted neighbors
    is_ok = true
    non_neighboring_peaks.each { |accepted|
      if neighbor?(candidate, accepted, NEIGHBOR_DISTANCE)
        is_ok = false
        break
      end
    }
    if is_ok
      non_neighboring_peaks << candidate
      puts "took #{candidate}"
    else
      puts "denied #{candidate}"
    end
  end
}

pp non_neighboring_peaks

Ben denemek ve bir göz ve ben Python kodu dönüştürmek olmadığını görmek için gidiyorum :-)
Ivo Flipse

Makul bir uzunluksa, kodu bir özüne bağlamak yerine yazının kendisine ekleyin.
agf
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.