Bildwerte einlesen mit C

Martinsi

Grünschnabel
Hallo,

Ich würde gerne die Bilder meiner Webcam, die über USB angeschlossen ist auslesen und die Werte am besten in einem Array speichern um sie dann weiterzuverarbeiten.
Leider habe ich keine Ahnung wie man die einzelnen Werte einliest.
Wäre schön wenn mir jemand helfen könnte.

Mfg
Martin
 
Original geschrieben von Martinsi
Hallo,

Ich würde gerne die Bilder meiner Webcam, die über USB angeschlossen ist auslesen und die Werte am besten in einem Array speichern um sie dann weiterzuverarbeiten.
Leider habe ich keine Ahnung wie man die einzelnen Werte einliest.
Wäre schön wenn mir jemand helfen könnte.

Mfg
Martin
Meinst du mit "Werte" die Werte der einzelnen Pixel? Dazu musst du die Bilder ja erst "capturen" oder wie man das nennen soll. Ich habe dazu mal Video for Windows verwendet. Das ist halbwegs unproblematisch gewesen. Wenn es dich interessiert, kann ich mal meine Sourcen suchen.
 
Ja ich würde gerne die Farbwerte der einzelnen Pixel auslesen um damit Objekte erkennen zu können. (alles nur ganz simpel bei einfärbigen Hintergrund).

Mein Problem ist eben, wie ich zu diesen einzelnen Farbwerte bekomme.
Die Sourcen würden mich sehr interessieren, ich muß aber gleich vorwegnehmen, daß ich ich nur die grundlegenden Programmierkenntnisse habe.
Mir geht es einfach darum die Werte der Pixel auszulesen und diese in ein zweidimensionales Array zu speichern.
 
So, habe jetzt alles wiedergefunden. Aber: Ich weiss nicht, ob es dir wichtig ist mit dem C - ich habe nur ein Beispiel für C++, und zwar mit MFC. Vielleicht nützt es dir dennoch.
Das eigentliche Capturing und das drum und dran ist im folgenden Schnipsel enthalten, allerdings nicht die Anzeige des gegrabbten Bildes, da ich die verwendete Lib nicht einfach rausgeben darf. Ansonsten hätte ich dir auch das komplette Porjekt geschickt.
Aber das von dir gewünschte Pixellesen ist damit möglich. Der Schnipsel stammt aus einem MFC-SDI-Projekt mit Visual C++ 6.0, bei dem ein Videofenster geöffnet wird und auf Doppelklick ein Frame gegrabbt wird.

Code:
//... stdafx.h usw.

#include <vfw.h>

#pragma comment( lib, "vfw32.lib" )


// Der View hat ein Member für das Capturewindow
CChildView::CChildView()
{
  hwndCapture_  = 0;
}



/////////////////////////////////////////////////////////////////////
//-    OnCreate
/////////////////////////////////////////////////////////////////////
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd ::OnCreate(lpCreateStruct) == -1)
		return -1;
	
  InitCapture();

  Invalidate();
  return 0;
}


/////////////////////////////////////////////////////////////////////
//-    OnEraseBkgnd
/////////////////////////////////////////////////////////////////////
BOOL CChildView::OnEraseBkgnd(CDC* pDC) 
{
  return TRUE;
}

/////////////////////////////////////////////////////////////////////
//-  
//-    Videograbbing
//-  
/////////////////////////////////////////////////////////////////////
namespace
{
  BOOL StartCapture( HWND hwndCapture )
  {
    if ( hwndCapture == NULL )
    {
      return FALSE;
    }

    if ( !SendMessage( hwndCapture,WM_CAP_DRIVER_CONNECT, 0, 0 ) )
    {
      // kein Video-Input-Device gefunden
      DestroyWindow( hwndCapture );
      return FALSE;
    }

    SendMessage( hwndCapture, WM_CAP_SET_SCALE, (WPARAM)TRUE, 0 );
    SendMessage( hwndCapture, WM_CAP_SET_PREVIEW, 1, 0 );
    SendMessage( hwndCapture, WM_CAP_SET_PREVIEWRATE, 30, 0 );

    return TRUE;
  }

