Directshow & .Net - Растровое изображение показывает полосу справа на левой стороне изображения?

2

Пример изображения: Изображение 174551

Я использую DirectShow.net, чтобы получить кадры веб-камеры в моей программе. Для этого я добавляю исходную камеру к графику и VideoMixingRenderer9.

Эта часть работает плавно, но часть, где я извлекаю фрейм с помощью GetCurrentImage (из lpDib), имеет то, что я могу описать только как нечетную проблему.

Я использую Marshal.PtrToSTructure для создания BitmapInfoHeader из lpDib, а затем вычисления формата width/height/stride/and pixel.

Проблема возникает, когда я смотрю на изображение, хранящееся в растровом изображении. Он имеет ширину в 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.

Я полностью потерялся здесь. Кажется, что-то вроде проблемы с смещением, и я пробовал настроить с шагами некоторые, но безрезультатно (просто создает нечетный диагональный вид).

Теги:
directshow

3 ответа

1
Лучший ответ

Средство рендеринга видео расширяет растровое изображение в соответствии со своими потребностями в выравнивании памяти, но оно будет скорректировать тип носителя, который будет соответствовать. Структура VIDEOINFOHEADER (или VIDEOINFOHEADER2) в типе носителя будет иметь прямоугольник rcTarget, который определяет допустимую область в более крупном растровом изображении. Вы можете запросить текущий тип носителя на входном контакте и получить эту информацию.

Вы обнаружите, что рендерингу нужен только этот расширенный шаг для некоторых форматов, поэтому, возможно, ваш самый простой подход - заставить другой формат захвата. Альтернативой является использование фильтра захвата образца вместо VMR.

С

  • 0
    У меня было немало времени, чтобы заставить сэмплер работать должным образом - все получилось, чтобы все работало надлежащим образом (я использую только одну камеру, так что вывод хорошо известен), просто обрезав оставшиеся 10 пикселей и переместив его в правая сторона. Спасибо за вашу помощь, отметим это как ответ, потому что это то, что это такое!
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;
        }
  • 0
    Можете ли вы сказать мне, что такое «windowlessCtrl».
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 можно найти здесь.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню