2009-07-20 10 views
10

Używam XNA do zbudowania projektu, w którym mogę narysować "graffiti" na mojej ścianie za pomocą projektora LCD i kamery monochromatycznej, która jest filtrowana, aby widzieć tylko ręczne wskaźniki laserowe. Chcę używać dowolnej liczby wskaźników laserowych - nie obchodzi mnie to w tej chwili.Szybkie wykrywanie punktów subpikselowych laserowych

Ściana 10' x 10' , a aparat jest tylko 640x480 tak ja próbuje użyć pomiar subpiksel użyciem krzywej składanej jak opisano tutaj: tpub.com

zapełnienia w 120fps (8 -bit), więc moje pytanie do was wszystkich jest najszybszą drogą do znalezienia tego centrum lasera subpikselowego. Obecnie używam przeszukiwania 2D w trybie brute force, aby znaleźć najjaśniejszy piksel na obrazie (0 - 254) przed wykonaniem interpolacji splajnu. Ta metoda nie jest zbyt szybka, a każda klatka zajmuje więcej czasu niż komputer.

Edytuj: Aby wyjaśnić, moje dane z kamery są reprezentowane przez dwuwymiarową tablicę bajtów wskazującą jasność pikseli.

Chciałbym użyć cieniowania XNA, aby poprawić obraz. Czy to jest praktyczne? Z tego co rozumiem, tak naprawdę nie ma sposobu na utrzymywanie trwałych zmiennych w module cieniującym Pixel, takich jak sumy bieżące, średnie itd.

Ale z argumentów, załóżmy, że znalazłem najjaśniejsze piksele za pomocą brutalnej siły, a następnie zapisał je i ich sąsiednie piksele na krzywej splajnu na X wierzchołków przy użyciu texcoordów. Czy praktyczne jest wtedy użycie HLSL do obliczenia krzywej splajnu za pomocą texcoord?

Jestem również otwarty na sugestie poza moim XNA boxem, czy to DX10/DX11, może jakiś FPGA, itp. Po prostu nie mam zbyt dużego doświadczenia ze sposobami fałszowania danych w ten sposób. Sądzę, że jeśli mogą zrobić coś takiego na Wii-Mote przy użyciu 2 baterii AA, prawdopodobnie robię to w niewłaściwy sposób.

Wszelkie pomysły?

+0

Co jest powolne, po wykonaniu skanowania lub wykonaniu interpolacji splajnu? – Nosredna

+0

Interpolacja splajnowa jest zdecydowanie najwolniejszym komponentem, w zależności od tego, z którą delta oceniam splajn. W tym przypadku chciałbym uzyskać dokładność 0,1px. – bufferz

+0

Powinienem dodać, że jeśli mam 20 laserów, obliczenia splajnu staną się bardzo drogim cenowo cPU. – bufferz

Odpowiedz

3

Masz do czynienia z dość złożonymi matematykami, jeśli chcesz dokładności subpiksela. Myślę, że this paper należy rozważyć. Niestety, będziesz musiał zapłacić, aby zobaczyć, korzystając z tej strony. Jeśli masz dostęp do odpowiedniej biblioteki, być może uda Ci się ją zdobyć.

Łącze w oryginalnym poście sugerowało wykonanie 1000 obliczeń splajnu dla każdej osi - jest traktowane oddzielnie xi y, co jest dobre dla okrągłych obrazów, ale jest nieco wyłączone, jeśli obraz jest przekrzywioną elipsą. Można użyć następujących uzyskać wystarczającą ocenić:

x c = suma (x n .f (x n))/suma (F (x n))

gdzie x C jest średni, x n jest punktem wzdłuż osi x i F (x n) ma wartość w punkcie x n. Tak na to:

  * 
     * * 
     * * 
     * * 
     * * 
     * * 
     * * * 
    * * * * 
    * * * * 
* * * * * * 
------------------ 
2 3 4 5 6 7 

otrzymujemy:

suma (x n .f (x n)) = 1 * 3 * 2 + 3 + 4 + 5 * 9 * 10 + 6 * 4 + 7 * 1

suma (f (x n)) = 1 + 3 + 9 + 10 + 4 + 1

x C = 128/28 = 4,57

i powtórz dla osi Y.

+0

To działa całkiem dobrze. Działa to znacznie szybciej niż moja implementacja splajnu. To prawie w czasie rzeczywistym! Dziękuję za sugestię. – bufferz

+0

O łączu: po prostu wyszukaj tytuł. Najlepsze trafienie: http://groups.mrl.illinois.edu/granick/Publications/pdf%20files/2009/stephen_2009_image%20analysis%20with%20rapid%20and%20accurate%202d%20gaussian%20fit.pdf – jnm2

5

