Hallo Leute!
Ich habe eine Kamera der Firma Prosilica vor mir liegen, welche einen Ethernet Anschluss besitzt!
Was ich machen will, ist eine einfache C#-Anwendung die mir direkt in einer PictureBox oder einem Sonstigen Steuerelement(weis nicht was hier am besten ist, dachte aber mal PictureBox) die aktuellen Bilder die die Kamera erfasst ausgibt...
(z.B.: 5 Bilder/Sekunde... ist aber jetzt noch nicht weiter wichtig... ist ja später einstellbar)
Ich habe da einmal selbst ein wenig rum gebastelt, nur was ich habe ist nicht optimal!
Von dem Bild wird jedes einzelne Pixel in ein byte-Array(Buffer) gespeichert(1024x768 Werte) und anschließend wird in der PictureBox jedes einzelne Pixel gezeichnet und ausgegeben...
Natürlich wie man daran erkennen kann dauert dies schon einige Sekunden, bzw. einfach viiiel zu lange bis das Bild dann vorhanden ist!
Daher möchte ich gerne wissen ob es in C# eine geeignetere Funktion dafür gibt?
Anbei der gesamte Code bzw. weiter unten die Funktion die das Bild erstellt:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using PvNET;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing.Imaging;
namespace Kamera_Tests
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//////////////////////////////////////////////////////
//Kameradaten erfassen Anfang
//
//Bei Klick auf den Button werden Details ausgegeben
//////////////////////////////////////////////////////
private void btnTest_Click(object sender, EventArgs e)
{
tErr err = 0;
if ((err = Pv.Initialize()) == 0)
{
UInt32 Major, Minor, Count, Handle, UID = 14;
tCameraInfo Info = new tCameraInfo();
tCameraInfo[] List = new tCameraInfo[10];
tIpSettings Settings = new tIpSettings();
tIpSettings[] IPS = new tIpSettings[10];
Major = 0;
Minor = 0;
Count = 0;
Pv.Version(ref Major, ref Minor);
Ausgabe("using API");
Ausgabe("Major: ", Major.ToString());
Ausgabe("Minor: ", Minor.ToString());
Thread.Sleep(1500); //Zeit zum Suchen geben
Ausgabe("Anzahl der Cams: ", Pv.CameraCount().ToString()); //Zeigt die Anzahl der angeschlossenen Cams an
if ((Count = Pv.CameraList(List, 10, ref Count)) != 0)
{
for (uint i = 0; i < Count; i++)
{
//Datenausgabe
Ausgabe("UniqueID: " + List[i].UniqueId.ToString());
Ausgabe("CAM-Name: " + List[i].DisplayName.ToString());
Ausgabe("InterfaceID: ", List[i].InterfaceId.ToString());
Ausgabe("PartVersion: ", List[i].PartVersion.ToString());
Ausgabe("Serialstring: ", List[i].SerialString.ToString());
Ausgabe("InterfaceType: ", List[i].InterfaceType.ToString());
Ausgabe("PartNumber: ", List[i].PartNumber.ToString());
Ausgabe("PermittedAccess: ", List[i].PermittedAccess.ToString());
}
}
else
Ausgabe("Keine Daten - no cam");
}
else
{
Ausgabe("failed to initialize the API : ");
Ausgabe(err.ToString());
}
}
private void Ausgabe(string bezeichnung, string ausgabewert)
{
lbxAusgabe.Items.Add(bezeichnung + ausgabewert);
}
private void Ausgabe(string bezeichnung)
{
lbxAusgabe.Items.Add(bezeichnung);
}
private void Ausgabe(string as1, string as2, string as3)
{
lbxAusgabe.Items.Add(as1 + as2 + as3);
}
/////////////////////////////////////////////////////
//Kameradaten erfassen Ende //
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//Bild erfassen Anfange //
/////////////////////////////////////////////////////
static void LinkCB(IntPtr Context, tInterface Interface, tLinkEvent Event, UInt32 UniqueId)
{
}
static void FrameCB(IntPtr pFrame)
{
// marshal the pointer into a frame structure
tFrame Frame = (tFrame)Marshal.PtrToStructure(pFrame, typeof(tFrame));
}
void CaptureFrame()
{
tErr err = 0;
// Initialisieren
if ((err = Pv.Initialize()) == 0)
{
UInt32 Major, Minor, Count, Handle, UID = 40044;
tLinkCallback lLinkCB = new tLinkCallback(LinkCB);
tFrameCallback lFrameCB = new tFrameCallback(FrameCB);
tCameraInfo Info = new tCameraInfo();
tCameraInfo[] List = new tCameraInfo[10];
tIpSettings Settings = new tIpSettings();
Major = 0;
Minor = 0;
Count = 0;
//Version lesen
Pv.Version(ref Major, ref Minor);
// Warten
Thread.Sleep(1500);
// Lesen der Information
if (Pv.CameraInfo(UID, ref Info) == tErr.eErrSuccess && Pv.CameraIpSettingsGet(UID, ref Settings) == tErr.eErrSuccess)
{
// open the camera (in master mode)
if (Pv.CameraOpen(UID, tAccessFlags.eAccessMaster, out Handle) == 0)
{
tAttributeInfo Detail = new tAttributeInfo();
IntPtr Strings = IntPtr.Zero;
UInt32 FrameSize = 0;
if (Pv.AttrUint32Get(Handle, "TotalBytesPerFrame", ref FrameSize) == 0)
{
tFrame Frame = new tFrame();
byte[] Buffer = new byte[FrameSize];
GCHandle pBuffer = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
Pv.AttrUint32Set(UID, "PacketSize", 1500);
// Framefelder setzen
Frame.Context.Field0 = new IntPtr(Handle); // Handle zum Öffnen der Kamera
Frame.ImageBuffer = pBuffer.AddrOfPinnedObject(); // @ of the pinned buffer
Frame.ImageBufferSize = FrameSize; // Buffergröße
// Start des CaptureModes
if (Pv.CaptureStart(Handle) == 0)
{
// set the camera in continuous acquisition mode
if (Pv.AttrEnumSet(Handle, "FrameStartTriggerMode", "FixedRate") == 0)
{
// and set the acquisition mode into continuous
if (Pv.CommandRun(Handle, "AcquisitionStart") != 0)
{
// if that fail, we reset the camera to non capture mode
Pv.CaptureEnd(Handle);
}
else
{
UInt32 Completed = 0;
UInt32 Received = 0;
// pin down a copy of the frame structure
GCHandle pFrame = GCHandle.Alloc(Frame, GCHandleType.Pinned);
// .BMP ERSTELLEN
if (Pv.CaptureQueueFrame(Handle, pFrame.AddrOfPinnedObject(), lFrameCB) == 0)
{
Bitmap bmp = new Bitmap(1024, 768);
int color;
for (int y = 0; y < 768; y++)
{
for (int x = 0; x < 1024; x++)
{
color = Buffer[y * 1024 + x];
bmp.SetPixel(x, y, Color.FromArgb(color, color, color));
}
}
picFrame.Image = bmp; //Ausgabe in der PictureBox
}
Pv.CommandRun(Handle, "AcquisitionStop");
Pv.CaptureEnd(Handle);
Pv.CaptureQueueClear(Handle); //Warteschlange löschen
// Release the Frame
pFrame.Free();
}
}
else
MessageBox.Show("failed to set trigger mode");
}
else
MessageBox.Show("failed to start capture");
// Release the Buffer
pBuffer.Free();
}
if (Pv.CameraClose(Handle) != 0)
MessageBox.Show("failed to close the camera");
}
else
MessageBox.Show("failed to open the camera");
}
//CB löschen
if (Pv.LinkCallbackUnregister(lLinkCB, tLinkEvent.eLinkAdd) != 0)
MessageBox.Show("failed to unregister CB");
if (Pv.LinkCallbackUnregister(lLinkCB, tLinkEvent.eLinkRemove) != 0)
MessageBox.Show("failed to unregister CB");
Pv.UnInitialize();
}
else
{
MessageBox.Show("failed to initialize the API : ");
}
Thread.Sleep(2000);
}
private void picFrame_Click(object sender, EventArgs e)
{
CaptureFrame();
}
}
}
Hier die kleine selbstgebastelte Ausgabefunktion:
// .BMP ERSTELLEN
if (Pv.CaptureQueueFrame(Handle, pFrame.AddrOfPinnedObject(), lFrameCB) == 0)
{
Bitmap bmp = new Bitmap(1024, 768);
int color;
for (int y = 0; y < 768; y++)
{
for (int x = 0; x < 1024; x++)
{
color = Buffer[y * 1024 + x];
bmp.SetPixel(x, y, Color.FromArgb(color, color, color));
}
}
picFrame.Image = bmp; //Ausgabe in der PictureBox
}
Danke für jede hilfreiche Antwort!!!
Vielleicht solltest du zuerst noch den Code etwas leserlicher gestalten!
Einfach nicht so viel einrücken,dann müsste es besser sein...
www.mkellenberger.ch Was ich täglich (neu) entdecke...
Besser so?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using PvNET;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing.Imaging;
namespace Kamera_Tests
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//////////////////////////////////////////////////////
//Kameradaten erfassen Anfang //
// //
//Bei Klick auf den Button werden Details ausgegeben//
//////////////////////////////////////////////////////
private void btnTest_Click(object sender, EventArgs e)
{
tErr err = 0;
if ((err = Pv.Initialize()) == 0)
{
UInt32 Major, Minor, Count, Handle, UID = 14;
tCameraInfo Info = new tCameraInfo();
tCameraInfo[] List = new tCameraInfo[10];
tIpSettings Settings = new tIpSettings();
tIpSettings[] IPS = new tIpSettings[10];
Major = 0;
Minor = 0;
Count = 0;
Pv.Version(ref Major, ref Minor);
Ausgabe("using API");
Ausgabe("Major: ", Major.ToString());
Ausgabe("Minor: ", Minor.ToString());
Thread.Sleep(1500); //Zeit zum Suchen geben
Ausgabe("Anzahl der Cams: ", Pv.CameraCount().ToString()); //Zeigt die Anzahl der angeschlossenen Cams an
if ((Count = Pv.CameraList(List, 10, ref Count)) != 0)
{
for (uint i = 0; i < Count; i++)
{
//Datenausgabe
Ausgabe("UniqueID: " + List[i].UniqueId.ToString());
Ausgabe("CAM-Name: " + List[i].DisplayName.ToString());
Ausgabe("InterfaceID: ", List[i].InterfaceId.ToString());
Ausgabe("PartVersion: ", List[i].PartVersion.ToString());
Ausgabe("Serialstring: ", List[i].SerialString.ToString());
Ausgabe("InterfaceType: ", List[i].InterfaceType.ToString());
Ausgabe("PartNumber: ", List[i].PartNumber.ToString());
Ausgabe("PermittedAccess: ", List[i].PermittedAccess.ToString());
}
}
else
Ausgabe("Keine Daten - no cam");
}
else
{
Ausgabe("failed to initialize the API : ");
Ausgabe(err.ToString());
}
}
private void Ausgabe(string bezeichnung, string ausgabewert)
{
lbxAusgabe.Items.Add(bezeichnung + ausgabewert);
}
private void Ausgabe(string bezeichnung)
{
lbxAusgabe.Items.Add(bezeichnung);
}
private void Ausgabe(string as1, string as2, string as3)
{
lbxAusgabe.Items.Add(as1 + as2 + as3);
}
/////////////////////////////////////////////////////
//Kameradaten erfassen Ende //
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//Bild erfassen Anfange //
/////////////////////////////////////////////////////
static void LinkCB(IntPtr Context, tInterface Interface, tLinkEvent Event, UInt32 UniqueId)
{
}
static void FrameCB(IntPtr pFrame)
{
// marshal the pointer into a frame structure
tFrame Frame = (tFrame)Marshal.PtrToStructure(pFrame, typeof(tFrame));
}
void CaptureFrame()
{
tErr err = 0;
// Initialisieren
if ((err = Pv.Initialize()) == 0)
{
UInt32 Major, Minor, Count, Handle, UID = 40044;
tLinkCallback lLinkCB = new tLinkCallback(LinkCB);
tFrameCallback lFrameCB = new tFrameCallback(FrameCB);
tCameraInfo Info = new tCameraInfo();
tCameraInfo[] List = new tCameraInfo[10];
tIpSettings Settings = new tIpSettings();
Major = 0;
Minor = 0;
Count = 0;
//Version lesen
Pv.Version(ref Major, ref Minor);
// Warten
Thread.Sleep(1500);
// Lesen der Information
if (Pv.CameraInfo(UID, ref Info) == tErr.eErrSuccess && Pv.CameraIpSettingsGet(UID, ref Settings) == tErr.eErrSuccess)
{
// open the camera (in master mode)
if (Pv.CameraOpen(UID, tAccessFlags.eAccessMaster, out Handle) == 0)
{
tAttributeInfo Detail = new tAttributeInfo();
IntPtr Strings = IntPtr.Zero;
UInt32 FrameSize = 0;
if (Pv.AttrUint32Get(Handle, "TotalBytesPerFrame", ref FrameSize) == 0)
{
tFrame Frame = new tFrame();
byte[] Buffer = new byte[FrameSize];
GCHandle pBuffer = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
Pv.AttrUint32Set(UID, "PacketSize", 1500);
// Framefelder setzen
Frame.Context.Field0 = new IntPtr(Handle); // Handle zum Öffnen der Kamera
Frame.ImageBuffer = pBuffer.AddrOfPinnedObject(); // @ of the pinned buffer
Frame.ImageBufferSize = FrameSize; // Buffergröße
// Start des CaptureModes
if (Pv.CaptureStart(Handle) == 0)
{
// set the camera in continuous acquisition mode
if (Pv.AttrEnumSet(Handle, "FrameStartTriggerMode", "FixedRate") == 0)
{
// and set the acquisition mode into continuous
if (Pv.CommandRun(Handle, "AcquisitionStart") != 0)
{
// if that fail, we reset the camera to non capture mode
Pv.CaptureEnd(Handle);
}
else
{
UInt32 Completed = 0;
UInt32 Received = 0;
// pin down a copy of the frame structure
GCHandle pFrame = GCHandle.Alloc(Frame, GCHandleType.Pinned);
// .BMP ERSTELLEN
if (Pv.CaptureQueueFrame(Handle, pFrame.AddrOfPinnedObject(), lFrameCB) == 0)
{
Bitmap bmp = new Bitmap(1024, 768);
int color;
for (int y = 0; y < 768; y++)
{
for (int x = 0; x < 1024; x++)
{
color = Buffer[y * 1024 + x];
bmp.SetPixel(x, y, Color.FromArgb(color, color, color));
}
}
picFrame.Image = bmp; //Ausgabe in der PictureBox
}
Pv.CommandRun(Handle, "AcquisitionStop");
Pv.CaptureEnd(Handle);
Pv.CaptureQueueClear(Handle); //Warteschlange löschen
// Release the Frame
pFrame.Free();
}
}
else
MessageBox.Show("failed to set trigger mode");
}
else
MessageBox.Show("failed to start capture");
// Release the Buffer
pBuffer.Free();
}
if (Pv.CameraClose(Handle) != 0)
MessageBox.Show("failed to close the camera");
}
else
MessageBox.Show("failed to open the camera");
}
//CB löschen
if (Pv.LinkCallbackUnregister(lLinkCB, tLinkEvent.eLinkAdd) != 0)
MessageBox.Show("failed to unregister CB");
if (Pv.LinkCallbackUnregister(lLinkCB, tLinkEvent.eLinkRemove) != 0)
MessageBox.Show("failed to unregister CB");
Pv.UnInitialize();
}
else
{
MessageBox.Show("failed to initialize the API : ");
}
Thread.Sleep(2000);
}
private void picFrame_Click(object sender, EventArgs e)
{
CaptureFrame();
}
}
}
if (Pv.CaptureQueueFrame(Handle, pFrame.AddrOfPinnedObject(), lFrameCB) == 0)
{
Bitmap bmp = new Bitmap(1024, 768);
int color;
for (int y = 0; y < 768; y++)
{
for (int x = 0; x < 1024; x++)
{
color = Buffer[y * 1024 + x];
bmp.SetPixel(x, y, Color.FromArgb(color, color, color));
}
}
picFrame.Image = bmp; //Ausgabe in der PictureBox
}
Hallo suam111,
Besser so?
ich glaube, es war nicht nur Anzahl der Zeichen, um die pro Einrückungsebene eingerückt wird, gemeint, sondern eher die Anzahl der Einrückungsebenen. Viele Einrückungsebenen machen den Code schwerer zu verstehen und somit anfälliger für Fehler.
Daher möchte ich gerne wissen ob es in C# eine geeignetere Funktion dafür gibt? GetPixel und SetPixel um Längen geschlagen. 800 mal schneller
herbivore
Original von herbivore
Habe das jetzt eingebaut...
tolle Sache hat es weit beschleunigt!
Doch das Problem ist jetzt, dass der ganz "Stream" noch ziemlich ruckelt...
Jedes Bild dauert beim erstellen ca. 0,3-0,6 Sekunden!
(Größe: 640x480)
Ich habe folgendes gebastelt...
Bei klick auf einen Button sollten 10 Bilder geschossen werden dies wird folgender Weise realisiert:
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
CaptureFrame();
}
}
Danach durchläuft es die Funktion:
Hier der wichtigste Ausschnitt der Funktion
Bitmap test = new Bitmap(640, 480); // Bitmap neu laden
FastBitmap rob = new FastBitmap(test); // FastBitmap davon erzeugen
// leere Bitmap gleicher Größe erstellen
Bitmap test2 = new Bitmap(640, 480, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
FastBitmap rob2 = new FastBitmap(test2); // FastBitmap davon erzeugen
// test2 = new Bitmap(test.Width, test.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
int color;
//Zeit bestimmen,die das Bildumwandeln benötigt
DateTime now1 = DateTime.Now;
for (int x = 0; x < rob.Width; x++)
for (int y = 0; y < rob.Height; y++)
{
color = Buffer[y * 640 + x];
rob2.SetPixel(x, y, Color.FromArgb(color, color, color));
}
picFrame.Image = rob2.ToBitmap();// kommt das Richtige Bild heraus?
Wo oder/und wie kann ich noch mehr Zeit einsparen, bzw einen Echtzeit-Stream erzeugen?
Der Buffer wird von der Kamera geliefert, in dem Buffer stehen 640x480 Color-Werte mit denen dann jedes einzelne Bild gezeichnet wird
Bin über jede Hilfe dankbar!!!!
Du könntest die Qualität einstellbar machen und dann Interlacing benutzen.
Qualität sollte gleich bleiben...
jetzt ist es ja so, dass jedes mal bei klick 10mal die funktion durchlaufen wird...
das heisst, der Buffer wird immer weider neu gefüllt das dauert ja schon ne weile meiner meinung nach...
könnte man da nicht einsparen indem man irgendwie sagt, dass nur die Pixel die einen neuen wert besitzen überschrieben werden, oder macht das keinen sinn?
Das wäre dann evtl. sowas in der Richtung:
http://www.codeproject.com/cs/media/Motion_Detection.asp