PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Child übermalen / WebCam probs


[LL][Romeo-G]
29.01.2004, 18:56
Hallo,

fokgendes Problem:

Ich habe meine WebCam in eine Win32-Anwendung angebunden und lese die Bilder mit API Funktionen aus.

Soweit so gut!

Allerdings möchte ich grafische Elemente wie Linien, 4-Ecke etc. auf das WebCam Bild malen (Später will ich mal bestimmte PIxelwerte durch beispielsweise ein Rechteck umrahmen <= dafür brauche ich das) und hier ist das Problem.

Wenn ich mit ebendfalls API Funktionen eine GErade male dann liegt diese "unter" dem Child und ich sehe die LInie entweder gar nicht bzw wenn ich das Child verschiebe bis dahin wo es anfängt .. wie gesagt ... das Child verdeckt halt die grafischen Elemente.


Wie kann ich das ändern ????

Habe was von wegen subclassing gehört allerdings habe ich das nicht hinbekommen so zum laufen zu kriegen, dass gewünschter Effekt erzielt wird.



Hier mal mein Code:



#include <windows.h>
#include <vfw.h>


#define ID_BUTTON_FOTO 1
#define ID_BUTTON_CLOSE 2
#define ID_VIDEO_WINDOW 3
#define BUTTON_BREITE 60
#define BUTTON_HOHE 20
#define FENSTER_BREITE 350
#define FENSTER_HOHE 320
#define P_FILM 0
#define P_FOTO 1

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL FensterSkalieren (HWND) ;
BOOL ButtonsSkalieren (HWND, int, int) ;

const char szAppName[] = "V. 01";
OPENFILENAME ofn ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclassex ;
wndclassex.cbSize = sizeof (WNDCLASSEX) ;
wndclassex.style = CS_HREDRAW | CS_VREDRAW ;
wndclassex.lpfnWndProc = WndProc ;
wndclassex.cbClsExtra = 0 ;
wndclassex.cbWndExtra = 0 ;
wndclassex.hInstance = hInstance ;
wndclassex.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (101)) ;
wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclassex.hbrBackground = CreateSolidBrush(RGB(200,200,255));
wndclassex.lpszMenuName = szAppName ;
wndclassex.lpszClassName = szAppName ;
wndclassex.hIconSm = NULL ;
RegisterClassEx (&wndclassex) ;
hwnd = CreateWindowEx (NULL ,
szAppName, szAppName,
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION,
CW_USEDEFAULT , CW_USEDEFAULT ,
FENSTER_BREITE, FENSTER_HOHE,
NULL, LoadMenu (hInstance, MAKEINTRESOURCE (102)), hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){

static HINSTANCE hInstance ;
static HWND hwndVideo ;
static int iIndex = 0 ;
char szDeviceName[80],
szDeviceVersion[80],
str[161];
static int iBreite = 0,
iHoche = 0,
iPruef = P_FOTO ;
static RECT rect;


switch (message){
case WM_CREATE :
hInstance = ((LPCREATESTRUCT) lParam) -> hInstance ;
hwndVideo = capCreateCaptureWindow((LPSTR) "WebCam",WS_CHILD| WS_VISIBLE,0, 0, 0, 0,(HWND) hwnd, (int) ID_VIDEO_WINDOW) ;

if (!capDriverConnect (hwndVideo, iIndex)) {
MessageBox (hwnd, "Treiber für die Webcam kann nicht geladen werden...", "Fehler", MB_ICONERROR) ;
SendMessage (hwnd, WM_DESTROY, 0, 0) ;
return 0;
}
capPreviewRate (hwndVideo, 33.3) ;
capPreview (hwndVideo, TRUE) ;
capGetDriverDescription (iIndex, szDeviceName, sizeof (szDeviceName),
szDeviceVersion, sizeof (szDeviceVersion)) ;
wsprintf (str, "%s, %s", szDeviceName, szDeviceVersion) ;
MessageBox (NULL, str, "Verbunden über...", NULL) ;
FensterSkalieren (hwnd) ;
ButtonsSkalieren (hwnd, iBreite, iHoche) ;
return 0 ;


case WM_SIZE :
rect.left = 0;
rect.top = 0;
rect.right = LOWORD(lParam);
rect.bottom = HIWORD(lParam);

iBreite = LOWORD (lParam) ;
iHoche = HIWORD (lParam) ;
return 0 ;

case WM_COMMAND :
switch (LOWORD (wParam)){

case ID_BUTTON_CLOSE :
SendMessage (hwnd, WM_DESTROY, 0, 0) ;
break ;

}
return 0 ;

case WM_DESTROY :
capPreview (hwndVideo, FALSE) ;
capDriverDisconnect (hwndVideo) ;
PostQuitMessage (0) ;
return 0 ;

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC;

const char szUeberschrift[] = "Cam_Einbindung_v01";

hDC = BeginPaint(hwnd, &ps);
{
int iStrLen = 0;
DrawText(hDC, szUeberschrift, lstrlen(szUeberschrift), &rect , DT_SINGLELINE | DT_CENTER | DT_TOP );
for(int i=0; i<1024; i++) SetPixel( hDC, i, 100, RGB(255,0,0) );
}

EndPaint(hwnd, &ps);
return 0;
}

}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}



