2

示例图片:替代文字

我正在使用 DirectShow.net 将网络摄像头素材放入我的程序中。为此,我将源相机添加到图表中,并添加了一个 VideoMixingRenderer9。

这部分工作正常,但我使用 GetCurrentImage(out lpDib) 提取帧的部分遇到了我只能描述为一个奇怪的问题。

我正在做的是使用 Marshal.PtrToSTructure 从 lpDib 创建一个 BitmapInfoHeader,然后计算宽度/高度/步幅/和像素格式。

当我查看存储在位图中的图像时,问题就出现了 - 它的左侧有一条 10 px 宽的线,实际上是右侧的!

值得注意的是,我从 GetCurrentImage 调用中获得的数据实际上是颠倒的——注意对 Cap.RotateFlip 的调用。

IntPtr lpDib;
windowlessCtrl.GetCurrentImage(out lpDib);

BitmapInfoHeader head;
head = (BitmapInfoHeader)Marshal.PtrToStructure(lpDib, typeof(BitmapInfoHeader));
int width = head.Width;
int height = head.Height;
int stride = width * (head.BitCount / 8);
PixelFormat pixelFormat = PixelFormat.Format24bppRgb;

switch (head.BitCount)
{
    case 24: pixelFormat = PixelFormat.Format24bppRgb; break;
    case 32: pixelFormat = PixelFormat.Format32bppRgb; break;
    case 48: pixelFormat = PixelFormat.Format48bppRgb; break;
    default: throw new Exception("Unknown BitCount");
}

Cap = new Bitmap(width, height, stride, pixelFormat, lpDib);
Cap.RotateFlip(RotateFlipType.RotateNoneFlipY);
//if we examine Cap here (Cap.Save, for example) I'm seeing the odd stripe.

我完全迷失在这里。似乎是某种偏移问题,我尝试过一些调整,但无济于事(只会产生奇怪的对角线外观)。

4

3 回答 3

2

此代码是使用 DirectShowLib 示例制作的,并且可以正常工作:

public Bitmap GetCurrentImage()
        {
            Bitmap bmp = null;
            if (windowlessCtrl != null)
            {
                IntPtr currentImage = IntPtr.Zero;

                try
                {
                    int hr = windowlessCtrl.GetCurrentImage(out currentImage);
                    DsError.ThrowExceptionForHR(hr);

                    if (currentImage != IntPtr.Zero)
                    {
                        BitmapInfoHeader structure = new BitmapInfoHeader();
                        Marshal.PtrToStructure(currentImage, structure);

                        PixelFormat pixelFormat = PixelFormat.Format24bppRgb;
                        switch (structure.BitCount)
                        {
                            case 24:
                                pixelFormat = PixelFormat.Format24bppRgb;
                                break;
                            case 32:
                                pixelFormat = PixelFormat.Format32bppRgb;
                                break;
                            case 48:
                                pixelFormat = PixelFormat.Format48bppRgb;
                                break;
                            default:
                                throw new Exception("BitCount desconhecido");
                        }

                        // este trecho: new IntPtr(currentImage.ToInt64() + 40), é o que resolve o problema da faixa (strip) da direita na esquerda.
                        bmp = new Bitmap(structure.Width, structure.Height, (structure.BitCount / 8) * structure.Width, pixelFormat, new IntPtr(currentImage.ToInt64() + 40));
                        bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    }
                }
                catch (Exception anyException)
                {
                    MessageBox.Show("Falha gravando imagem da Webcam: " + anyException.ToString());
                }
                finally
                {
                    Marshal.FreeCoTaskMem(currentImage);
                }
            }
            return bmp;
        }
于 2013-06-04T14:27:39.550 回答
1

视频渲染器正在扩展位图以适应它自己的内存对齐需求,但它会调整媒体类型以匹配。媒体类型中的 VIDEOINFOHEADER(或 VIDEOINFOHEADER2 结构)将有一个 rcTarget 矩形,用于定义较大位图中的有效区域。您可以在输入引脚上查询当前媒体类型并获取此信息。

您会发现对于某些格式,渲染器只需要这种扩展步幅,因此您最简单的方法可能是强制使用不同的捕获格式。另一种方法是使用采样器过滤器而不是 VMR。

G

于 2009-08-31T11:06:43.223 回答
0

对于那些想避免使用 SampleGrabber 的人。“条纹”问题可以通过将位图标头的偏移量添加到 IntPtr 来解决。但是,这需要不安全的代码

    IntPtr pBuffer = IntPtr.Zero;
    int xBufferSize = 0;
    int xWidth, xHeight;

    basicVideo.get_VideoWidth(out xWidth);
    basicVideo.get_VideoHeight(out xHeight);

    int hr = basicVideo.GetCurrentImage(ref xBufferSize, IntPtr.Zero);
    pBuffer = Marshal.AllocCoTaskMem(xBufferSize);

    // Get the pixel buffer for the thumbnail
    hr = basicVideo.GetCurrentImage(ref xBufferSize, pBuffer);

    // Offset for BitmapHeader info
    var bitmapHeader = (BitmapInfoHeader)Marshal.PtrToStructure(pBuffer, typeof(BitmapInfoHeader));
    var pBitmapData = (byte*)pBuffer.ToPointer();
    pBitmapData += bitmapHeader.Size;

    // This will be the pointer to the bitmap pixels
    var bitmapData = new IntPtr(pBitmapData);

    //Change for your format type!
    System.Drawing.Imaging.PixelFormat xFormat = (System.Drawing.Imaging.PixelFormat.Format32bppRgb);

    int bitsPerPixel = ((int)xFormat & 0xff00) >> 8;
    int bytesPerPixel = (bitsPerPixel + 7) / 8;
    int stride = 4 * ((xWidth * bytesPerPixel + 3) / 4);

    Bitmap image = new Bitmap(xWidth, xHeight, stride, xFormat, bitmapData);
    image.RotateFlip(RotateFlipType.RotateNoneFlipY);
    return image;

可以在此处找到步幅的计算。

于 2016-06-02T20:08:47.613 回答