  void StopCapture( HWND hwndCapture )
  {
    if ( hwndCapture == NULL )
    {
      return;
    }
    SendMessage( hwndCapture, WM_CAP_STOP, 0, 0 );
    SendMessage( hwndCapture, WM_CAP_SET_PREVIEW, 0, 0 );
  }

  inline unsigned long C24TO15( unsigned long color )
  {
    return    ( ( ( ( color & 0xff0000 ) >> 16 ) >> 3 ) << 10 ) 
           |  ( ( ( ( color & 0x00ff00 ) >> 8  ) >> 3 ) << 5  ) 
           |  ( ( ( ( color & 0x0000ff ) >> 0  ) >> 3 ) << 0  ); 
  }
};

int CChildView::InitCapture()
{
  hwndCapture_  = capCreateCaptureWindow( "capture", 
                                        WS_OVERLAPPEDWINDOW,
                                        0,   0, 
                                        640,  480, 
                                        GetSafeHwnd(), 
                                        0 );
  
  ::SetWindowPos( hwndCapture_, NULL, 0, 0, 380, 285, SWP_NOZORDER );
  ::ShowWindow( hwndCapture_, SW_SHOW );
  StartCapture( hwndCapture_ );
  return 0;

}

void CChildView::OnDestroy() 
{
  if ( hwndCapture_ != NULL )
  {
    StopCapture( hwndCapture_ );
    ::SendMessage( hwndCapture_, WM_CAP_DRIVER_DISCONNECT, 0, 0 );
    ::DestroyWindow( hwndCapture_ );
    hwndCapture_ = NULL;
  }

	CWnd::OnDestroy();
}

void CChildView::OnDateiEinstellungen() 
{
  capDlgVideoFormat( hwndCapture_ );
}

/*-CaptureImage---------------------------------------------------------------+
 |                                                                            |
 +----------------------------------------------------------------------------*/
BOOL CChildView::CaptureImage()
{
  ::SendMessage( hwndCapture_, WM_CAP_GRAB_FRAME, 0, 0 );
  ::SendMessage( hwndCapture_, WM_CAP_EDIT_COPY, 0, 0 );

  if ( !::OpenClipboard( GetSafeHwnd() ) )
  {
    ::MessageBox( GetSafeHwnd(), "Konnte ClipBoard nicht anfordern.", "Fehler!", 0 );
    return FALSE;
  }
   
  HBITMAP hBitmap = (HBITMAP)GetClipboardData( CF_DIBV5 );
  if ( hBitmap == NULL )
  {
    CloseClipboard();
    ::MessageBox( GetSafeHwnd(), "Das Clipboard ist leer!", "Fehler", 0 );
    return FALSE;
  }
  
  BITMAPINFO* pInfo = ((BITMAPINFO*)hBitmap);
  LONG dwWidth      = pInfo->bmiHeader.biWidth;
  LONG dwHeight     = pInfo->bmiHeader.biHeight;
  WORD bitcount     = pInfo->bmiHeader.biBitCount;
  DWORD colorused   = pInfo->bmiHeader.biClrUsed;

  // für debugging
  //dh() << dwWidth << ", " << dwHeight << ", " << bitcount << ", " << colorused << "\n";
  //dh() << pInfo->bmiHeader.biSize << "\n"; 

  if ( bitcount == 24 )
  {
    int iLO = dwWidth;
    if ( iLO % 4 ) iLO += ( 4 - iLO % 4 );

    DWORD dwHeaderSize = 124;

    int targetwidth = m_pFrontPage->width();

    char* pBitmap = ( (char*) pInfo ) + dwHeaderSize + colorused * 4;

    for ( int j = 0; j < dwHeight; ++j )
    {
      for ( int i = 0; i < dwWidth; ++i )
      {
        unsigned long* pPixel = (unsigned long*)( pBitmap + i * 3 + j * iLO * 3 ); 
//#pragma TODO( "umbauen, damits auch für andere screenbreiten passt" )

        // HIER BEKOMMST DU JEDEN EINZELNEN PIXELWERT!  

        // das würde die pixel buffern:  
        //        (WORD)*( (WORD*)(m_pFrontPage->data()) + i + ( dwHeight - j - 1 ) *  targetwidth ) = C24TO15( *pPixel );
      }
    }
  }

  DeleteObject( hBitmap );
  CloseClipboard();

  return TRUE;
}

