如何使用 directshow.net 扫描 ISampleGrabber 的每一帧
本文关键字:一帧 directshow 何使用 net 扫描 ISampleGrabber | 更新日期: 2023-09-27 18:36:44
>我有一个程序,它当前显示USB网络摄像头的预览,然后在按下按钮时在图片框中显示一个框架。这是通过使用直接显示 DxSnap 示例来完成的,因此使用 ISampleGrabberCB 接口。
是否可以在不使用按钮的情况下自动扫描每一帧?
我尝试使用计时器执行此操作,但是结果以预览和捕获的图像质量不佳而告终。
这会通过使用IsampleGrabberCB.BufferCB函数来实现吗?
我目前使用的方式是一个按钮,包括:
int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr buffer, int bufferLength)
{
Debug.Assert(bufferLength == Math.Abs(pitch) * videoHeight, "Wrong Buffer Length");
if (gotFrame)
{
gotFrame = false;
Debug.Assert(imageBuffer != IntPtr.Zero, "Remove Buffer");
CopyMemory(imageBuffer, buffer, bufferLength);
pictureReady.Set();
}
return 0;
}
public void getFrameFromWebcam()
{
if (iPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(iPtr);
iPtr = IntPtr.Zero;
}
//Get Image
iPtr = sampleGrabberCallBack.getFrame();
Bitmap bitmapOfFrame = new Bitmap(sampleGrabberCallBack.width, sampleGrabberCallBack.height, sampleGrabberCallBack.capturePitch, PixelFormat.Format32bppRgb, iPtr);
bitmapOfFrame.RotateFlip(RotateFlipType.RotateNoneFlipY);
pictureBox3.Image = bitmapOfFrame;
barcodeReader(bitmapOfFrame);
}
public IntPtr getFrame()
{
int hr;
pictureReady.Reset();
imageBuffer = Marshal.AllocCoTaskMem(Math.Abs(pitch) * videoHeight);
try
{
gotFrame = true;
if (videoControl != null)
{
hr = videoControl.SetMode(stillPin, VideoControlFlags.Trigger);
DsError.ThrowExceptionForHR(hr);
}
if (!pictureReady.WaitOne(9000, false))
{
throw new Exception("Timeout waiting to get picture");
}
}
catch
{
Marshal.FreeCoTaskMem(imageBuffer);
imageBuffer = IntPtr.Zero;
}
return imageBuffer;
}
DirectShow
为您设置了视频流,因此您拥有帧流,而不是单个图像,例如按下按钮时获得的图像(事实上,对按钮的响应对于 DirectShow 来说是不典型的,可能需要一些特定于相机的集成)。 因此,ISampleGrabberCB::SampleCB
可以按顺序获取每个捕获的视频帧。您不会使用计时器轮询它,而是为每一帧调用一个回调。
由于听起来您没有得到这个,我想您错过了两件事之一,或者两者兼而有之:
- 您可以/需要设置您感兴趣的捕获分辨率和像素格式 - 对于图像处理,您可能更喜欢未压缩的视频格式而不是压缩的视频格式
- 回调调用是阻塞的,帧处理速度越慢,有效帧速率越低,因为您正在延迟视频流与视频处理时间。
另请注意,某些消费级相机具有更高的快照分辨率和较低的视频流分辨率,因此在视频处理方面,您无法达到相机规格上声明的最高分辨率。