2

サンプル画像:代替テキスト

DirectShow.net を使用して、Web カメラの映像をプログラムに取り込みます。これを達成するために、ソース カメラと VideoMixingRenderer9 をグラフに追加しています。

その部分はすべて問題なく動作していますが、GetCurrentImage(out lpDib) を使用してフレームを抽出する部分には、奇妙な問題としか言いようのないものがあります。

私がやっていることは、Marshal.PtrToSTructure を使用して lpDib から BitmapInfoHeader を作成し、幅/高さ/ストライド/& ピクセル形式を計算することです。

問題は、ビットマップに保存されている画像を見ると発生します-実際には右側から来た左側に幅10ピクセルの線があります!

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;

Stride の計算は、こちらで確認できます。

于 2016-06-02T20:08:47.613 に答える