Jeśli przez Brute-wymuszenie patrzenia na każdy piksel niezależnie, jest to w zasadzie jedyny sposób na zrobienie tego. Będziesz musiał przeskanować wszystkie piksele obrazów, bez względu na to, co chcesz zrobić z obrazem. Mimo że nie musisz szukać najjaśniejszych pikseli, możesz filtrować obraz według kolorów (np .: jeśli używasz czerwonego lasera). Można to łatwo zrobić za pomocą kolorowego obrazu HSV. Jeśli szukasz szybszych algorytmów, wypróbuj OpenCV. To znowu i znowu zoptymalizowane do obróbki obrazu i można go używać w C# poprzez owinięcie:

[http://www.codeproject.com/KB/cs/Intel_OpenCV.aspx][1]

OpenCV może również pomóc łatwo znaleźć centra punkt i śledzić każdy punkty.

Czy istnieje powód, dla którego używasz kamery 120 klatek na sekundę? Czy wiesz, że oko ludzkie może zobaczyć tylko około 30 fps, prawda? Zgaduję, że chodzi o śledzenie bardzo szybkich ruchów laserowych ... Możesz rozważyć obniżenie go, ponieważ przetwarzanie 120 klatek na sekundę w czasie rzeczywistym będzie bardzo trudne do osiągnięcia.

4

przechodząc przez 640 * 480 bajtów, aby znaleźć najwyższy bajt, powinien działać w ciągu ms. Nawet na wolnych procesorach. Nie trzeba wybierać trasy shaderów.

Poradziłbym, aby zoptymalizować pętlę. na przykład: to jest bardzo powolny (bo robi mnożenia z każdego odnośnika tablicy):

byte highest=0; 
foundX=-1, foundY=-1; 
for(y=0; y<480; y++) 
{ 
    for(x=0; x<640; x++) 
    { 
     if(myBytes[x][y] > highest) 
     { 
      highest = myBytes[x][y]; 
      foundX = x; 
      foundY = y; 
     } 
    } 
} 

to dużo szybciej:

byte [] myBytes = new byte[640*480]; 
//fill it with your image 

byte highest=0; 
int found=-1, foundX=-1, foundY=-1; 
int len = 640*480; 
for(i=0; i<len; i++) 
{ 
    if(myBytes[i] > highest) 
    { 
     highest = myBytes[i]; 
     found = i; 
    } 
} 
if(found!=-1) 
{ 
    foundX = i%640; 
    foundY = i/640; 
} 

Jest poza czubek głowy tak żal błędy; ^)

3

Brute-force to jedyna prawdziwa droga, jednak twój pomysł na użycie shadera jest dobry - odciąłbyś kontrolę brutalnej siły od procesora, który może spojrzeć tylko na niewielką liczbę pikseli jednocześnie (w przybliżeniu 1 na rdzeń), co do prawdopodobnego GPU ma ponad 100 głupich rdzeni (potoków), które mogą jednocześnie porównywać piksele (twój algorytm może wymagać trochę modyfikacji, aby działał dobrze z instrukcją 1 - wiele układów rdzeni GPU).

Największy problem, jaki widzę, to to, czy można przenieść dane na GPU wystarczająco szybko.

+0

Jak mogę śledzić pojedynczy najwyższy piksel na ramie w GPU? Czy rozumiem to poprawnie, ponieważ głupie rdzenie nie mogą dzielić pamięci w sposób, który pozwoliłby im porównać piksel z poprzednim najjaśniejszym pikselem? – bufferz

+1

GPU można uważać za dużą kolekcję naprawdę prostych procesorów zoptymalizowanych pod kątem operacji matematycznych. Największą różnicą jest jednak to, że dekoder instrukcji został usunięty - pojedynczy kontroler wysyła tę samą instrukcję do każdego głupiego rdzenia, gdzie jest wykonywany na tym rdzeniu danych. Instrukcje IF są wykonywane przez dwukrotne uruchomienie tego samego kodu - zamiast rozgałęzień, rdzenie, które nie pasują do warunku, po prostu się zatrzymują. Te same dane są następnie przesyłane ponownie, ale po odwróceniu instrukcji porównania. – David

+1

W twoim przypadku nie można porównać z * bezpośrednim * poprzednim najjaśniejszym pikselem, ponieważ każdy z (powiedzmy) 128 rdzeni mógł znaleźć jaśniejszy piksel. Zamiast tego postaraj się, aby każdy rdzeń koncentrował się na samej linii - znajdź najjaśniejszy piksel w linii (przetwarzając 128 linii jednocześnie). Po tym, jak linie na obrazie zostały skutecznie podsumowane jako najjaśniejszy piksel w tej linii, możesz znaleźć ogólnie najjaśniejszy w sposób szeregowy. – David

1

Połóż aparat nieco nieostry i bitblt na neutralnej próbce. Możesz szybko skanować wiersze dla wartości innych niż 0. Również jeśli masz 8 bitów i odbierasz 4 bajty na raz, możesz szybciej przetworzyć obraz. Jak wskazano, możesz zmniejszyć liczbę klatek na sekundę. Jeśli masz mniej wierności niż wynikowy obraz, nie ma większego sensu w wysokiej częstotliwości skanowania.

