Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Ansprechen einer GigE Kamera (Prosilica GC2450C) (https://www.delphipraxis.net/169247-ansprechen-einer-gige-kamera-prosilica-gc2450c.html)

BoolString 6. Jul 2012 12:04

Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Moin!

Ich habe hier gerade eine GigE Kamera von Prosilica GC2450C auf dem Tisch liegen, die bisher in einer anderen Anwendung steckte.

Ich würde diese Kamera nun gerne erstmalig durch eine eigene Software unter Delphi ansprechen und etwa 4-5 Bilder die Sekunde aufnehmen. Dazu ist auch ein SDK erhältlich (Prosilica SDK PvAPI und Doku). Leider komme ich derzeit nicht ganz klar mit den Aufrufstrukturen der DLL. Die Beispiele sind leider nur in C und ich bekomme die nicht (funktionsfähig) übersetzt...

Hat schon jemand mal damit Erfahrung gesammelt und könnte mir zumindest ein wenig Code für die Initialisierungsroutine/Grabbing zeigen?
Ich hab selbst bestimmt wieder ein Jahr keine einzige Zeile Delphi-Code geschrieben und bräuchte ein wenig Anstarthilfe.

Beste Grüße

Jan

brechi 8. Jul 2012 12:34

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Ich kann dir das Universal Package empfehlen (2. Link). Damit kannst du dann auch alle anderen Kameras von AVT ansprechen. Dort sind eigentlich auch genug Beispiel dabei. Wenn du Problemebe bei der Ueberstzunge einzelner Funktionen hast kann ich dir helfen, benoetigen wirst du zumindest dann folgende:


UCC_Init
UCC_GetCameras
UCC_OpenCameraEx
UCC_PrepareFreeGrab
UCC_GrabBitmap24Image
UCC_CloseCamera
UCC_Release

BoolString 10. Jul 2012 20:57

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Hallo brechi,

schönenn Dank für dein Angebot. Ich war gerade 2 Tage unterwegs und hab meine Mails nur vom Handy aus kontrolliert und nicht das Forum. Eigentlich hatte ich die Mail-Benachrichtigung angeklickt; aber da kam irgendwie nichts. Deshalb erst jetzt...

Wie du vermutlich schon erahnst, habe ich derzeit tatsächlich das Probleme die C++ Header Datei zum Import der PvAPI Funktionen in Delphi umzusetzen. Das fängt mit einigen Compilerdirektiven zur systemabhängigen Compilierung an und geht in einigen anderen Punkten weiter. Zudem hätte ich gerne ein paar Beispiele (wie geasagt, bin programmiertechnisch komplett eingerostet. Habe inzwischen mit dem AVT Support telephoniert; die konnten mir aber auch nur sagen, daß sie derzeit keine Delphi Samples bereitstellen können. Hinzu kommt, daß ich mich bisher nur äußerst selten mit DLLs beschäftigt habe.

Parallel habe ich jetzt gerade beantragt, die UniAPI zu bekommen.

Eigentlich ist der fehlende Delphi Support schade. Wir nutzen die Prosilicas seit bald 7 Jahren in verschiedenen Projekten, allerdings immer mit großen Teilen an Fremdsoftware, die die Bildaquise macht. Die kann ich aber derzeit nicht nutzen, da ich eine Art Aufnahmerecorder benötige, der bei Programmstart (einbinden ins Autostart) automatisch anfängt aufzunehmen und dabei parallel auf verschiedene, existierende Delphi-Sourcen zugreift.

Jan


PS: Hab dir gerade eine PN übers Forum zukommen lassen.

sx2008 11. Jul 2012 06:54

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Normalerweise gibt es nicht nur die Low-Level-APIs sondern auch ActiveX-APIs, die man mit Delphi problemlos ansprechen kann.
Es müsste eigentlich auch noch ein ActiveX-Control geben, das man nur auf ein Formular ziehen braucht und so das Bild angezeigt bekommt.

BoolString 11. Jul 2012 16:06

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
So, einige erste Funktionen (wie Initialize und Versionsinfos) bekomme ich inzwischen aus der DLL.
Allerdings sind da noch diverse offene Fragen bezüglich der Übersetzung. Ich habe den C Code:

Delphi-Quellcode:
#define PVDECL  __stdcall
typedef void*   tPvHandle; // Camera handle


typedef enum
{
   ePvErrSuccess      = 0,       // No error
   ePvErrCameraFault  = 1,       // Unexpected camera fault
   ePvErrInternalFault = 2,       // Unexpected fault in PvApi or driver
   ePvErrBadHandle    = 3,       // Camera handle is invalid
   ePvErrBadParameter = 4,       // Bad parameter to API call
   ePvErrBadSequence  = 5,       // Sequence of API calls is incorrect
   ePvErrNotFound     = 6,       // Camera or attribute not found
   ePvErrAccessDenied = 7,       // Camera cannot be opened in the specified mode
   ePvErrUnplugged    = 8,       // Camera was unplugged
   ePvErrInvalidSetup = 9,       // Setup is invalid (an attribute is invalid)
   ePvErrResources    = 10,      // System/network resources or memory not available
   ePvErrBandwidth    = 11,      // 1394 bandwidth not available
    ePvErrQueueFull    = 12,      // Too many frames on queue
   ePvErrBufferTooSmall= 13,      // Frame buffer is too small
    ePvErrCancelled    = 14,      // Frame cancelled by user
   ePvErrDataLost     = 15,      // The data for the frame was lost
    ePvErrDataMissing  = 16,      // Some data in the frame is missing
   ePvErrTimeout      = 17,      // Timeout during wait
    ePvErrOutOfRange   = 18,      // Attribute value is out of the expected range
   ePvErrWrongType    = 19,      // Attribute is not this type (wrong access function)
    ePvErrForbidden    = 20,      // Attribute write forbidden at this time
   ePvErrUnavailable  = 21,      // Attribute is not available at this time
    ePvErrFirewall     = 22,      // A firewall is blocking the traffic (Windows only)
   __ePvErr_force_32   = 0xFFFFFFFF
} tPvErr;

typedef enum
{
   ePvAccessMonitor       = 2, // Monitor access: no control, read & listen only
   ePvAccessMaster        = 4, // Master access: full control
   __ePvAccess_force_32    = 0xFFFFFFFF
} tPvAccessFlags;


typedef struct
{
   unsigned long      StructVer;            // Version of this structure
   //---- Version 1 ----
   unsigned long      UniqueId;           // Unique value for each camera
   char               CameraName[32];     // People-friendly camera name (usually part name)
   char               ModelName[32];      // Name of camera part
   char               PartNumber[32];     // Manufacturer's part number
   char               SerialNumber[32];   // Camera's serial number
   char               FirmwareVersion[32]; // Camera's firmware version
   unsigned long      PermittedAccess;    // A combination of tPvAccessFlags
   unsigned long      InterfaceId;        // Unique value for each interface or bus
   tPvInterface       InterfaceType;      // Interface type; see tPvInterface

} tPvCameraInfoEx;


  unsigned long PVDECL PvCameraListEx(tPvCameraInfoEx* pList,
                         unsigned long ListLength,
                    unsigned long* pConnectedNum,
                    unsigned long StructSize);

  tPvErr PVDECL PvCameraOpen(unsigned long UniqueId,
              tPvAccessFlags AccessFlag,
                             tPvHandle* pCamera);
Quasi folgendermassen übersetzt:

Delphi-Quellcode:
 

  {MINENUMSIZE 4} // stimmt diese Größe???
 
  tPvHandle = Pointer;


  vErr =
      (ePvErrSuccess       = 00,       // No error
       ePvErrCameraFault   = 01,       // Unexpected camera fault
       ePvErrInternalFault = 02,       // Unexpected fault in PvApi or driver
       ePvErrBadHandle     = 03,       // Camera handle is invalid
       ePvErrBadParameter  = 04,       // Bad parameter to API call
       ePvErrBadSequence   = 05,       // Sequence of API calls is incorrect
       ePvErrNotFound      = 06,       // Camera or attribute not found
       ePvErrAccessDenied  = 07,       // Camera cannot be opened in the specified mode
       ePvErrUnplugged     = 08,       // Camera was unplugged
       ePvErrInvalidSetup  = 09,       // Setup is invalid (an attribute is invalid)
       ePvErrResources     = 10,       // System/network resources or memory not available
       ePvErrBandwidth     = 11,       // 1394 bandwidth not available
       ePvErrQueueFull     = 12,       // Too many frames on queue
       ePvErrBufferTooSmall = 13,       // Frame buffer is too small
       ePvErrCancelled     = 14,       // Frame cancelled by user
       ePvErrDataLost      = 15,       // The data for the frame was lost
       ePvErrDataMissing   = 16,       // Some data in the frame is missing
       ePvErrTimeout       = 17,       // Timeout during wait
       ePvErrOutOfRange    = 18,       // Attribute value is out of the expected range
       ePvErrWrongType     = 19,       // Attribute is not this type (wrong access function)
       ePvErrForbidden     = 20,       // Attribute write forbidden at this time
       ePvErrUnavailable   = 21,       // Attribute is not available at this time
       ePvErrFirewall      = 22,       // A firewall is blocking the traffic (Windows only)
       __ePvErr_force_32    = $FFFFFFFF
      ) ;

  tPvAccessFlags =
      (ePvAccessMonitor    = 2,        // Monitor access: no control, read & listen only
       ePvAccessMaster     = 4,        // Master access: full control
       __ePvAccess_force_32 = $FFFFFFFF
      );


tPvCameraInfoEx = Packed Record
                      StructVer  : Cardinal;                    // Version of this structure
                      //---- Version 1 ----
                      UniqueId       : Cardinal;             // Unique value for each camera
                      CameraName     : Array [0..32] of Char; // People-friendly camera name (usually part name)
                      ModelName      : Array [0..32] of Char; // Name of camera part
                      PartNumber     : Array [0..32] of Char; // Manufacturer's part number
                      SerialNumber   : Array [0..32] of Char; // Camera's serial number
                      FirmwareVersion : Array [0..32] of Char; // Camera's firmware version
                      PermittedAccess : Cardinal;             // A combination of tPvAccessFlags
                      InterfaceId    : Cardinal;             // Unique value for each interface or bus
                      InterfaceType  : tPvInterface;         // Interface type; see tPvInterface
                    end;

Function PvCameraListEx (pList : Array of tPvCameraInfoEx; ListLength : Cardinal; pConnectedNum : Cardinal; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';
Function PvCameraOpen  (UNiqueID : Cardinal; AccessFlag : tPvAccessFlags; pCamera : tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
Leider möchte das bereits an dieser frühen Stelle nicht kompilieren. Bin recht zuversichtlich, aber es kommt ja noch die Extraktion der Bilder aus dem Datenstream...

Ich denke, daß Cardinal dem unsigned long entsprechen sollte. Die Frage ist allerdings, ob die Array-Grenzen so richtig sind, ob es tatsächlich ein Packed Record ist und vor allem wie die Pointereien im Aufruf umzusetzen sind. Oder hab ich hier noch ganz andere Fehler drin?

Jan




Aufrufen würde ich das später etwa so:
Delphi-Quellcode:
    Var listAVTGigECams : Array [0..20] of tPvCameraInfoEx;
    valNumberOfCams     : Cardinal;
    valAvailableCams    : Cardinal;
    aHandle             : tPvHandle;

begin

  valNumberOfCams := PvCameraListEx (listAVTGigECameras, High (listAVTGigECams), valAvailableCameras, SizeOf (tPvCameraInfoEx));
  PvCameraOpen (listAVTGigECameras[0].UniqueID, aHandle);

end;

BoolString 11. Jul 2012 21:01

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Ohne pushen zu wollen, aber wie würde man denn dies Konstrukt:

Delphi-Quellcode:
unsigned long PVDECL PvCameraListEx(tPvCameraInfoEx* pList,
                                            unsigned long ListLength,
                                            unsigned long* pConnectedNum,
                                            unsigned long StructSize);
wohl korrekt übersetzen und aufrufen? Ich glaube ich hab nicht wirklich die Essenz der Zeiger. Einer meiner verschiedenen Versuche war:

Delphi-Quellcode:
Function PvCameraListEx (pList : Array of tPvCameraInfoEx; ListLength : Cardinal; pConnectedNum : Cardinal; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';


type tlistAVTGigECams = Array [0..15] of tPvCameraInfoEx;
Var listAVTGigECams : tlistAVTGigECams;
valNumberOfCams := PvCameraListEx (listAVTGigECams, High (listAVTGigECams), valAvailableCams, SizeOf (tPvCameraInfoEx));
Mal davon abgesehen, daß meine Arrays im obigen Posting noch alle einen zu lang waren...

jan

Horst0815 12. Jul 2012 01:28

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
http://forum.delphi-treff.de/showthr...er-f%FCr-C-DLL

brechi 12. Jul 2012 08:16

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Du darfst es nicht als "array of byte" uebersetzen, da dann zwei intern die Laenge+Groesse des Array uebergeben wird, woduch die Parameter nicht mehr mit dem C header uebereinstimmen. Unter der UniversaAPI koennen maximal 64 Kameras angesprochen werden. Also versuchs mal mit:

Delphi-Quellcode:
type
  tPvCameraInfoExList = array[0..63] of tPvCameraInfoEx;
  PPvCameraInfoEx = ^tPvCameraInfoEx;

Function PvCameraListEx (pList : PPvCameraInfoEx; ListLength: Cardinal; pConnectedNum : Cardinal; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';

Var listAVTGigECams : tPvCameraInfoExList ;
valNumberOfCams := PvCameraListEx (@listAVTGigECams, Length(listAVTGigECams), valAvailableCams, SizeOf (tPvCameraInfoEx));
oder

Delphi-Quellcode:
type
  tPvCameraInfoExList = array of tPvCameraInfoEx;
  PPvCameraInfoEx = ^tPvCameraInfoEx;

Function PvCameraListEx (pList : PPvCameraInfoEx; ListLength: Cardinal; pConnectedNum : Cardinal; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';

Var listAVTGigECams : tPvCameraInfoExList ;
setLength(listAVTGigECams , 10);
if Length(listAVTGigECams) > 0 then
  valNumberOfCams := PvCameraListEx (@listAVTGigECams[0], Length(listAVTGigECams), valAvailableCams, SizeOf (tPvCameraInfoEx));

BoolString 13. Jul 2012 12:48

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
@horst0815: Danke, aber das sind Punkte, die kommen erst noch deutlich später. Wen ich mal bis zu diesem Schritt gekommen bin, werd ich da sicherlich auch Infos rausziehen können...

@brechi: Der Bezugspunkt bezüglich deiner 'Array of Byte' Anmerkung ist nicht ganz klar geworden. Hatte in den bisherigen Postings keine solche Struktur.


Die Funktion PvCameraListEx der DLL kann ich erstmal fehlerfrei anrufen. Allerdings erzeugt der Aufruf :

Delphi-Quellcode:
 tPvInterface =
      (ePvInterfaceFirewire   = 1,      // Firewire interface
       ePvInterfaceEthernet   = 2,      // Ethernet interface
       __ePvInterface_force_32 = $FFFFFFFF
      );


 tPvCameraInfoEx = Packed Record
                      StructVer      : Cardinal;                // Version of this structure
                      //---- Version 1 ----
                      UniqueId       : Cardinal;             // Unique value for each camera
                      CameraName     : Array [0..31] of Byte; // People-friendly camera name (usually part name)
                      ModelName      : Array [0..31] of Byte; // Name of camera part
                      PartNumber     : Array [0..31] of Byte; // Manufacturer's part number
                      SerialNumber   : Array [0..31] of Byte; // Camera's serial number
                      FirmwareVersion : Array [0..31] of Byte; // Camera's firmware version
                      PermittedAccess : Cardinal;             // A combination of tPvAccessFlags
                      InterfaceId    : Cardinal;             // Unique value for each interface or bus
                      InterfaceType  : tPvInterface;         // Interface type; see tPvInterface
                    end;


  tPvCameraInfoExList = array of tPvCameraInfoEx;
  pPvCameraInfoExList = ^tPvCameraInfoExList;
  tConnectedCams     = Cardinal;
  pConnectedCams     = ^tConnectedCams;



  Function PvCameraListEx (pList : pPvCameraInfoExList; ListLength : Cardinal; pConnectedNum : pConnectedCams; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';

auf folgende Weise:

Delphi-Quellcode:
Var listAVTGigECams : tPvCameraInfoExList;
    valNumberOfCams : Cardinal;
    valAvailableCams : Cardinal;
    i: Integer;

begin

  SetLength (listAVTGigECams, 1);

  valNumberOfCams := PvCameraListEx (@listAVTGigECams, Length (listAVTGigECams), @valAvailableCams, SizeOf (tPvCameraInfoEx));

  Sleep (100);

  memo1.Lines.Add ('High  value           : ' + IntToStr(High  (listAVTGigECams)));
  memo1.Lines.add ('Number of cams in list : ' + IntToStr (valNumberOfCams));
  memo1.Lines.add ('Number of cams available: ' + IntToStr (valAvailableCams));

  For i := 00 to valNumberofCams-1 do
  Begin
    Memo1.Lines.Add (IntToStr (listAVTGigECams[i].UniqueID));
    Memo1.Lines.Add (Chr(listAVTGigECams[i].CameraName[0]));
  end;
end;
ein merkwürdiges Verhalten. wenn man das ganze im Debugger beobachtet, dann beinhaltet das Array listAVTGigECams nach SetLength genau einmal den Record. Nachdem die Funktion PvCameraListEx aufgerufen wurde, besitzen die Variablen valNumberOfCams und valAvailableCams die korrekten Werte (eine Kamera) in der Liste der lokalen Variablen des Dubuggers.
Das Array listAVTGigECams besitzt allerdings plötzlich 131072 (0..131071) Elemente, wovon die ersten 365 (0..364) leer sind. Das Element 366 (Index 365) beinhaltet die erwartete Record Struktur; wenn auch mit komplett unherleitbaren Werten. Gleiches gilt für die folgenden Elemente. Element 752-1093 (Index 751-1092) ist wieder leer und so weiter.

Nach dem Aufruf der Funktion PvCameraListEx kann man auch nicht mehr auf die anderen Variablen zugreifen (oben z.B. in den Memo1.lines.Add); hier werden vermutlich Speicherzuweisungen überschrieben.


Ich habe momentan die Vermutung, daß es an der Definition von tPvCameraInfoEx liegt. Das SizeOf zeigt mit 180 den Wert an, den ich erwarten würde. Allerdings ist mir die Indizierungs des Arrays auffällig mit 2*180+5 verknüpft. Es sind 5 Arrays of Byte da drin. Ich hab versucht an diversen Stelen nachzulesen (unter anderem Asserbads DLL Manual) und hab eine Übersetzungsempfehlung für
Delphi-Quellcode:
 char CameraName[32]
mit
Delphi-Quellcode:
CameraName : Array [00..31] of Byte
gefunden. Ein Char geht nicht mehr, da es unter DelphiXE dem WideChar entspricht; obgleich man dann ja wohl auch AnsiChar verwenden könnte. Die Größe von tPvInterface scheint durch den $FFFFFFFF Wert korrekt auf 4 Byte aliniert zu werden.

Wenn die Kamera abgezogen ist, wird das Array nicht bestückt und man kann auch auf die Variablen valNumberOfCams und valAvailableCams zugreifen.

[...]

brechi 13. Jul 2012 17:53

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Ich meinte auch
Delphi-Quellcode:
array of tPvCameraInfoEx;
Wenn du dynamische Arrays verwendest und diese als Pointer uebergeben willst musst du immmer @Array[0] uebergeben, niemals @Array, denn vor dem 1. Element sind noch andere Daten gespeichert (Laenge).

Also entweder du verwendest ein statisches Array (dann geh @Array aber auch dort ist @Array[0] erlaubt) oder ein dynamisches mit @Array[0].

Delphi-Quellcode:
tPvInterface =
      (ePvInterfaceFirewire = 1, // Firewire interface
       ePvInterfaceEthernet = 2, // Ethernet interface
       __ePvInterface_force_32 = $FFFFFFFF
      );


 tPvCameraInfoEx = Packed Record
                      StructVer : Cardinal;   // Version of this structure
                      //---- Version 1 ----
                      UniqueId : Cardinal; // Unique value for each camera
                      CameraName : array[0..31] of char; // People-friendly camera name (usually part name)
                      ModelName : array[0..31] of char; // Name of camera part
                      PartNumber : array[0..31] of char; // Manufacturer's part number
                      SerialNumber : array[0..31] of char; // Camera's serial number
                      FirmwareVersion : array[0..31] of char; // Camera's firmware version
                      PermittedAccess : Cardinal; // A combination of tPvAccessFlags
                      InterfaceId : Cardinal; // Unique value for each interface or bus
                      InterfaceType : tPvInterface; // Interface type; see tPvInterface
                    end;


  tPvCameraInfoExList = array of tPvCameraInfoEx;
  tConnectedCams = Cardinal;



  Function PvCameraListEx (pList : pPvCameraInfoExList; ListLength : Cardinal; out pConnectedNum : pConnectedCams; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';


Var listAVTGigECams : tPvCameraInfoExList;
    valNumberOfCams : Cardinal;
    valAvailableCams : Cardinal;
    i: Integer;
begin

  SetLength (listAVTGigECams, 1);

  valNumberOfCams := PvCameraListEx (@listAVTGigECams[0], Length (listAVTGigECams), valAvailableCams, SizeOf (tPvCameraInfoEx));

  Sleep (100);

  memo1.Lines.Add ('High value : ' + IntToStr(High (listAVTGigECams)));
  memo1.Lines.add ('Number of cams in list : ' + IntToStr (valNumberOfCams));
  memo1.Lines.add ('Number of cams available: ' + IntToStr (valAvailableCams));

  For i := 0 to valNumberofCams-1 do
  Begin
    Memo1.Lines.Add (IntToStr (listAVTGigECams[i].UniqueID));
    Memo1.Lines.Add (listAVTGigECams[i].CameraName));
  end;
end;

BoolString 17. Jul 2012 10:14

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Theoretisch hätte mir das wohl klar sein sollen; aber praktisch...

Ich hab zumindest über das Wocheende ein wenig weiter dran gearbeitet und komme inzwischen auch an diverse Attribute der Kamera heran.

Ich kann die Kamera inzwischen auch sauber öffnen. Allerdings bekomme ich dabei den PermittedAccess Status 6 zurückgeliefert. Laut SDK Unterlagen sollen aber nur die Statuswerte 2 und 4 (und nicht deren addierte Bitsumme) valide sein. Was könnte das denn wohl bedeuten?

Ich glaube, daß ich schon ein großes Stück weiter bin. Habe mir aus diversen C-Samples jetzt etwas zusammengebastelt. Das muss alles noch in einzelne Procs/Funcs ausgelagert werden, aber für eine Version zum Debuggen ist es ganz praktisch. Derzeit hängt es aber an der Struktur des pFrame (?). Ich versuche das so ähnlich zu machen wie in den C-Samples und im Quellcode, den horst0815 gepostet hat. aber hier stimt irgendwas noch nicht. Ich komme derzeit an kein Bild. Der PvCaptureQueueFrame wirft eine Exception, die ich nicht richtig verfolgt bekomme.

Ich habe derzeit die Header-Datei folgendermassen übersetzt (Ausschnitte):
Delphi-Quellcode:
  tPvImageFormat =
      (ePvFmtMono8         = 0,           // Monochrome, 8 bits
        ePvFmtMono16        = 1,           // Monochrome, 16 bits, data is LSB aligned
        ePvFmtBayer8        = 2,           // Bayer-color, 8 bits
        ePvFmtBayer16       = 3,           // Bayer-color, 16 bits, data is LSB aligned
        ePvFmtRgb24         = 4,           // RGB, 8 bits x 3
        ePvFmtRgb48         = 5,           // RGB, 16 bits x 3, data is LSB aligned
        ePvFmtYuv411        = 6,           // YUV 411
        ePvFmtYuv422        = 7,           // YUV 422
        ePvFmtYuv444        = 8,           // YUV 444
        ePvFmtBgr24         = 9,           // BGR, 8 bits x 3
        ePvFmtRgba32        = 10,          // RGBA, 8 bits x 4
        ePvFmtBgra32        = 11,          // BGRA, 8 bits x 4
        ePvFmtMono12Packed = 12,          // Monochrome, 12 bits,
        ePvFmtBayer12Packed = 13,          // Bayer-color, 12 bits, packed
        __ePvFmt_force_32   = $FFFFFFFF
       );


//
// Bayer pattern. Applicable when a Bayer-color camera is sending raw bayer
// data.
//
  tPvBayerPattern =
      (ePvBayerRGGB       = 0,           // First line RGRG, second line GBGB...
       ePvBayerGBRG       = 1,           // First line GBGB, second line RGRG...
        ePvBayerGRBG       = 2,           // First line GRGR, second line BGBG...
       ePvBayerBGGR       = 3,           // First line BGBG, second line GRGR...
       __ePvBayer_force_32 = $FFFFFFFF
       );


  tPvFrame = Packed Record
               //----- In -----
                ImageBuffer         : Pointer;                 // Buffer for image/pixel data.
               ImageBufferSize     : Cardinal;                // Size of ImageBuffer in bytes
               AncillaryBuffer     : Pointer;                 // Camera Firmware >= 1.42 Only.
                                                                              // Buffer to capture ancillary chunk mode data. See ChunkModeActive attr.
                                                                   // This MUST be 0 if not in use.
                                                                              // Chunk mode format:
                                                                              //   [Bytes 1 - 4]  acquisition count.
                                                                              //   [Bytes 5 - 8]  user value. Not currently implemented. 0.
                                                                              //     [Bytes 9 - 12] exposure value.
                                                                   //     [Bytes 13 - 16] gain value.
                                                                              //     [Bytes 17 - 18] sync in levels.
                                                                   //     [Bytes 19 - 20] sync out levels.
                                                                              //     [Bytes 21 - 40] not implemented. 0.
                                                                   //     [Bytes 41 - 44] chunk ID. 1000.
                                                                              //     [Bytes 45 - 48] chunk length.
                AncillaryBufferSize : Cardinal;                // Size of your ancillary buffer in bytes. See NonImagePayloadSize attr.
                                                                   //   Set to 0 for no buffer.
               Context             : Array [0..3] of Pointer; // For your use. Possible application: unique ID
                                                                              //   of tPvFrame for frame-done callback.
               _reserved1           : Array [0..7] of Cardinal;
                //----- Out -----
               Status              : tPvErr;                  // Status of this frame
                ImageSize           : Cardinal;                // Image size, in bytes
               AncillarySize       : Cardinal;                // Ancillary data size, in bytes
               Width               : Cardinal;                // Image width
               Height              : Cardinal;                // Image height
                RegionX             : Cardinal;                // Start of readout region (left)
                RegionY             : Cardinal;                // Start of readout region (top)
                Format              : tPvImageFormat;          // Image format
               BitDepth            : Cardinal;                // Number of significant bits
                BayerPattern        : tPvBayerPattern;         // Bayer pattern, if bayer format
                FrameCount          : Cardinal;                // Frame counter. Uses 16bit GigEVision BlockID. Rolls at 65535.
                TimestampLo         : Cardinal;                // Time stamp, lower 32-bits
                TimestampHi         : Cardinal;                // Time stamp, upper 32-bits
               _reserved2           : Array [0..31] of Cardinal;
             end;



  tPvCameraInfoExList = array of tPvCameraInfoEx;
  pPvCameraInfoExList = ^tPvCameraInfoExList;
  tConnectedCams     = Cardinal;
  pConnectedCams     = ^tConnectedCams;
  pPvFrame           = ^tPvFrame;


Const PVINFINITE     = $FFFFFFFF; // Never timeout


//-------------------------------------------------------------------------------------
// define DLL-calls:
    Function PvAttrEnumSet            (pCamera: tPvHandle; Name: PAnsiChar; Value: PAnsiChar): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvAttrUint32Get          (pCamera: tPvHandle; Name: PAnsiChar; Out pValue: Cardinal) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCameraListEx           (pList: pPvCameraInfoExList; ListLength : Cardinal; Out ConnectedNum : tConnectedCams; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';
    Function PvCameraClose            (pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCameraOpen             (UniqueID: Cardinal; AccessFlag: tPvAccessFlags; Out pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureStart           (pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureQueueFrame      (pCamera: tPvHandle; pFrame: pPvFrame; FrameCallBack: Pointer ): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureWaitForFrameDone (pCamera: tPvHandle; pFrame: pPvFrame; Timeout: Cardinal): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCommandRun             (pCamera: tPvHandle; Name : PAnsiChar): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvInitialize             : tPvErr;       stdcall; external 'PvAPI.dll';
    Function PvInitializeNoDiscovery  : tPvErr;       stdcall; external 'PvAPI.dll';
    Procedure PvUnInitialize;                           stdcall; external 'PvAPI.dll';
    Procedure PvVersion                (Var Major, Minor: Cardinal); stdcall; external 'PvAPI.dll';
Auf der anderen seite steckt erst einmal alles in einem ButtonClick:

Delphi-Quellcode:
procedure TForm1.Button6Click(Sender: TObject);
Var aFrame      : tPvFrame;
    aFrameBuffer : Array of Byte;
    aBitMap     : tBitmap;
    aErrValue   : tPvErr;

Begin
  aErrValue := PvAttrUint32Get (CamHandle, 'TotalBytesPerFrame', aFrame.ImageBufferSize);
  If aErrValue = ePvErrSuccess then
  Begin
    SetLength (aFrameBuffer, aFrame.ImageBufferSize);
    aFrame.ImageBuffer := @aFrameBuffer[0];
  end
  Else
  Begin
    Exit;
  end;

  aErrValue := PvCaptureStart (CamHandle);
  If aErrValue = ePvErrSuccess THen
  Begin

    aErrValue := PvAttrEnumSet (CamHandle, 'FrameStartTriggerMode', 'Freerun');
    If aErrValue = ePvErrSuccess Then
    Begin

      aErrValue := PvCommandRun (CamHandle, 'AcquisitionStart');
      If aErrValue = ePvErrSuccess Then
      Begin

        aErrValue := PvCaptureQueueFrame (CamHandle, @aFrame, 0) ;
        If aErrValue = ePvErrSuccess Then
        Begin

          aErrValue := PvCaptureWaitForFrameDone (CamHandle, @aFrame, PVINFINITE);
          If aErrValue = ePvErrSuccess Then
          Begin
//            CreateDIBitmap (@aBitmap,...?????)
            Beep;Beep;Beep;
          end;

        end;
      end;

    end;


  end;
end;
Soweit ich es der SDK-Doku entnehme sollte so eine Aufrufreihenfolge zum Erfolg führen. Aber momentan ist dem noch nicht so...

Jan

PS: Was sind denn wohl erfahrungsgemäß gute Werte für ein TimeOut der Kamera im Debugmodus?

BoolString 17. Jul 2012 21:48

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Update...

ich bin inzwischen so weit, daß ich ein einzelnes Frame (theoretisch) per DLL einfangen kann. Hier scheint im Debug der Timeout ein Problem gewesen zu sein und schlechte Lötstellen von einem nicht spezifiziertes Unterwasser-Kabel. Nachdem ich diese erstmal ausgetauscht habe, habe ich auch keine 'Camera was unplugged' mehr.

Das Kommando PvCaptureWaitForFrameDone liefert nun ein Success zurück. Leider hat der entsprechend zurückgelieferte Frame keine Daten und das Status sagt, daß einige Daten verloren gingen (Error Code 16). Das ist charmant untertrieben, da Image Size 0 besagt. Die anderen Werte (die mir logisch nachvollziehbar erscheinen, wie FrameCount, FrameWidth, und FrameHeight) scheinen korrekt zu sein. Mit der BitDepth von 8 bin ich mir nicht sicher; das ist doch garantiert nicht pro RGB Kanal gemeint? Auch ist mir noch nicht ganz klar, wie ich die Daten aus dem Pointer mit den anderen Infos zu einem korrekten Bitmap zusammenstelle, welches ich dann speichern und darstellen kann.

Ich versuche es in der DLL Anbindung jetzt so:

Delphi-Quellcode:
    Function PvAttrBooleanGet         (pCamera: tPvHandle; Name: PAnsiChar; Out pValue: Boolean) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvAttrBooleanSet         (pCamera: tPvHandle; Name: PAnsiChar; pValue: Boolean) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvAttrEnumGet            (pCamera: tPvHandle; Name: PAnsiChar; Out pBuffer : PAnsiChar; BufferSize: Cardinal; Out pSize: Cardinal): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvAttrEnumSet            (pCamera: tPvHandle; Name: PAnsiChar; Value: PAnsiChar): tPvErr; stdcall; external 'PvAPI.dll';
//geht noch nicht://    Function PvAttrUint32Get          (pCamera: tPvHandle; Name: PAnsiChar; Out pValue: Cardinal) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCameraListEx           (pList: pPvCameraInfoExList; ListLength : Cardinal; Out ConnectedNum : tConnectedCams; Size : Cardinal) : Cardinal; stdcall; external 'PvAPI.dll';
    Function PvCameraClose            (pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCameraCount            : Cardinal; stdcall; external 'PvAPI.dll';
    Function PvCameraOpen             (UniqueID: Cardinal; AccessFlag: tPvAccessFlags; Out pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureEnd             (pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureStart           (pCamera: tPvHandle) : tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureQueueFrame      (pCamera: tPvHandle; pFrame: pPvFrame; FrameCallBack: Pointer ): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCaptureWaitForFrameDone (pCamera: tPvHandle; pFrame: pPvFrame; Timeout: Cardinal): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvCommandRun             (pCamera: tPvHandle; Name : PAnsiChar): tPvErr; stdcall; external 'PvAPI.dll';
    Function PvInitialize             : tPvErr;       stdcall; external 'PvAPI.dll';
    Function PvInitializeNoDiscovery  : tPvErr;       stdcall; external 'PvAPI.dll';
    Procedure PvUnInitialize;                           stdcall; external 'PvAPI.dll';
    Procedure PvVersion                (Var Major, Minor: Cardinal); stdcall; external 'PvAPI.dll';

implementation


Function PvReturnErrorString (aErrCode: tPvErr) : String;
Begin
  Case aErrCode of
     ePvErrSuccess       : Result := 'Code 0000: No error';
     ePvErrCameraFault   : Result := 'Code 0001: Unexpected camera fault';
     ePvErrInternalFault : Result := 'Code 0002: Unexpected fault in PvApi or driver';
     ePvErrBadHandle     : Result := 'Code 0003: Camera handle is invalid';
     ePvErrBadParameter  : Result := 'Code 0004: Bad parameter to API call';
     ePvErrBadSequence   : Result := 'Code 0005: Sequence of API calls is incorrect';
     ePvErrNotFound      : Result := 'Code 0006: Camera or attribute not found';
     ePvErrAccessDenied  : Result := 'Code 0007: Camera cannot be opened in the specified mode';
     ePvErrUnplugged     : Result := 'Code 0008: Camera was unplugged';
     ePvErrInvalidSetup  : Result := 'Code 0009: Setup is invalid (an attribute is invalid)';
     ePvErrResources     : Result := 'Code 0010: System/network resources or memory not available';
     ePvErrBandwidth     : Result := 'Code 0011: 1394 bandwidth not available';
     ePvErrQueueFull     : Result := 'Code 0012: Too many frames on queue';
     ePvErrBufferTooSmall : Result := 'Code 0013: Frame buffer is too small';
     ePvErrCancelled     : Result := 'Code 0014: Frame cancelled by user';
     ePvErrDataLost      : Result := 'Code 0015: The data for the frame was lost';
     ePvErrDataMissing   : Result := 'Code 0016: Some data in the frame is missing';
     ePvErrTimeout       : Result := 'Code 0017: Timeout during wait';
     ePvErrOutOfRange    : Result := 'Code 0018: Attribute value is out of the expected range';
     ePvErrWrongType     : Result := 'Code 0019: Attribute is not this type (wrong access function)';
     ePvErrForbidden     : Result := 'Code 0020: Attribute write forbidden at this time';
     ePvErrUnavailable   : Result := 'Code 0021: Attribute is not available at this time';
     ePvErrFirewall      : Result := 'Code 0022: A firewall is blocking the traffic (Windows only)';
     __ePvErr_force_32    : Result := 'Code $FFFFFFFF: Codon forcing Error codes to be 32bit';
  end;
end;

Und im eigentlichen Programm rufe ich die Funktionen wie nachfolgend auf. Es ist vorläufig eine Testversion, die auf jeden Fall dringender Überarbeitung bedarf. Wenn das ganze mal Bilder liefert denke ich, daß die komplette Unit mit Beispiel hier Veröffentlichung finden sollte. Dafür das in der FeatureMatrix des Herstellers die Delphi-Option gelistet ist, finde ich die reale Umsetzung für ein SDK doch etwas unumgänglich:

Delphi-Quellcode:
procedure TForm1.Button6Click(Sender: TObject);
Var aFrame      : tPvFrame;
    aFrameBuffer : Array of Byte;
    aBitMap     : tBitmap;
    aErrValue   : tPvErr;
    aString     : PAnsiChar;
    aValue      : Cardinal;
    bmp_BMI     : BITMAPINFO;
    bmp_Bitmap  : tBitmap;

Begin
  aErrValue := PvAttrUint32Get (CamHandle, 'TotalBytesPerFrame', aFrame.ImageBufferSize);
  If aErrValue = ePvErrSuccess then
  Begin
    SetLength (aFrameBuffer, aFrame.ImageBufferSize);
    aFrame.ImageBuffer := @aFrameBuffer[0];
  end
  Else
  Begin
    Exit;
  end;

  aErrValue := PvCaptureStart (CamHandle);
  If aErrValue = ePvErrSuccess THen
  Begin

    aErrValue := PvAttrEnumSet (CamHandle, 'FrameStartTriggerMode', 'Freerun');
    Memo1.Lines.Add ('Set FrameStartTriggerMode  : ' + PvReturnErrorString (aErrValue));

    If aErrValue = ePvErrSuccess Then
    Begin
//      SetLength (aString, 20);
      aErrValue := PvAttrEnumGet (CamHandle, 'FrameStartTriggerMode', aString, SizeOf (aString[0]), aValue);
      Memo1.Lines.Add ('Get FrameStartTriggerMode  : ' + PvReturnErrorString (aErrValue)+ ' ; String:' + aString + ';(' + IntToStr (aValue) + ')');


      aErrValue := PvCommandRun (CamHandle, 'AcquisitionStart');
      Memo1.Lines.Add ('CommandRun AcquisitionStart : ' + PvReturnErrorString (aErrValue));

      If aErrValue = ePvErrSuccess Then
      Begin

        aErrValue := PvCaptureQueueFrame (CamHandle, @aFrame, 0) ;
        Memo1.Lines.Add ('CaptureQueueFrame          : ' + PvReturnErrorString (aErrValue));

        If aErrValue = ePvErrSuccess Then
        Begin

          aErrValue := PvCaptureWaitForFrameDone (CamHandle, @aFrame, PVINFINITE);
          Memo1.Lines.Add ('Capture Wait For Frame Done : ' + PvReturnErrorString (aErrValue));

          If aErrValue = ePvErrSuccess Then
          Begin
            Memo1.Lines.Add ('Frame count                : ' + IntToStr (aFrame.FrameCount));
            Memo1.Lines.Add ('Bit depth                  : ' + IntToStr (aFrame.BitDepth));
            Memo1.Lines.Add ('Frame width                : ' + IntToStr (aFrame.Width));
            Memo1.Lines.Add ('Frame height               : ' + IntToStr (aFrame.Height));
            Memo1.Lines.Add ('Image size                 : ' + IntToStr (aFrame.ImageSize));
            Memo1.Lines.Add ('Frame status               : ' + PvReturnErrorString (aFrame.Status));


            bmp_BMI.bmiHeader.biSize         := SizeOf (bmp_BMI.bmiHeader);
            bmp_BMI.bmiHeader.biWidth        := aFrame.Width;
            bmp_BMI.bmiHeader.biHeight       := aFrame.Height;
            bmp_BMI.bmiHeader.biPlanes       := 1;
            bmp_BMI.bmiHeader.biBitCount     := aFrame.BitDepth;
            bmp_BMI.bmiHeader.biCompression  := BI_RGB;
            bmp_BMI.bmiHeader.biSizeImage    := 0;
            bmp_BMI.bmiHeader.biXPelsPerMeter := 0;
            bmp_BMI.bmiHeader.biYPelsPerMeter := 0;
            bmp_BMI.bmiHeader.biClrUsed      := 0;
            bmp_BMI.bmiHeader.biClrImportant := 0;


//            CreateDIBitmap (@aBitmap,...?????)
//createDIBSection

//            image1.Picture.Bitmap.Handle
          end;

          aErrValue := PvCaptureEnd (CamHandle);
          Memo1.Lines.Add ('Capture end                : ' + PvReturnErrorString (aErrValue));

        end;
      end;
    end;
  end;
end;
Liebe Grüße aus dem Norden

Jan

brechi 17. Jul 2012 21:52

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Du solltest den Buffer mal clearen.

Delphi-Quellcode:
ZeroMemory(@aFrame, SizeOf(aFrame);
aErrValue := PvAttrUint32Get (CamHandle, 'TotalBytesPerFrame', totalbytes);
  If aErrValue = ePvErrSuccess then
  Begin
    SetLength (aFrameBuffer, totalbytes);
    aFrame.ImageBufferSize := totalbytes;
    aFrame.ImageBuffer := @aFrameBuffer[0];
  end;
Den Mode kann man vorher einstellen (8bit gray, 16bitgray, rgb, etc.).

Du musst dir dann ein Bitmap erstellen und die Pixel z.B. mit SetBitmapBits setzen. Als alternative zum Testen gehts auch erstmal mit nem Bitmap und Scanline.

BoolString 17. Jul 2012 22:16

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Leider nicht...

Ich hab das Memory Blanking jetzt an der hier geposteten Selle und an einer anderen (nicht geposteten) eingebaut.
Das Ergebnis ist aber immer noch dasselbe. Es kommt immer ein tPvFrame.Status = 16, 'Some data in frame missing'.

Jan

BoolString 19. Jul 2012 09:40

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Ich habe spaßeshalber mal eine andere Kamera angeschlossen (Prosilica GE2040 monochrom) und dabei ist mir etwas aufgefallen. Wenn das Bildformat der Kamera auf Mono8 gestellt ist, dann erhalte ich plötzlich auch Daten im FrameBuffer (nach PvCaptureWaitForFrameDone), der bisher immer nur mit 0 gefüllt blieb.
Stelle ich die Farbkamera (GC2450C) mit dem Prosilica Herstellertool von Bayer8 ebenfalls auf 8bit monochrom (Mono8) um, dann bekomme ich auch hier plötzlich Daten in meinen Buffer geschrieben (zumindest unterscheiden sich nach jetzigem Erkenntnisstand die Werte von 0). Das kann es zwar auf Dauer nicht sein, ich möchte ja auch gerne die Farben, aber es ist wenigstens mal wieder ein kleiner Fortschritt.
Bei beiden Varianten habe ich aber immer wieder den Fall, daß einige Frames ausfallen mit der Fehlermeldung, daß einige Daten fehlen (Error Code 16).


Ich habe mir inzwischen aus dem MSDN Informationen zusammengesucht um aus einem Speicherbereich ein Bitmap zu erzeugen, welches ich erst einmal auf dem Bildschirm mit einer TImage Komponente darstellen wollte. Für Stream und Dateien gibt es ja genug Beispiele. Für diesen Fall sind die Samples aber eer schmal gestreut und erschienen nicht anwendbar/funktional.
Derzeit scheinen die Bilddaten allerdings trotzdem irgenwo hängen zu bleiben. Auch ist noch nicht klar, wie die Palette des Bildes korrekt auszuformulieren ist. Ich versuche derzeit (bislang ja nur Graustufen) eine Palette manuell einzubauen. Werden bmiColors einfach ignoriert, wenn entsprechende RGB Werte vorliegen? Dies muss ja sicherlich anders im Header deklariert werden.
Oder gibt es hier evtl. noch andere Faktoren die ich bislang nicht gefunden habe?

Delphi-Quellcode:
Var aFrame      : tPvFrame;
    aFrameBuffer : Array of Byte;
    aBitMap     : tBitmap;
    aErrValue   : tPvErr;
    aString     : PAnsiChar;
    aValue      : Cardinal;
    bmpInfo     : ^BITMAPINFO;
    totalbytes  : Cardinal;
    aChar       : Char;
    dc          : HDC;
    hBmp        : HBITMAP;
    cp          : PRGBQUAD;
    j           : Cardinal;

            GetMem(bmpInfo, sizeof(bmpInfo.bmiHeader) + sizeof(RGBQUAD) * Trunc(Power (2, aFrame.BitDepth)));

            bmpInfo^.bmiHeader.biSize         := SizeOf (bmpInfo.bmiHeader);
            bmpInfo^.bmiHeader.biWidth        := aFrame.Width;
            bmpInfo^.bmiHeader.biHeight       := aFrame.Height;
            bmpInfo^.bmiHeader.biPlanes       := 1;
            bmpInfo^.bmiHeader.biBitCount     := aFrame.BitDepth;
            bmpInfo^.bmiHeader.biCompression  := BI_RGB;
            bmpInfo^.bmiHeader.biSizeImage    := 0;
            bmpInfo^.bmiHeader.biXPelsPerMeter := 0;
            bmpInfo^.bmiHeader.biYPelsPerMeter := 0;
            bmpInfo^.bmiHeader.biClrUsed      := 0;
            bmpInfo^.bmiHeader.biClrImportant := 0;
            for j := 0 to Trunc (Power (2, aFrame.BitDepth)) - 1 do
            begin
              bmpInfo^.bmiColors[j].rgbBlue    := j;
              bmpInfo^.bmiColors[j].rgbGreen   := j;
              bmpInfo^.bmiColors[j].rgbRed     := j;
              bmpInfo^.bmiColors[j].rgbReserved := 0;
            end;



            dc := CreateDC('DISPLAY', nil, nil, nil);
            hBmp := CreateDIBSection(dc, bmpInfo^, DIB_RGB_COLORS, aFrame.ImageBuffer, 0, 0);
//            hBmp := CreateDIBitmap(dc, bmpInfo^, DIB_RGB_COLORS, aFrame.ImageBuffer, 0, 0);
            DeleteDC(dc);
            FreeMem(bmpInfo, sizeof(bmpInfo.bmiHeader) + sizeof(RGBQUAD) * Trunc(Power (2, aFrame.BitDepth)));

            aBitmap := TBitmap.Create;
            aBitmap.Handle := hBmp;

            Image1.Picture.Bitmap := aBitmap;

Ganz herzlichen Dank an alle, die Hilfe beigesteuert haben

Jan

BoolString 19. Jul 2012 21:55

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Ich glaub ich mach an dieser Stelle mal einen Reset. Es sind in meinen letzten Beiträgen ein wenig zu viele Punkte parallel angesprochen gewesen. Deshalb jetzt mal die Konzentration auf die derzeit kritischsten Probleme; zumindest so wie sie mir erscheinen:


1.) Der gleiche, vorher gepostete Code funktioniert derzeit für eine ältere, rein monochrome Kamera (Prosilica GE2040). Ich versuche dabei das Bild über PvCaptureWaitForFrameDone aufzunehmen. Eine Callback-Funktion habe ich derzeit noch nicht implemetiert. Für die alte Kamera klappt dies und der Datenrecord weist die korrekte Anzahl an Bytes aus. Mit der Farbkamera (Prosilica GC2450C) funktioniert dies nicht. Es kommt immer die Rückmeldung, daß Daten fehlen. Hier habe ich auch mit anderen Aufnahmemodi und Veränderungen der TimeOuts keine Erfolge erzielt. Ich vermute inzwischen fast, daß diese die Farbkamera noch andere Parameter gesetzt benötigt. Kann dies sein; und wenn ja welche?


2.) Mit der (leider geborgten und demnächst rückgabefälligen) Monochrom-Kamera (GE2040) bekomme ich ja tatsächlich ein Bild. Allerdings bin ich hier nicht in der Lage ein DIB zu erstellen. Alle Versuche führen derzeit zu einer einfarbigen Fläche. Natürlich kann ich mit:
Delphi-Quellcode:
      aBitmap := TBitmap.Create;
            aBitmap.PixelFormat := pf8Bit;
            aBitmap.Height := aFrame.Height;
            aBitmap.Width := aFrame.Width;
            For y := 0 to aFrame.Height - 1 do
            Begin
            //  lPixel := aBitmap.Scanline[y];
              For x := 0 to aFrame.Width - 1 do
              Begin
                idx := aFrameBuffer [y*aFrame.Width + x];
                aBitmap.Canvas.Pixels[x, y] := idx + idx shl 8 + idx Shl 16;
              end;
            end;
die Daten in ein Bitmap kopieren. Allerdings ist dies relativ langsam (auch mit Scanline) und ich vermute, es hat durchaus seine Berechtigung, daß in den meisten Fällen auf HBITMAP und CreateDIB/StretchDIB verwiesen wird. Als Langzeitziel würde ich (zur Überprüfung einer Idee) gerne auf 5-6 Bilder die Sekunde kommen.
Ich scheine derzeit aber aus den mir vorliegenden Informationen persönlich nicht in der Lage zu sein, eine vernünftige Bitmap hinzubekommen. Mir erscheint es so, daß die Daten nicht richtig zusammengesammelt werden. Das Ergebnis ist immer eine einfarbige Fläche.


3.) Als Fortführung: Gibt es eine allgemeine Form, wie man mit dem Hintergrundwissen (Mono8, Bayer8, Bayer16, ...; BayerPattern; Bytes pro Frame) eine universelle Routine gestaltet, die ein darstellbares/speicherfähiges Bild erzeugt? Ich habe diesbezüglich schon viel ergoogelt, allerdings persönlich noch keine Implementation geschafft, die aus einem Pointer auf ein Array of Byte eine funktionale Lösung erzeugt (wobei die Daten dann ja noch abhängig vom Pixel-Format sein können.


Ich werde am Wochenende versuchen der Funktion PvCaptureQueueFrame eine Callback-Funktion zu verpassen. Laut SDK-Dokumentation würde diese Funktion dann in einem eigenen Thread ausgeführt, NACHDEM das Bild fertig aquiriert ist. Damit würde dann die bisher eingesetzte Funktion PvCaptureWaitForFrameDone obsolet werden. Vielleicht liegt hier auch ein Teil der Problematik.

Bis dahin würde ich es großartig finden, wenn mir jemand ein wenig auf die Sprünge helfen könnte...
Wie gesagt, ich würde die Routinen (wenn sie funktionieren) auch durchaus zur Verfügung stellen. Wenn man die Suchmaschinen bemüht stellt man schnell fest, daß es mehr Leute gibt die diese (durchaus guten) Kameras unter Delphi zum Laufen bekommen wollen...

Liebe Grüße aus dem Norden

Jan

brechi 19. Jul 2012 23:04

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Zu 1.) Leider kenn ich mich mit dieser Api nicht aus, aber eventuell musst di bei einer Farbkamera mehr speicher reservieren. Hast du denn mal ausgerechnet ob die Größe die du reservierst stimmt? Also bei 8Bit waeren das Breite*Hoehe, bei 16 (YUV) Breite*Hoehe*2 bei RGB Breite*Hoehe*3.

zu 2.) Es kommt ganz darauf an was du spaeter mit den Daten machen willst. Wenn du diese dann sowieso komprimierst (z.b. JPEG) dann lohnt sich da z.B: LibJpegTurbo zu verwenden, dafür brauchst du noch nicht einmal ein Bitmap und z.B. fuer OpenCV glaub ich auch.

Ansonsten ist Scanline schnell genug und auch nicht wirklich langsamer als es direkt ueber die API zu machen. Wichtig ist hier, dass du EINMAL das Bitmap erstellst und die Groesse + Pixelformat setzt und NICHT fuer jedes Bild. (Das gilt auch fuer den Speicher den du fuer das Bild reservierst).

Hier Beispiel fuer 8Bit:
Delphi-Quellcode:
  // on Create
  FBmp := TBitmap.Create;
  FBmp.Width := 640; // Einstellungen der kamera
  FBmp.Height := 480;
  FBmp.PixelFormat := pf8Bit;

  // on destroy
  FreeAndNil(FBmp)

  // Pro bild
var
  y: integer;
begin
  pmem := // dein datenpointer
  for y := 0 to FBmp.Height-1 do
    CopyMemory(FBmp.Scanline[y], Pointer(Integer(pmem) + FBmp.width * y), Fbmp.height);
 
  Form1.Canvas.Draw(0,0,FBmp);
zu 3.
Die UniversalAPI bietet dir z.B. Moeglichkeiten ein Bild immer in RGB auszulesen, egal welche Einstellung die Kamera hat. In den Manuals von AVT steht vieles beschrieben (z.B. Debayering etc)

BoolString 20. Jul 2012 22:19

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Hallo Brechi!

Ich hab nach deinem Posting gestern Nacht dann doch noch mal beim kanadischen (?; zumindest englischsprachiger Raum) Hersteller-Support nachgefragt. Wollte mir dein Paket mal anschauen. Heut Morgen hab ich dann auch eine Kopie der UniAPI erhalten. Macht auf jeden Fall einen deutlich ausgereifteren/umfangreicheren Eindruck als die reine PvAPI. Da ich selbst nach einem Kamera-Firmwareupdate keine großen Verbesserungen hatte, wollte ich es jetzt mal damit versuchen.

Hab mich nun eine Weile hingesetzt und lese mich in die Header und Beispiele ein. Ehrlich gesagt hats mich dann einen Moment geerdet. Die Headerfiles ergehen sich ja geradezu in Typdeklarationen. Hat mich einen Moment gekostet, um zu sehen, daß es in erster Linie wohl um Plattformkompatibilität geht. Die meisten Typen kann man scheinbar gut auf Standards rückführen...

Kann es sein, daß die Kameras nur über ihr Handle identifiziert werden? Bislang hab ich noch keine entsprechende Kamera-Liste entdeckt, wie bei der PvAPI.

Einige Funktionen hab ich schon importiert und die Typen aus den endlosen Querreferenzen auf Standards zurückgeführt. Muss jetzt nur bei dem InfoString noch mal bei.
Delphi-Quellcode:
Function UCC_Init: Int64; stdcall; external 'UniControl.DLL';
Function UCC_Release: Int64; stdcall; external 'UniControl.DLL';
Function UCC_GetCameras ( Var pnSize : UInt32; Out vecIds : UInt32) : Int64; stdcall; external 'UniControl.DLL';
Function UCC_OpenCamera (CamId : UInt32; lSpeedLimit : Int32) : Int64; stdcall; external 'UniControl.DLL';
Function UCC_CloseCamera (CamId : UInt32) : Int64; stdcall; external 'UniControl.DLL';
Function UCC_GetCameraInfoString (CamId : UInt32; nId : UInt32; Out pszInfoString : PAnsiChar; Var pLength : UInt32) : Int64; stdcall; external 'UniControl.DLL';
Offensichtlich bewege ich mich schon mal in die Nähe der Kamera. Aber da geht es Morgen weiter. Den Kindern gehts grad nicht so gut; sind kurze Nächte...

Delphi-Quellcode:

procedure TForm1.Button1Click(Sender: TObject);
Var CamID       : Uint32;
    aCount      : Uint32;
    aVendor     : PAnsiChar;
    aModel      : PAnsiChar;
    aModelLength : Uint32;

begin
  aCount  := 64;
  aVendor := ' ';
  aModel  := ' ';
 
  Memo1.Lines.Add ('Initialise           : ' + IntToStr(UCC_Init));
  Memo1.Lines.Add ('');

  Memo1.Lines.Add ('Get cameras          : ' + IntToStr (UCC_GetCameras (aCount, CamID)));
  Memo1.Lines.Add ('Camera counts        : ' + IntToStr (aCount));
  Memo1.Lines.Add ('CamID                : ' + IntToStr (CamID));
  Memo1.Lines.Add ('');

  Memo1.Lines.Add ('Camera open          : ' + IntToStr (UCC_OpenCamera (CamID, -1)));
  aModelLength := SizeOf (aModel);
  UCC_GetCameraInfoString (CamID, 0, aModel, aModelLength);
  Memo1.Lines.Add ('Model                : ' + aModel);

  Memo1.Lines.Add ('Camera close         : ' + IntToStr (UCC_CloseCamera (CamID)));

  Memo1.Lines.Add ('Uninitialise         : ' + IntToStr(UCC_Release));
  Memo1.Lines.Add ('');

end;
Werde dies Wochenende sicherlich noch mal auf dich zurückkommen. Ich hab schon ein paar Funktionen des UniAPI entdeckt, die sich vielversprechend anhören, aber einige Fallstricke bieten könnten.

Jan

brechi 20. Jul 2012 23:46

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Hi, also bei der kann ich dir wirklich mehr weiterhelfen :)

Delphi-Quellcode:
UNI_RETURN_TYPE = Cardinal;

Function UCC_GetCameras ( Var pnSize : UInt32; VecIds : PUInt32) : UNI_RETURN_TYPE; stdcall;

// mit
var
  Cameras: array of Uint32;
  CameraCount: Uint32;

CameraCount := 64;
SetLength(Cameras, CameraCount);
if GetCameras(CameraCount, @Cameras[0]) = S_OK then begin
  SetLength(Cameras, CameraCount);
  for i := Low(cameras) to High(cameras) do
    memo.lines.add(inttostr(cameras[i])); // cameraID
end;
Die Kameras werden ueber die ID angesprochen (diese siehst du auch im UniCamViewer). Eine Liste der verfuegbaren Kameras erhaelst du wie im SourceCode oben.

Bei UCC_GetCameraInfoString musst du dir vorher den Speicher reservieren (Wie bei den WinAPIs) [Rueckgabe ist cardinal, deklarier dir das besser wie oben als UNI_RETURN_TYPE):

Delphi-Quellcode:

  const
     E_CAMINFO_MODEL = 0;
     E_CAMINFO_VENDOR = 1; //.....
 
  Function UCC_GetCameraInfoString (CamId : UInt32; nId : UInt32; pszInfoString : PAnsiChar; Var pLength : UInt32) : Cardinal;

  if UCC_GetCameraInfoString(camId, E_CAMINFO_MODEL, nil, len) = S_OK then begin // laenge ermitteln
    SetLength(text, len);
    if UCC_GetCameraInfoString(camId, E_CAMINFO_MODEL, PChar(text), len) = S_OK then begin // auslesen
      memo1.lines.add(text);
    end;
  end;

BoolString 23. Jul 2012 21:10

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Bin am Wochenende natürlich nicht so wirklich weiter gekommen.

Ich bekomme inzwischen schon mal die maximalen Auflösungen der Kamera, die BitTiefe und habe inzwischen die kompletten E_UNI_CAMERA_INFO Block mit den E_CAMINFO_XXX Deklarationen als Konstanten übersetzt. Macht es Sinn die als reine Konstanten zu übersetzen, oder sollte man besser die enum Struktur übernehmen?

Wie hast du denn die Variable text in deinem Beispiel für UCC_GetCameraInfoString deklariert? Die Funktion wirft bei mir immer einen von S_OK verschiedenen Wert.

Die Funktion

Delphi-Quellcode:
 
Function UCC_PrepareFreeGrab (CamId :UInt32;Var pMode, pColorFormatId, pWidth, pHeight, pBufferCount, pXOffset, pYOffset, pBusLoad : UInt32) : UNI_RETURN_TYPE; stdcall; external 'UniControl.DLL';

Var aCamMode    : UInt32;
    aColFormat  : UInt32;
    aBufferCount : UInt32;
    aXOffset    : UInt32;
    aYOffset    : UInt32;
    aBusLoad    : UInt32;
    aResult     : Cardinal;

  aColFormat  := E_CC_YUV422;
  aCamMode    := 0;
  aBufferCount := 0;
  aXOffset    := 0;
  aYOffset    := 0;
  aBusLoad    := 0;
  aResult := UCC_PrepareFreeGrab (CameraIDs[0], aCamMode, aColFormat, aCamMaxWidth, aCamMaxHeight, aBufferCount, aXOffset, aYOffset, aBusLoad);
  Memo1.Lines.Add ('Camera prepare free grab: ' + IntToStr (aResult));
wirft auf jeden Fall schon mal ein S_OK zurück. Aber diese Bilder benötigen dann ja vermutlich ein Debayering. an dieser Stelle müsste ich dann die UniTransform Funktionen einbeziehen, oder?

Im Manual bin ich jetzt auf die Funktion UCC_GrabBitmapImage gestoßen. Kann man damit die einzelne Bitmaps gewinnen, die ich dann wie gewohnt verarbeiten kann? Soweit wie ich es jetzt nachvollziehen kann, scheint dies so zu sein. Ich schau mir gerade die zugehörigen S_SIS_DATA Deklaration an. Das Union und die aufeinanderbauenden Records versuche ich so zu übersetzen. Ist das in der Theorie zumindest richtig?
Delphi-Quellcode:
  S_SISEnable : Packed Record of
                  Case m_Enable : UInt32 of
                    1 : Packed Record of
                            m_CycleCounter     : UInt32 = 1;   //!< inq cycle counter
                            m_FrameCounter     : UInt32 = 1;   //!< inq frame count since last reset
                            m_TriggerCounter   : UInt32 = 1;   //!< inq triggers received by the camera
                            m_AOILeft          : UInt32 = 1;   //!< inq left coordinate of the cameras AOI
                            m_AOITop           : UInt32 = 1;   //!< inq top coordinate of the cameras AOI
                            m_AOIWidth         : UInt32 = 1;   //!< inq width of the AOI
                            m_AOIHeight        : UInt32 = 1;   //!< inq height of the AOI
                            m_Shutter          : UInt32 = 1;   //!< inq camera shutter for the image
                            m_Gain             : UInt32 = 1;   //!< inq camera gain for the image
                            Reserved0           : UInt32 = 1;
                            m_OutputState      : UInt32 = 1;   //!< inq output pin states
                            m_InputState       : UInt32 = 1;   //!< inq input pin states
                            m_SequenceIndex    : UInt32 = 1;   //!< inq position in sequence
                            Reserved2a         : UInt32 = 1;
                            m_ColorCoding      : UInt32 = 1;   //!< inq IIDC color coding
                            Reserved2b         : UInt32 = 1;
                            m_SerialNumber     : UInt32 = 1;   //!< inq serial number of the camera
                            m_UserValue        : UInt32 = 1;   //!< inq user defined value
                            Reserved2           : UInt32 = 13;
                            m_Valid            : UInt32 = 1;   //!< Data in m_Enable is valid
                        end;
                    2 : m_Data               : UInt32;                //!< m_Enable as UINT32
                  end;

/** SIS data structure*/

  S_SIS_DATA : Packed Record of
                  m_CycleCounter  : UInt32;               //!< bus cycle count
                  m_FrameCounter  : UInt32;               //!< frame count since last reset
                  m_TriggerCounter : UInt32;               //!< from camera received triggers
                  m_AOILeft       : UInt16;               //!< left coordinate of the AOI begin
                  m_AOITop        : UInt16;               //!< top coordinate of the AOI begin
                  m_AOIWidth      : UInt16;               //!< width of the AOI
                  m_AOIHeight     : UInt16;               //!< height of the AOI
                  m_Shutter       : UInt32;               //!< camera shutter for the image
                  m_Gain          : UInt16;               //!< camera gain for the image
                  m_Reserved0      : UInt16;               //!< reserved for future use
                  m_OutputState   : Array [0..3] of UInt8; //!< state of the output pins
                  m_InputState    : Array [0..1] of UInt8; //!< state of the input pins
                  m_Reservec1      : Array [0..1] of UInt8; //!< reserved for future use
                  m_SequenceIndex : UInt8;                //!< position in the sequence
                  m_Reserved2a    : UInt8;                //!< reserved for future use
                  m_ColorCoding   : UInt8;                //!< IIDC color coding for the transport format
                  m_Reserved2b    : UInt8;                //!< reserved for future use
                  m_SerialNumber  : UInt32;               //!< camera serial number
                  m_UserValue     : UInt32;               //!< user defined value
                  m_SISEnable     : S_SIS_ENABLE;         //!< state inq struct
                end;
Und welchen Pointer auf das Bitmap möchte UCC_GrabBitmapImage denn wohl haben? Auf das @Bitmap, Handles oder irgendwelche Datenbereiche?

Nur mal für mich... wie weit bin ich denn wohl noch von einem ersten, (Prosilica)kameraunabhängigen Bild entfernt?

Liebe Grüße

Jan

brechi 25. Jul 2012 19:55

AW: Ansprechen einer GigE Kamera (Prosilica GC2450C)
 
Bei S_SISEnable hab ich ich nur einen Cardinal verwendet und mir Funktionen zum Bitshiften geschrieben.
S_SIS_DATA soltle so richtig uebersetzt sein.

Schau dir mal UCC_GrabBitmap24Image das liefert dier ein Array mit RGB Werten, die Daten kannst dann mit Scanline vom Bitmap relativ einfach anzeigen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:01 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz