C# 在Picturebox上显示从相机检索的位图的实验
在我的代码中,我使用指向非托管对象的指针从相机检索帧,对其进行一些计算,然后将其显示在picturebox控件上。C# 在Picturebox上显示从相机检索的位图的实验,c#,opencv,bitmap,camera,picturebox,C#,Opencv,Bitmap,Camera,Picturebox,在我的代码中,我使用指向非托管对象的指针从相机检索帧,对其进行一些计算,然后将其显示在picturebox控件上。 在我进一步介绍这个应用程序的所有细节之前,我想确保这个过程的基本代码是好的。 我特别想: -尽量减少执行时间,避免不必要的操作,例如 复制的图像比需要的多。我只想保留必要的东西 操作 -了解每帧计算过程中的延迟是否会对图像的显示方式产生不利影响(即,如果未按我的预期打印),或者跳过某些图像 -防止更严重的错误,例如由于内存或线程管理或图像显示引起的错误。 为此,我设置了一些实验性的
在我进一步介绍这个应用程序的所有细节之前,我想确保这个过程的基本代码是好的。 我特别想:
-尽量减少执行时间,避免不必要的操作,例如 复制的图像比需要的多。我只想保留必要的东西 操作
-了解每帧计算过程中的延迟是否会对图像的显示方式产生不利影响(即,如果未按我的预期打印),或者跳过某些图像
-防止更严重的错误,例如由于内存或线程管理或图像显示引起的错误。
为此,我设置了一些实验性的代码行(如下),但我无法解释我发现的结果。如果你有OpenCv的可执行文件,你可以自己试试
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
public partial class FormX : Form
{
private delegate void setImageCallback();
Bitmap _bmp;
Bitmap _bmp_draw;
bool _exit;
double _x;
IntPtr _ImgBuffer;
bool buffercopy;
bool copyBitmap;
bool refresh;
public FormX()
{
InitializeComponent();
_x = 10.1;
// set experimemental parameters
buffercopy = false;
copyBitmap = false;
refresh = true;
}
private void buttonStart_Click(object sender, EventArgs e)
{
Thread camThread = new Thread(new ThreadStart(Cycle));
camThread.Start();
}
private void buttonStop_Click(object sender, EventArgs e)
{
_exit = true;
}
private void Cycle()
{
_ImgBuffer = IntPtr.Zero;
_exit = false;
IntPtr vcap = cvCreateCameraCapture(0);
while (!_exit)
{
IntPtr frame = cvQueryFrame(vcap);
if (buffercopy)
{
UnmanageCopy(frame);
_bmp = SharedBitmap(_ImgBuffer);
}
else
{ _bmp = SharedBitmap(frame); }
// make calculations
int N = 1000000; /*1000000*/
for (int i = 0; i < N; i++)
_x = Math.Sin(0.999999 * _x);
ShowFrame();
}
cvReleaseImage(ref _ImgBuffer);
cvReleaseCapture(ref vcap);
}
private void ShowFrame()
{
if (pbCam.InvokeRequired)
{
this.Invoke(new setImageCallback(ShowFrame));
}
else
{
Pen RectangleDtPen = new Pen(Color.Azure, 3);
if (copyBitmap)
{
if (_bmp_draw != null) _bmp_draw.Dispose();
//_bmp_draw = new Bitmap(_bmp); // deep copy
_bmp_draw = _bmp.Clone(new Rectangle(0, 0, _bmp.Width, _bmp.Height), _bmp.PixelFormat);
}
else
{
_bmp_draw = _bmp; // add reference to the same object
}
Graphics g = Graphics.FromImage(_bmp_draw);
String drawString = _x.ToString();
Font drawFont = new Font("Arial", 56);
SolidBrush drawBrush = new SolidBrush(Color.Red);
PointF drawPoint = new PointF(10.0F, 10.0F);
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
drawPoint = new PointF(10.0F, 300.0F);
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
g.DrawRectangle(RectangleDtPen, 12, 12, 200, 400);
g.Dispose();
pbCam.Image = _bmp_draw;
if (refresh) pbCam.Refresh();
}
}
public void UnmanageCopy(IntPtr f)
{
if (_ImgBuffer == IntPtr.Zero)
_ImgBuffer = cvCloneImage(f);
else
cvCopy(f, _ImgBuffer, IntPtr.Zero);
}
// only works with 3 channel images from camera! (to keep code minimal)
public Bitmap SharedBitmap(IntPtr ipl)
{
// gets unmanaged data from pointer to IplImage:
IntPtr scan0;
int step;
Size size;
OpenCvCall.cvGetRawData(ipl, out scan0, out step, out size);
return new Bitmap(size.Width, size.Height, step, PixelFormat.Format24bppRgb, scan0);
}
// based on older version of OpenCv. Change dll name if different
[DllImport( "opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvCreateCameraCapture(int index);
[DllImport("opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvReleaseCapture(ref IntPtr capture);
[DllImport("opencv_highgui246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvQueryFrame(IntPtr capture);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvGetRawData(IntPtr arr, out IntPtr data, out int step, out Size roiSize);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvCopy(IntPtr src, IntPtr dst, IntPtr mask);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cvCloneImage(IntPtr src);
[DllImport("opencv_core246", CallingConvention = CallingConvention.Cdecl)]
public static extern void cvReleaseImage(ref IntPtr image);
}
使用系统;
使用系统图;
使用系统、绘图、成像;
使用System.Windows.Forms;
使用System.Runtime.InteropServices;
使用系统线程;
公共部分类FormX:Form
{
私有委托void setImageCallback();
位图bmp;
位图\u bmp\u绘制;
布尔乌出口;
双x;
IntPtr_ImgBuffer;
布尔缓冲拷贝;
bool复制位图;
布尔刷新;
公共表格x(
{
初始化组件();
_x=10.1;
//设置实验参数
buffercopy=false;
copyBitmap=false;
刷新=真;
}
私有无效按钮开始单击(对象发送者,事件参数e)
{
螺纹凸轮螺纹=新螺纹(新螺纹开始(循环));
camThread.Start();
}
私有无效按钮停止单击(对象发送者,事件参数e)
{
_退出=真;
}
私有无效循环()
{
_ImgBuffer=IntPtr.Zero;
_退出=假;
IntPtr vcap=cvCreateCameraCapture(0);
while(!\u退出)
{
IntPtr帧=cvQueryFrame(vcap);
如果(缓存副本)
{
非托管拷贝(帧);
_bmp=共享的位图(_ImgBuffer);
}
其他的
{{u bmp=SharedBitmap(框架);}
//算计
整数N=1000000;/*1000000*/
对于(int i=0;i
结果[双核2 Duo T6600 2.2 GHz]:
A。buffercopy=false;copyBitmap=false;刷新=错误这是更简单的配置。依次检索每一帧,进行操作(实际上它们基于同一帧,这里只是计算),然后将计算结果打印在图像顶部,最后显示在图片盒上。
OpenCv文档说明: OpenCV 1.x函数cvRetrieveFrame和cv.RetrieveFrame返回图像 存储在视频捕获结构中。这是不允许的 修改或释放图像!可以使用复制帧 cvCloneImage()然后对副本执行任何操作 但这并不妨碍我们做实验。
如果计算结果不正确