C# 如何使用directshow.net扫描ISampleGrabber中的每一帧

C# 如何使用directshow.net扫描ISampleGrabber中的每一帧,c#,winforms,image-processing,directshow,directshow.net,C#,Winforms,Image Processing,Directshow,Directshow.net,我有一个程序,当前显示一个usb网络摄像头的预览,然后在按下一个按钮时在一个图片盒中显示一个框架。这是通过使用directshow DxSnap样本完成的,因此使用ISampleGrabberCB接口 是否可以在不使用按钮的情况下自动扫描每一帧 我试着用定时器来做这件事,但是结果是预览和拍摄的图像质量都很差 这是否可以通过使用IsampleGrabberCB.BufferCB函数来实现 我目前使用的获取帧的方式是一个按钮,包括: int ISampleGrabberCB.BufferCB(dou

我有一个程序,当前显示一个usb网络摄像头的预览,然后在按下一个按钮时在一个图片盒中显示一个框架。这是通过使用directshow 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是不典型的,并且可能需要一些特定于相机的集成)<因此,code>ISampleGrabberCB::SampleCB将按顺序获取每个捕获的视频帧。您不使用计时器轮询它,而是为每一帧调用一个回调

因为听起来你没有明白这一点,我想你错过了两件事中的一件,或者两件都错过了:

  • 您可以/需要设置您感兴趣的捕获分辨率和像素格式-对于图像处理,您可能更喜欢未压缩的视频格式,而不是压缩的视频格式
  • 回调调用被阻塞,帧处理速度越慢,有效帧速率越低,因为您会随着视频处理时间延迟视频流

  • 还要注意的是,一些消费级相机的快照分辨率较高,而视频流分辨率较低,因此在视频处理方面,您无法达到相机规格中规定的最高分辨率。

    因此,我会使用给定的IMediaSample并将其转换为位图吗(因为外部库需要位图)?是的,这实际上很简单。常规流媒体并不完全使用位图,因此您必须从流媒体格式的视频帧中获取位图。我认为会是这种情况,我目前使用的是
    ISampleGrabberCB::BufferCB
    ,因此当按下按钮时,当前帧将以较小的格式显示er框和条形码然后扫描给我一个数字字符串,所以基本上我试图自动实现这一点。是否有转换IMediaSample(我假设是当前帧)的一般过程进入位图?您的问题放错了。您已经自动获取了帧,因此不需要使用按钮,只需将回调调用连接到按钮处理程序所做的任何操作。不存在有关
    IMediaSample
    的一般过程。但是,如果媒体样本是24/32位RGB,您可以使用此接口方法通过指针访问BufferCB中的数据。所以基本上我相信我的BufferCB会不断保存帧,然后当我单击我的按钮执行getFrameFromWebcam()函数时,它会调用getFrame()函数,然后获取当前保存的图像,然后函数的其余部分转换为位图,并将数字显示为字符串。是否理想地将所有这些内容移动到BufferCB中,并且仍然有效?