ASK LAB8 KameraVfW


Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
Laboratorium: MS Windows  obsługa kamery
Krok 1. Uruchamiamy Visual Studio C++. Otwieramy nowy projekt (menu-File-
New-Project). Konfigurujemy tak jak na rysunku poniżej. Projekt umieszczamy w
katalogu C:\users\inazwisko gdzie inazwisko to pierwsza litera swojego imienia i
nazwisko (bez spacji).
Rys. 1. Okno zakładania nowego projektu
Krok 2. Konfigurujemy wzorzec projektu tak jak na rysunku poniżej (typu Single
Document).
Rys. 2. Okno konfiguracji projektu
1
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
Krok 3. Otwieramy plik  KameraView.h i wprowadzamy modyfikacje:
1) dołączamy plik  Vfw.h (rys.3)
2) dodajemy pole HWND m_wndKamera (rys.3)
3) Dodajemy symbol ID_CAMWND (rys.4)
1
2
Rys. 3. Modyfikacje w pliku KameraView.h
3
Rys. 4. Dodawanie symbolu ID_CAMWND
2
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
Krok 4. Do klasy CKameraView dodajemy metodę OnInitialUpdate (rys.5).
Wpisujemy kod do utworzonej metody (rys.6). Następnie uruchamiamy program.
Powinniśmy otrzymać komunikat błędu taki jak na rys.7.
void CKameraView::OnInitialUpdate(){
CView::OnInitialUpdate();
// TODO: Add your specialized code here
HWND hwndParent = this->GetSafeHwnd();
m_wndKamera = capCreateCaptureWindow( L"Nazwa",
WS_CHILD | WS_VISIBLE,
10, 10, 640, 480,
hwndParent, ID_CAMWND );
}//---------------------------------------------------
Rys. 6. Kod w OnInitialUpdate()
Rys. 7. Spodziewany komunikat błędów
Rys. 5. Dodawanie metody
OnInitialUpdate
komentarz:
Funkcja capCreateCaptureWindow tworzy okno przechwytywania strumienia wideo.
Wykorzystując technologię Vfw (Video for Windows) trzeba takie okno utworzyć, nawet jeśli nie
chcemy aby było widoczne. Zaleca się spojrzenie do dokumentacji MSDN w celu przeanalizowania
argumentów przekazywanych do funkcji. Ciekawszą obserwacją może być sposób otrzymania
uchwytu do  naszego okna (CKameraView), które ma się stać oknem nadrzędnym względem
tworzonego. Wykorzystana jest do tego metoda GetSafeHwnd.
3
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
Krok 5. Dodajemy do linkera powiązanie z biblioteką vfw32.lib (rys.8). Następnie
uruchamiamy program ponownie.
Rys. 8. Dodanie powiązania do vfw32.lib
komentarz:
Tym razem kompilacja i łączenie powinno przejść pomyślnie. W wyniku powinniśmy otrzymać
okno z czarnym kwadratem w środku o rozmiarach 640 na 480. W tym kwadracie w dalszych
etapach będzie pokazywany obraz z kamery po jego przetworzeniu wykonanym przez nas.
Krok 6. Enumeracja urządzeń.
komentarz:
Wykorzystując Vfw można obsługiwać do 10 urządzeń wideo. Każde dostaje swój numer. Które
urządzenie jest gotowe do obsługi i które ma jaki numer można określić wykorzystując funkcje
capGetDriverDescription, capDriverGetName oraz capDriverGetCaps. Do
połączenia się ze sterownikiem służy funkcja capDriverConnect a do rozłączenia
capDriverDisconnect.
Zadanie:
Wypisać listę wszystkich urządzeń ich statusu oraz stanu ich gotowości:
1) Dodać tablicę łańcuchów (CString) do klasy CKameraView (rys.9).
2) Dodać kod do enumeracji w OnInitialUpdate (rys.10).
3) Przeanalizować dodany kod, w sytuacji jakby coś nie było wystarczająco jasne
KONIECZNIE PYTAĆ (ważne aby rozumieć)
4) Dodać kod do OnDraw wypisujący listę urządzeń na ekranie (rys.11).
4
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
5)
class CKameraView : public CView
{
protected: // create from serialization only
CKameraView();
DECLARE_DYNCREATE(CKameraView)
protected:
HWND m_wndKamera;
CString m_strDriversEnum[10];
CString m_strDriversParam[10];
bool m_bIsDrivers[10];
&
Rys. 9. Modyfikacje w KameraView.h  dodanie tablic łańcuchów z opisem urządzeń
void CKameraView::OnInitialUpdate(){
CView::OnInitialUpdate();
HWND hwndParent = this->GetSafeHwnd();
m_wndKamera = capCreateCaptureWindow( L"Nazwa", WS_CHILD | WS_VISIBLE,
10, 10, 640, 480, hwndParent, ID_CAMWND );
for( int i =0; i<10; i++ ){
bool res = capDriverConnect( m_wndKamera, i );
m_bIsDrivers[i] = res;
m_strDriversParam[i] = L" ";
if( res ){
char mstring[80];
capDriverGetName( m_wndKamera, mstring, 80 );
CAPDRIVERCAPS drvCaps;
capDriverGetCaps( m_wndKamera, &drvCaps, sizeof( drvCaps ) );
m_strDriversEnum[i].Format( L"%d. %s", i, mstring );
if( drvCaps.fHasDlgVideoSource ){
m_strDriversParam[i] += L"SourceDLG; ";
};
if( drvCaps.fHasDlgVideoFormat ){
m_strDriversParam[i] += L"FormatDLG; ";
};
if( drvCaps.fCaptureInitialized ){
m_strDriversParam[i] += L"INIT; ";
};
}else{
m_strDriversEnum[i].Format( L"%d. ----------", i );
};
capDriverDisconnect( m_wndKamera );
};
}//-----------------------------------------------------------------------------
Rys. 10. Kod w metodzie OnInitialUpdate
5
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
void CKameraView::OnDraw(CDC* pDC){
int y = 20;
for( int i =0; i<10; i++ ){
pDC->TextOut( 700, y, m_strDriversEnum[i] ); y += 20;
if( m_bIsDrivers[i] ){
pDC->TextOut( 700, y, m_strDriversParam[i] );
y += 20;
};
};
}//-----------------------------------------------------------------------------
Rys. 11. Kod w metodzie OnDraw  wyświetlanie tekstów
komentarz:
Pomysł algorytmu jest dość prosty. Na etapie inicjalizacji w pętli pytane jest wszystkie 10
możliwych urządzeń (pętla for) o parametry. W tym celu należy połączyć się ze sterownikiem
urządzenia (capDriverConnect) i jeśli połączenie się udało (sterownik właściwy) to zapytać go
o nazwę (capDriverGetName) oraz zapewniane przez sterownik możliwości
(capDriverGetCaps, końcówka -Caps od Capabilities). Procedura wypełnia właściwe
łańcuchy (odpowiednio m_strDriversEnum do numeru oraz nazwy oraz
m_strDriversParam do zapewnianych możliwości) oraz wypełnia informacje, czy sterownik
był dostępny(m_bIsDrivers). Obie tablice łańcuchów jak również informacja o dostępności
sterownika wykorzysytwana jest w procedurze obsługi komunikatu WM_PAINT (rysowanie
ekranu, metoda OnDraw w tym przypadku).
Krok 7. Połączenie ze sterownikiem kamery, ustawienie parametrów kamery i
pobieranie ramki obrazu.
Zadanie:
Pokazać w oknie właściwy obraz z kamery i pobierać nową ramkę na żądanie ręcznie oraz
automatycznie w procedurze obsługi WM_TIMER:
1) Połączyć się ze sterownikiem oraz uruchomić okno ustalania parametrów
(capDlgVideoFormat) (rys.12).
2) Uruchomić aplikację, powinno na starcie uruchomić się okno dialogowe z możliwością
ustawiania parametrów kamery. Ustawić rozdzielczość 640x480 oraz kompresje na
RGB24 (rys.13).
3) Dodać do menu aplikacji nowe wpisy (rys.14).
4) Dodać metodę na obsługę zdarzenia wybrania komendy  Pobierz ramke z menu
(rys.15).
5) Dodać obsługę komunikatów OnKameraFilmTimerStart oraz OnKameraFilmTimerStop
analogicznie do punktu 4.
6) Dodać metodę OnTimer obsługujące komunikat WM_TIMER (rys.17). W celu obsługi
komunikatu od Timera należy dodać symbol ID_TIMER, podobnie jak to robione było z
symbolem ID_CAMWND (rys.4).
7) Wypisać kod do nowo utworzonych metod zgodnie z rys.18.
6
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
void CKameraView::OnInitialUpdate(){
&
bool res = capDriverConnect( m_wndKamera, 0 );
capDlgVideoFormat( m_wndKamera );
}//-----------------------------------------------------------------------------
Rys. 12. Kod w metodzie OnDraw  wyświetlanie tekstów
Rys. 13. Przykładowe okno dialogowe ustawiania parametrów.
Rys. 14. Nowe wpisy w MENU.
void CKameraView::OnKameraPobierz(){
capGrabFrame( m_wndKamera, true );
}//----------------------------------------
Rys. 15. Dodanie metody
Rys. 16. Kod OnKameraPobierz.
obsługi komunikatu
ID KAMERA POBIERZ
7
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
//------------------------------------------------
void CKameraView::OnKameraFilmTimerStart(){
SetTimer( ID_TIMER, 50, NULL );
}//-----------------------------------------------
//------------------------------------------------
void CKameraView::OnKameraFilmTimerStop(){
KillTimer( ID_TIMER );
}//-----------------------------------------------
//------------------------------------------------
void CKameraView::OnTimer(UINT_PTR nIDEvent){
capGrabFrame( m_wndKamera, true );
CView::OnTimer(nIDEvent);
}//-----------------------------------------------
Rys. 17. Dodanie komunikatu
Rys. 18. Kod metod OnKameraFilmTimerStart,
OnTimer.
OnKameraFilmTimerStop oraz OnTimer
Krok 8. Modyfikacje na obrazie  odwracanie obrazu.
Zadanie:
Pokazać w oknie zanegowany obraz z kamery (tam gdzie był kolor biały ma być czarny itd.):
1) Dodać funkcję cbFunct. Ma znaczenie w którym miejscu w pliku CKameraView.cpp
umieścimy tą funkcję. Powinna być umieszczona przed odwołaniem się do niej, czyli
przed metodą OnInitialUpdate. Proponuje się umieszczenie jej kodu bezpośrednio za
konstruktorem klasy.
2) Zmodyfikować metodę OnInitialUpdate dodając na końcu wywołanie funkcji
capSetCallbackOnFrame (rys.20).
//------------------------------------------------------------------------------
LRESULT CALLBACK cbFunct(HWND hWnd, LPVIDEOHDR lpVHdr){
long size = lpVHdr->dwBufferLength;
for( int x=0; x<640; x++ )
for( int y = 0; y<480; y++ ){
int i0 = x*3 + y * 3 * 640;
lpVHdr->lpData[i0] = 255 - lpVHdr->lpData[i0]; // BLUE
lpVHdr->lpData[i0+1] = 255 - lpVHdr->lpData[i0+1]; // GREEN
lpVHdr->lpData[i0+2] = 255 - lpVHdr->lpData[i0+2]; // RED
};
return (LRESULT) TRUE ;
}//-----------------------------------------------------------------------------
void CKameraView::OnInitialUpdate(){
&
capSetCallbackOnFrame( m_wndKamera, cbFunct );
}//-----------------------------------------------------------------------------
8
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11
Architektura Systemów Komputerowych, Wydział Informatyki, ZUT
komentarz:
Jest to typowe wykorzystanie mechanizmu CallBack. Przypominam w skrócie, że polega on na
tym, że do urządzenia przekazujemy adres funkcji którą chcemy aby on wykonał na skutek
wybranego zdarzenia. Alternatywą do tego mechanizmu jest na przykład mechanizm
wykorzystujący pętle komunikatów, na przykład ten znany z systemu MS Windows.
W tym konkretnym przypadku zdarzeniem jest odebranie nowej ramki obrazu z kamery. Gdy nowa
ramka nadejdzie sterownik urządzenia po jej sformatowaniu wywoła funkcję cbFunct. Pytanie do
zastanowienia brzmi, jakie mogą być potencjalne wady wykorzystania mechanizmu CallBack, tak
że nie jest on dominującym mechanizmem.
Krok 9. (praca samodzielna) (1) Rysować tylko składową zieloną, (2) rysować
obraz w odcieniach szarości (współczynniki uśredniania R:0.2125, G:0.7154,
B:0.0721) (3) rysować obraz w odcieniach szarości ze współczynnikami uśredniania
1/3 i porównać z pp.2, (3) Wykonać progowanie (thresholding) dla progu równego 50
i eksperymentować z innymi wartościami progu.
Krok 10. (praca samodzielna) Rysowanie na obrazie  funkcja rysująca zielony
kwadrat pomiędzy zadanymi współrzędnymi (x0, y0) oraz (xk, yk).
Krok 11. (praca samodzielna) Znajdowanie współrzędnej punktu ze wskaznika
laserowego (najbardziej czerwonego punktu na obrazie) i oznaczanie jej (śledzenie
obiektu). Wypisać pod obrazem współrzędne tego obiektu.
Krok 12. (praca samodzielna) Konkurs na najlepszy projekt na roku dotyczący
rozpoznawania obrazów z kamery. Najlepszy projekt będzie nagrodzony oceną
bardzo dobrą z całości kursu (laboratorium oraz wykładu).
Linki do ciekawych pomysłów tego typu aplikacji (proszę nie ograniczać pomysłów do tego typu
aplikacji, czym ciekawszy pomysł tym lepiej):
http://www.youtube.com/watch?v=fGFypLpxD7M&feature=related
http://www.youtube.com/watch?v=ml4_MIM52g0&feature=related
http://www.youtube.com/watch?v=YBorbRaFrn8
http://www.youtube.com/watch?v=i_bZNVmhJ2o
http://www.youtube.com/watch?v=exbGdHpFiW0
9
Opracował: Mariusz Kapruziak (mkapruziak@wi.ps.pl) wersja: 2009-11-11


Wyszukiwarka