(Nieznaczny nieostry kamery pomogą uzyskać tylko najjaśniejsze punkty i zmniejszyć liczbę fałszywych alarmów, jeśli masz zajęty powierzchnię ... oczywiście zakładając, że nie strzelają sprawne/płaską powierzchnię)

2

Kolejna optymalizacja do rozważenia: jeśli rysujesz, aktualna lokalizacja wskaźnika prawdopodobnie zamyka ostatnią lokalizację wskaźnika. Zapamiętaj ostatnią zarejestrowaną pozycję wskaźnika między ramkami, a skanuj tylko obszar znajdujący się w pobliżu tej pozycji ... powiedz obszar 1'x1 '. Tylko wtedy, gdy wskaźnik nie zostanie znaleziony w tym obszarze, należy przeskanować całą powierzchnię.

Oczywiście, pojawi się kompromis pomiędzy tym, jak szybko twój program może skanować, i jak szybko będziesz w stanie poruszać myszą, zanim kamera "straci" wskaźnik i musi przejść do powolnego, pełnego obrazu skandować. Trochę eksperymentów prawdopodobnie ujawni optymalną wartość.

Fajny projekt, przy okazji.

+0

Dlaczego właśnie 1x1. Dlaczego nie zwiększyć rozmiaru 1^2. Więc jeśli nie zostanie znaleziony w 1x1, to sprawdzi 2x2, 4x4 itd. Trochę się troszczysz i możesz przejść przez obszar, który już sprawdziłeś. –

+0

Myślałem o tym również. Ale może mieć wiele laserów, więc i tak będzie musiał patrzeć na każdy piksel. Laser może włączyć lub ponownie wprowadzić obszar bez powiadomienia. – Nosredna

1

Rozpocznij od czarnego bufora wyjściowego. Zapomnij o subpikselie na teraz. Każda klatka, każdy piksel to:

outbuff = max (outbuff, inbuff);

Filtrowanie subpikseli do trzeciego "czystego" bufora, gdy skończysz z obrazem. Możesz też wykonać porcję lub linię ekranu naraz w czasie rzeczywistym. Zaleta: widok "nieobrobionego" widoku w czasie rzeczywistym, oczyszczony podczas podróży.

Po przejściu z bufora surowego wydruku do "czystego" trzeciego bufora, można wyczyścić szorstki do czarnego. Pozwala to na ciągłe rysowanie bez spowalniania.

Rysując "czysty" nad "szorstkim", może w nieco innym kolorze, będziesz miał to co najlepsze z obu światów.

Jest to podobne do programów do malowania - jeśli rysujesz bardzo szybko, zobaczysz wersję z grubsza, a następnie program do malowania "czyści" obraz, gdy będzie miał czas.


Niektóre komentarze na algorytmie:

Widziałem wiele oszustów w tej dziedzinie. Grałem w Sonica na emulatorze Sega Genesis, który pobiera próbki. i ma kilka dość dzikich algorytmów, które działają bardzo dobrze i są bardzo szybkie.

Rzeczywiście masz pewne zalety, które możesz uzyskać, ponieważ możesz znać jasność i promień kropki.

Możesz po prostu popatrzeć na każdy piksel i jego 8 sąsiadów i pozwolić tym 9 pikselom "głosować" w zależności od ich jasności, gdzie znajduje się subpiksel.


Inne myśli

Twoja ręka nie jest tak dokładna, kiedy można kontrolować wskaźnik laserowy. Postaraj się uzyskać wszystkie kropki co 10 klatek, identyfikując które belki są tymi, które (w oparciu o poprzedni ruch, i uwzględniające nowe kropki, wyłączone lasery i kropki, które weszły lub opuściły pole widzenia), a następnie po prostu wysoki poziom krzywa rozdzielczości. Nie martw się o subpiksel na wejściu - po prostu narysuj krzywą do wyjścia o wysokiej rozdzielczości.

Użyj splajnu Catmull-Rom, który przechodzi przez wszystkie punkty kontrolne.

+0

Podoba mi się ten pomysł, ma sens. Więc może reprezentują "czyste" piksele jako struktury zawierające wartości 5x5 pikseli i przechodzą przez nie w kolejce w osobnym wątku. Mimo to wypalenie tej kolejki byłoby ogromnym przedsięwzięciem procesora. Może mogę przechowywać każdą z tych struktur w wierzchołku i tworzyć krzywą spline na karcie graficznej? Wciąż szukam szybkiego sposobu oświetlenia do obliczenia splajnów 2D 5x5. Dziękuję za sugestię wysokiego poziomu! – bufferz

+0

To naprawdę nie ma znaczenia, jak powolne. Możesz później zoptymalizować. Po prostu obserwujesz zegar i widzisz, ile ekranu możesz zrobić dla każdej klatki. – Nosredna