Directshow & .Net - Bitmap shows stripe from right on left side of image?

﹥>﹥吖頭↗ 提交于 2019-12-12 18:13:12

问题


Sample Image:

I'm using DirectShow.net to get webcam footage into my program. To accomplish this, I'm adding the source camera to the graph, and a VideoMixingRenderer9.

That part is all working swimmingly, but the part where I extract a frame using GetCurrentImage(out lpDib) is having what I can only describe as an odd issue.

What I am doing is using Marshal.PtrToSTructure to create a BitmapInfoHeader from lpDib, then calculating the width / height / stride / & pixel format.

The problem comes when I look at the image stored in bitmap - It has a 10 px wide line down the left side that came from what is actually the right!

It is worth noting that the data I am getting from the GetCurrentImage call is actually upside down - note the call to 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.

I'm completely lost here. Seems like some sort of offset issue, and I've tried tweaking with stride some, but to no avail (just creates odd diagonal look).


回答1:


The video renderer is extending the bitmap to suit its own memory alignment needs, but it will have adjusted the media type to match. The VIDEOINFOHEADER (or VIDEOINFOHEADER2 structure) in the media type will have an rcTarget rectangle that defines the valid area within the larger bitmap. You can query the current media type on the input pin and get hold of this information.

You will find that the renderer only needs this extended stride for some formats, so perhaps your simplest approach is to force a different capture format. An alternative is to use the sample grabber filter instead of the VMR.

G




回答2:


This code is made using the DirectShowLib samples and it works:

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;
        }



回答3:


For those who want to avoid using SampleGrabber. The "stripe" issue can be fixed by adding the offset of the bitmap header to the IntPtr. However this requires unsafe code

    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;

Calculation for Stride can be found here.



来源:https://stackoverflow.com/questions/1354165/directshow-net-bitmap-shows-stripe-from-right-on-left-side-of-image

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!