void CChildView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
  CaptureImage();
  StartCapture( hwndCapture_ );
	CWnd::OnLButtonDblClk(nFlags, point);
}

void CChildView::OnEditCopy() 
{
  CaptureImage();
  StartCapture( hwndCapture_ );
}
Ich hoffe, dass du daraus schlau wirst. Falls nicht, frag bitte nochmal nach. Vielleicht sollte ich noch weitere Kommentare in den Code packen, aber dazu fehlt mir im Moment die Zeit.
 
Wow vielen Dank,

eines kann ich schon jetzt sagen: der Code übersteigt meineProgrammierkünste bei weitem. Werde mich aber trotzdem mal reinknien wenn ich mehr Zeit habe.
Vielen Dank für Deine Bemühungen. So prompt wurde mir noch in keinem Forum geholfen.

Mfg
Martin
 
Gern geschehen! Es tut mir nur Leid, dass du damit jetzt nicht so viel anfangen kannst. Vielleicht meldest du dich am besten noch einmal, wenn du damit rumprobieren willst und ich erkläre dir dann den Code und was du tun musst.
 
Also das schreiben in die zweidimensionale Matrix wollte ich auch mit zwei for -Schleifen machen.


Ich habe es mir so vorgestellt:
Code:
anz=480;    // für 640x480 Bild.
anzsp=640

 for (zaehlerz=1;zaehlerz<=anzz;zaehlerz++)
      {
        for (zaehlersp=1;zaehlersp<=anzsp;zaehlersp++)    
              {  lesepixel( "%d", &x);   //Lies Wert  an Stelle zaehlerz  und zaehlersp   .                          
               matrix[zaehlerz][zaehlersp]=x; 
               }
      }
Mir ist nur nicht klar wie ich die Funktion lesepixel umsetze und welchen Wert ich dann für die Pixel bekomme. Eigentlich eine Integer Zahl oder ?

So wie ich das in dem von Dir geposteten Code sehe, muß sich das Bild erstmal im Clipboard befinden oder ? d.h es wird nicht direkt die Kamera oder so angesprochen......
 
Zuletzt bearbeitet:
Der augenblickliche Videostream wird in einem seperaten Fenster angezeigt. Für das Captuirng wird der augenblickliche Frame ins Clipboard kopiert, was eine elegante Lösung ist, weil es auch zum Beispiel ermöglicht, das Bild in ein Grafikprgramm zu pasten und zu verarbeiten oder zu speichern.
Der Eintrag im Clipboard enthält ein BITMAPINFO, das die Abmessungen und die tatsächlichen Pixel des gegrabbten Frames enthält. Die Pixel, also die eigentliche Bitmap sind bereits ein Array von Pixelwerten. Seine Abmessungen, also Breite, Höhe, Bits pro Pixel stehen auch im Bitmapinfo drin.
In meinem Beispiel wird folgendermassen auf das Bitmaparray zugegriffen:
Code:
 unsigned long* pPixel = (unsigned long*)( pBitmap + i * 3 + j * iLO * 3 );
pBitmap ist ein Pointer auf den Beginn der Bitmap im Clipboard, das heisst auf den Pixel links oben. i und j sind die x- bzw. Y-Koordinaten. In diesem Fall kann man leider nicht über die normalen Arrayoperatoren [] auf die Pixel zugreifen, weil ein Pixel 3 Byte bzw. 24 Bit gross ist. (Bei 1, 2 oder 4 Byte grossen Pixel wäre es denkbar, wenn die Bildzeilen unmittelbar im Speicher aneinanderstossen. ) Jedenfalls musste durch die Multiplikation mit 3 usw. der Offset einzelner Pixel vom Anfangspixel berechnet werden. Ich hoffe, ich habe das nicht zu umständlich ausgedrückt und du kannst was damit anfangen.
 
Zurück