BOOL ButtonsSkalieren (HWND hwndParent, int iBreite, int iHoche){
MoveWindow (GetDlgItem (hwndParent, ID_BUTTON_CLOSE),
iBreite - BUTTON_BREITE, iHoche - BUTTON_HOHE,
BUTTON_BREITE, BUTTON_HOHE, TRUE) ;
MoveWindow (GetDlgItem (hwndParent, ID_BUTTON_FOTO),
iBreite - (2 * BUTTON_BREITE) - 5, iHoche - BUTTON_HOHE,
BUTTON_BREITE, BUTTON_HOHE, TRUE) ;
return TRUE ;
}

BOOL FensterSkalieren (HWND hParent){
CAPSTATUS CS ;
capGetStatus (GetDlgItem (hParent, ID_VIDEO_WINDOW), &CS, sizeof (CAPSTATUS)) ;
SetWindowPos (GetDlgItem (hParent, ID_VIDEO_WINDOW), NULL, 0, 0, CS.uiImageWidth,
CS.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE) ;
SetWindowPos (hParent, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CS.uiImageWidth,
CS.uiImageHeight /*+ 75*/, SWP_NOZORDER | SWP_NOMOVE) ;
return TRUE ;
}





Vielen Dank
[LL][Romeo-G]


brainbug
29.01.2004, 20:35
Hi!
das erste problem ist dass du mit deinen Grafik-befehlen ins Hauptfenster Zeichnest:

