Webcam Programmierung / einzelnes bild in Array speichern
-
Hallo,
Ich habe auf www.codeproject.com einen Programmcode gefunden, welcher einzelene Bilder von einer Webcam einlesen kann.
Leider bekomme ich diesen Code nicht zu laufen. Vielleicht schafft es von euch einer.Vorneweg:
Ihr müsst folgende Libraries einbinden:strmbasd.lib
strmiids.lib
winmm.libAußerdem benötigt ihr folgende Headerdatei:
streams.h
Alle Libraries müssten im Platform SDK und im DirectX SDK (Summer 2004) zu finden sein.
Außer strmbasd.lib.
Diese Bibliothek muss noch erstellt werden.Beim Platform SDK gibt es in
...\PlatformSDK\Samples\Multimedia\DirectShow\BaseClasses eine Datei mit der man mit nmake die strmbasd.lib erstellen können müsste (wer es weiss wie es geht kann es mir mitteilen)Oder:
Im DirectX SDK (summer 2004) gibt es im gleichen Ordner ein Projekt, das man debuggen muss. Dann wird diese Library erstellt. Dies geht auf jedenfall, ich weiss aber nicht ob dies die richtige Versin ist.Ich würde mich freuen wenn den Code jemand zum laufen bekäme und mir sagen könnte wie er das gemacht hat.
Ich benutzte VS 2003.net
Und nun der Code:
#include <windows.h> #include <dshow.h> #include <streams.h> int w,h; HWND hwnd; MSG msg = {0}; BITMAPINFOHEADER bmih={0}; struct __declspec( uuid("{71771540-2017-11cf-ae26-0020afd79767}") ) CLSID_Sampler; struct Sampler : public CBaseVideoRenderer { Sampler( IUnknown* unk, HRESULT *hr ) : CBaseVideoRenderer(__uuidof(CLSID_Sampler), NAME("Frame Sampler"), unk, hr) {}; HRESULT CheckMediaType(const CMediaType *media ) { VIDEOINFO* vi; if(!IsEqualGUID( *media->Subtype(), MEDIASUBTYPE_RGB24) || !(vi=(VIDEOINFO *)media->Format()) ) return E_FAIL; bmih=vi->bmiHeader; SetWindowPos(hwnd,0,0,0,20+(w=vi->bmiHeader.biWidth),60+(h=vi->bmiHeader.biHeight),SWP_NOZORDER|SWP_NOMOVE); return S_OK; } HRESULT DoRenderSample(IMediaSample *sample){ BYTE* data; sample->GetPointer( &data ); // Process RGB Frame data* here. For Example: ZeroMemory(data+w*h,w*h); BITMAPINFO bmi={0}; bmi.bmiHeader=bmih; RECT r; GetClientRect( hwnd, &r ); return StretchDIBits(GetDC(hwnd),0,16,r.right,r.bottom-16,0,0,w,h,data,&bmi,DIB_RGB_COLORS,SRCCOPY); } }; int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmd,int show){ HRESULT hr = CoInitialize(0); hwnd=CreateWindowEx(0,"LISTBOX",0,WS_SIZEBOX,0,0,0,0,0,0,0,0); IGraphBuilder* graph= 0; hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&graph ); IMediaControl* ctrl = 0; hr = graph->QueryInterface( IID_IMediaControl, (void **)&ctrl ); Sampler* sampler = new Sampler(0,&hr); IPin* rnd = 0; hr = sampler->FindPin(L"In", &rnd); hr = graph->AddFilter((IBaseFilter*)sampler, L"Sampler"); ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs); IEnumMoniker* cams = 0; hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0; IMoniker* mon = 0; hr = cams?cams->Next (1, &mon, 0):0; IBaseFilter* cam = 0; hr = mon?mon->BindToObject(0,0,IID_IBaseFilter, (void**)&cam):0; IEnumPins* pins = 0; hr = cam?cam->EnumPins(&pins):0; IPin* cap = 0; hr = pins?pins->Next(1,&cap, 0):0; hr = graph->AddFilter(cam, L"Capture Source"); IBaseFilter* vid = 0; hr = graph->AddSourceFilter (L"c:\\Windows\\clock.avi", L"File Source", &vid); IPin* avi = 0; hr = vid?vid->FindPin(L"Output", &avi):0; hr = graph->Connect(cap?cap:avi,rnd); hr = graph->Render( cap?cap:avi ); hr = ctrl->Run(); SendMessage(hwnd, LB_ADDSTRING, 0, (long)(cap?"Capture source ...":"File source ...")); ShowWindow(hwnd,SW_SHOW); while ( msg.message != WM_QUIT) { if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); if(msg.message == WM_KEYDOWN && msg.wParam==VK_ESCAPE ) break; } Sleep(30); } };Wenn ihr sonst noch etwas wissen möchtet, dann fragt einfach nach. Vielleicht kann ich euch dabei noch helfen. Ich habe mir schon lange genug den Kopf darüber zerbrochen.
Vielen Dank!!!!!!
PS: Bin noch blutiger Anfänger!
-
DER Code funktioniert!!!!!!!!!!
man muss alles so machen wie ich es oben beschrieben habe!! Außerdem muss mand die Die Libraries richig einbinden und die
LIBCD.lib
ignorieren!!!
dann läuft alles einwandfrei.
-
Da das Programm nun läuft will ich daran weiterarbeiten. Leider bin ich in der Programmierung von Directx un WinAPI noch ziemlich unerfahren.
Vielleicht kannmir jemand sagen wie ich aus diesem Abschnitt des Codes ein einzelnes Bild capturen und in einem Array abspeichern kann.
Sampler( IUnknown* unk, HRESULT *hr ) : CBaseVideoRenderer(__uuidof(CLSID_Sampler), NAME("Frame Sampler"), unk, hr) {}; HRESULT CheckMediaType(const CMediaType *media ) { VIDEOINFO* vi; if(!IsEqualGUID( *media->Subtype(), MEDIASUBTYPE_RGB24) || !(vi=(VIDEOINFO *)media->Format()) ) return E_FAIL; bmih=vi->bmiHeader; SetWindowPos(hwnd,0,0,0,20 +(w=vi->bmiHeader.biWidth),60 +(h=vi->bmiHeader.biHeight),SWP_NOZORDER|SWP_NOMOVE); return S_OK; } HRESULT DoRenderSample(IMediaSample *sample) { BYTE* data; sample->GetPointer( &data );aus diesem Teil müsste es wohl zu holen sein.
mfg Andi
-
Hallo gramboler,
es ist nicht ganz so einfach aus deinen Postings etwas herauszulesen. Ich versuche Dir gerne zu helfen und sicherlich auch alle anderen, aber wenn man nur Bruchstück-Informationen bekommt, um was es genau geht wird es schwierig.
Du schreibst selbst, das Du wenig Ahnung von der "Windows API" und von DirectX hast. Wenn ich dir hierzu einen Tip geben darf - befass Dich ersteinmal mit der Windows Programmierung. Gute Tutorials findest Du unter http://www.robsite.de/index.php
Und danach mit DirectShow.Zu deinem Problem zurück. So wie ich es verstehe möchtest Du ein einzelnes Frame aus einem Film als Bitmap abspeichern. Verwende hierzu am einfachsten den SampleGrabber. Du findest die englische Doku im MSDN und wenn ich mich nicht ganz irre gibts auch Beispiele im Netz (auch auf codeproject)
Zur vorgehensweise: Du fügst den Filter SampleGrabber zu deinem Filtergraphen hinzu und ...
Hier ist ein Code Beispiel mit ganz guter Erklärung

http://www.codeproject.com/audio/framegrabber.asp
-
danke!!
auf Robsite.de war ich schon und habe auch das WinApi Tutorial durchgemacht.
Das Beispiel auf codeproject sieht nicht schlecht aus. Ich muss es mir einmal genauer anschauen.Bei MSDN habe ich nicht über den SampleGrapper gefunden abe vielleicht muss ich einfach noch einmal nachschauen.
-
gramboler schrieb:
Bei MSDN habe ich nicht über den SampleGrapper gefunden abe vielleicht muss ich einfach noch einmal nachschauen.
Nicht SampleGrapper
!! Sondern SampleGraBBerNichts zu danken. Achja wenn Du dich eingehender mit DirectShow befassen möchtest ist es auch ganz hilfreich sich ein wenig mit COM-Objekten auszukennen.
-
ja ich habs auch bemerkt. lol, sogar schon vor dir.

trotztdem danke!!
Eine Frage habe ich noch.
wie erstellt man eine Bitmaptdatei? Ich habe es mit Createfile () versucht.
Als Dateiname übergebe ich CreateFile ():
HANDLE fileHandle; char filename [] = "C:\\testbild.bmp"; fileHandle=CreateFile(filename,GENERIC_READ | GENERIC_WRITE,(DWORD)0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL); CloseHandle(fileHandle);damit erstelle ich auch eine Datei, die ich aber mit einem Bildbearbeitungsprogramm (z. B. Paint) nicht öffen kann.
Was mache ich falsch? Oder was muss ich anders machen?
Müßte ich mit diesem Code nicht eine leere Bitmapdatei erstellen? Oder muss ich CreateFile zuerst noch die Bitmapinformationen übergeben?
Wie übergebe ich der erzeugeten Datei die Bitmapinformationen?
Danke!!!
-
Hmm da fehlt noch einiges damit es ein Bitmap wird

Schau Dir mal dieses Beispiel an hier wird genau das beschrieben was Du möchtest. Schöner kann man es echt nicht mehr erklären

http://www.codeguru.com/cpp/g-m/directx/directshow/article.php/c9551/
-
ok, wenn ich nun alles richtig verstanden habe, dann erstelle ich mit
CreateFile();nur eine leere Datei.
Diese Datei muss ich nun mit Informationen fütteren können, was ich wahrscheinlich mit
WriteFile (hf,&(bmih), BufferSize, &Written, NULL );machen kann.
Mir sind nun nur nicht die Parameter die übergeben werden klar. Schaue ich in der VS Hilfe nach, dann werden dort maximal drei Parameter übergeben, in diesem Fall sind es aber fünf.
Kann mmir jemand erklären, was das für vier Parameter sind und was für WErte ich denen übergeben muss?
-
Frage zurück, ich habe die Antwort selbst gefunden. Für alle die es Wissen wollen:
WriteFile ( HANDLE hFile, LPCVOID 1pBUFFER, DWORD nNumberOfBytesToWrite, LPDWORD 1pNumberOfBytesWriteen: LPOVERLAPPED 1pOverlapped);hFiel: ist der Handle auf das Dateiobjekt
LpBuffer: ist ein Zeiger auf den Buffer
nNumberOfBytesToWrite: ist die Anzahl der Bytes, die aus dem Buffer in das Dateiobjekt übertragen werden soll
1pNumberOfBytesWriteen: gibt an wieviel Bytes in das Dateiojekt geschrieben werden
1pOverlapped: gibt den Offset an