从网络摄像头自上而下的图像

时间:2012-12-15 16:51:51

标签: c# wpf image api capture

我从相机中获取了镜头。像这样:

初​​始化:

uint pcount = (uint)(capGrabber.Width * capGrabber.Height * PixelFormats.Bgr32.BitsPerPixel / 8);
section = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04, 0, pcount, null);
map = MapViewOfFile(section, 0xF001F, 0, 0, pcount);
BitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromMemorySection(section, capGrabber.Width, capGrabber.Height, PixelFormats.Bgr32, capGrabber.Width * PixelFormats.Bgr32.BitsPerPixel / 8, 0) as InteropBitmap;
capGrabber.Map = map;

,其中

IntPtr map;
IntPtr section;
InteropBitmap BitmapSource;

Graber(capGrabber):

public int BufferCB(double sampleTime, IntPtr pBuffer, int bufferLen)
{
    if (Map != IntPtr.Zero)
    {
        CopyMemory(Map, pBuffer, bufferLen);
        OnNewFrameArrived();
    }

    return 0;            
}

我将图像颠倒(自上而下)。需要解决这个问题。我找到了一些东西(使用结构BITMAPINFO),但我没有工作。提出任何想法。

3 个答案:

答案 0 :(得分:1)

问题似乎与Top-Down vs. Bottom-Up DIBs有关。

有些人添加WPF转换以将位图旋转180度,但我找到的最简单的解决方案是以相反的顺序复制位图,即替换

CopyMemory(Map, pBuffer, bufferLen);

通过

for(IntPtr pMap = Map, pBuf = pBuffer+bufferLen; pBuf.ToInt64() > pBuffer.ToInt64(); pMap += 4, pBuf -= 4)
    CopyMemory(pMap, pBuf-4, 4);

注意数字4表示代表一个像素的字节数,即32位(RGB32)除以8。

答案 1 :(得分:1)

var target = m_Map;
var bytesPerRow = (m_Width * 4);
var source = aBuffer + aLength - bytesPerRow;

for (int i = m_Height - 1; i > 0; i--)
{
    Interop.CopyMemory(target, source, bytesPerRow);
    target += bytesPerRow;
    source -= bytesPerRow;
}

性能更高。原始代码每次迭代需要224 467 428个刻度。每行复制仅需4 041 288个刻度

答案 2 :(得分:1)

Petr Gotthard考虑到了正确的问题,但代码并没有解决问题。

根据MSDN

  

在自下而上的DIB中,图像缓冲区以底行像素开始,然后是下一行,依此类推。图像的顶行是缓冲区中的最后一行。因此,存储器中的第一个字节是图像的左下角像素。在GDI中,所有DIB都是自下而上的。下图显示了自底向上DIB的物理布局。

这意味着您的图像首先绘制底行,而不是顶行。这会产生垂直镜面效果。但是,它并没有反转左右。

考虑以下数组:

[ 0, 1, 2 ]
[ 3, 4, 5 ]
[ 6, 7, 8 ]

自上而下将按照说明读取和输出。但是自下而上会以这种方式解析它:

[ 6, 7, 8 ]
[ 3, 4, 5 ]
[ 0, 1, 2 ]

如果我们简单地撤销它,我们就会得到:

[ 2, 1, 0 ]
[ 5, 4, 3 ]
[ 8, 7, 6 ]

所以要把它放回去,我们需要步幅(宽度),然后我们逐行反转。

因此,考虑到Petr的答案并加大步伐,我们得到了这个:

int stride = Width * PixelFormats.Bgr32.BitsPerPixel / 8;
for (IntPtr pMap = Map, pBuf = buffer + bufferLen; pBuf.ToInt64() > buffer.ToInt64(); pMap += stride, pBuf -= stride)
    CopyMemory(pMap, pBuf - stride, stride);