hDC=BeginPaint(hwnd

folglich hest du den hdc von dem hauptfenster.
aber mit dem subclassing ist sone sache ob das geht.. wenn das capturing-fenster bei jedem neuen frame eine WM_PAINT oder sonstige message sendet, dann ja!

ansonsten kannst du mal versuchen dem capturing-fenster regionen zu verpassen..

allerdings (kenn mich da leider net so aus mit den capturing-fenstern) kann es sein, dass das laufende video per overlay eingezeichnet wird. dann hab ich zumindest keine lösung mehr!!

aber obs per overlay gezeichnet wird kannste schnell rausfinden: einfach mach die DRUCK-taste aufm keyboard drücken und dir den screenshot in nem grafikproggy aus der zwischenablage holen. Ist an der stelle wo das video zu sehen ist nur schwarz, dann ists leider per overlay..

hoffe das konnte dir weiterhelfen!

[LL][Romeo-G]
30.01.2004, 07:55
Also, wie es aussieht läuft es nicht per overlay, da ich das Bild sehe wenn ich nen Screenshot des Programms mache.

Du hast gesagt, dass ein Fehler sein könnte, dass ich die Grafikelemente ins Hauptfenster zeichne ... die Frage ist ... was ist die alternative ?

hwndVideo = capCreateCaptureWindow((LPSTR) "WebCam",WS_CHILD| WS_VISIBLE,0, 0, 0, 0,(HWND) hwnd, (int) ID_VIDEO_WINDOW) ;

wenn ich ihm angebe, dass er's in hwnd malen ( wie bei der WebCam) soll klappt es natürlich nicht.

Wie soll das mit den "capturing-fenster regionen" funktionieren?? Habe noch nie was davon gehört.


Danek
[LL][Romeo-G]

brainbug
30.01.2004, 11:20
also mit BeginPaint bekommst du eh immer nur einen DC der für die regionen freigeschaltet ist die neu zu zeichnen sind (also vorher verdeckt waren), die andren werden "weg geclippt",. dH du kannst mit einem DC den du über BeginPaint bekommst auch immer nur innerhalb eines WM_PAINT des entsprechenden Fernsters zeichnen.

könntest es so Probieren:

hDC=GetWindowDC(hwndVideo);
{
//hier deine zeichnungen
}
ReleaseDC(hwndVideo,hDC)

allerdings werden die dann wohl einfach überschrieben wenn das Capturing-fernster ein neues frame einzeichnet!


ansonsten kannst du mit SetWindowRgn(hwndVideo,hRGN) teile des Capturing-fensters unsichtbar machen!
hRGN ist ein RegionHandle, das kannst du mit diversen Region-Funktionen erzeugen und mit etwas geschick jede beliebige form verpassen. und genau diese form ist dann im capturing-fenster transparent. und dann kannst du die paint-funktion auch so lassen wie sie im moment ist..


Wenn du aber sicher weisst, dass das capturing-fenster nach jeden frame eine WM_<irgendwas> versendet ist subclassing aber die einzige saubre methode..
ist auch garnicht schwierig das zu machen.. kann ich dir dann ganz schnell mal nen beispiel geben

[LL][Romeo-G]
30.01.2004, 12:35
hDC=GetWindowDC(hwndVideo);
{
//hier deine zeichnungen
}
ReleaseDC(hwndVideo,hDC)



Das hat zwar bewirkt, dass der Strich über dem Stream lag jedoch wurde der stream nicht mehr aktuallisiert ... naja und nen Standbild reicht für meine Zwecke nicht ...

Dennoch danke

[LL][Romeo-G]

butterkeks
30.01.2004, 15:34
Du kannst mit invalidateRect() versuchen, nur 'nen Teil des Bilds zu sperren.

brainbug
30.01.2004, 16:14
also wenn der stream dann stopt isses natürlich blöd!
also schau mal in der SDK nach ob das irgendeine message versendet.

wenn nciht würd ich es mit ner regionen versuchen:
RECT rc;
GetClientRect(hwndVideo,&rc);
HRGN hRgn=CreateRectRgnIndirect(&rc);
HRGN hExcludeRgn=CreateRectRgn(0,100,1024,101); //dies erzeugt eine region von dieser linie die du zeichnest

CombineRgn(hRgn,hRgn,hExcludeRgn,RGN_DIFF); // von der hauptregion diese linienregion abziehen
DeleteObject(hExcludeRgn);

SetWindowRegion(hwndVideo,hRgn);

diesen code dann einfach ans ende deiner WM_CREATE message setzen, nachden du das captureFEnbster erzeugt hast.. falls das geht musst du halt noch zusätzlich dann das rechteck von deinem text von der hauptregion noch abziehn

edit:
achja zeichnen tust du dann noch wie in deinem ersten post ins hauptfenster, nur mit dem unterschied dass das capturefenster jetzt an der stelle wo die linie ist transparent sein sollte

[LL][Romeo-G]
31.01.2004, 09:11
: error C2065: 'SetWindowRegion' : nichtdeklarierter Bezeichner
: error C2360: Initialisierung von 'hExcludeRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hExcludeRgn'
: error C2360: Initialisierung von 'hRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hRgn'
: error C2360: Initialisierung von 'hExcludeRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hExcludeRgn'
: error C2360: Initialisierung von 'hRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hRgn'
: error C2360: Initialisierung von 'hExcludeRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hExcludeRgn'
: error C2360: Initialisierung von 'hRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hRgn'
: error C2360: Initialisierung von 'hExcludeRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hExcludeRgn'
: error C2360: Initialisierung von 'hRgn' durch 'case'-Marke übersprungen
: Siehe Deklaration von 'hRgn'


Cam_Einbindung_v01.exe - 9 Fehler, 0 Warnung(en)


-----------------------------------

So hat das leider auch nicht geklappt .... Hast du selbst ne WebCam und kannst es mal ausprobieren oder gehst du die ganze Zeit "nunr" theoretisch ran ???

Mal abgesehen davon, dass ich deinen Ansatz im MOment nicht zum Laufen kriege.

Wären nicht mit einmal alle Probleme vom Tisch wenn man das capCreateCaptureWindow ohne WS_Child initialisieren könnte ???

Die frage ist nur wie, da wenn ich es einfach rausnehme auch Fehler entstehen.


Danke
Romeo

skka
31.01.2004, 10:41
also ich würde das child window auf 1x1 größe verkleinern (mit nem unsichtbaren oder 0x0 window klappt das folgende nicht) und dann nen callback für den stream reintun.

capSetCallbackOnFrame(hWndCap,FrameCallbackProc);

dann kannst du bequem aus der callback prozedur jedes einzelne frame bearbeiten (sprich drauf rummalen) und es dann selber blitten (aus der LPVIDEOHDR struktur heraus).

LRESULT PASCAL FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)
{
//blitte hier
}

brainbug
31.01.2004, 11:04
Nee, hab keine Webcam hab auch nochnix mit diesem Capturing-Fenster gemacht..
Ich geh das nur Theoretisch (sollte nurmal die funktionsweise demonstriern) an.. ja stimmt durch die Case anweisung musste die HRGN an vor die switch setzen oder das nochmal einklammern {}
wie auch immer.

aber was skka schreibst ist mit 100% die bessre lösung, wusste leider nicht dass man da CallBack-Funktionen setzen kann!
Ist auf jedenfall ne saubere lösung..
ich glaub ich werd mich auch mal mit diesen capture-Funktionen auseinandersetzen.. wusste garnicht was damit so alles geht :-O