现在的位置: 首页 > 综合 > 正文

用SampleGrabber为实时采集视频叠加文字标识

2013年10月21日 ⁄ 综合 ⁄ 共 2482字 ⁄ 字号 评论关闭
 

DirectShow实时采集的视频,在采集filter的输出端子与下一级处理filter之间,添加一个SampleGrabber,可以实现为视频打上logo或者文字标识的功能。

通过IFilterGraph::AddFilter()将SampleGrabber添加到graph中后,在连接之前,首先需要通过ISampleGrabber::SetMediaType()设置SampleGrabber的媒体类型。

因为需要画图,所以需要要将SampleGrabber的媒体类型设置如下:(以下代码段为采用directshow.net的C#语言编写)
   int hr;
    AMMediaType media = new AMMediaType();

    // Set the media type to Video/RGB24
    media.majorType = MediaType.Video;
    media.subType = MediaSubType.RGB24;
    media.formatType = FormatType.VideoInfo;
   
    hr = sampGrabber.SetMediaType( media );
    DsError.ThrowExceptionForHR( hr );

    DsUtils.FreeAMMediaType(media);
设置subType为RGB24,则可以从SampleGrabber抓出的sample中,得到每一帧图像的类型为RGB24的Bitmap,在这个Bitmap上绘制logo或者文字,就可以实现文字叠加的功能。

当然,也可以设置subType为其他位图类型,但是考虑到某些位图类型(比如ARGB32),采集设备可能不支持,所以推荐使用RGB24。

实现ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen),在这个回调函数中对采集设备传过来的帧图像进行绘制,下面代码获得帧的Bitmap:
    Bitmap theFrame = new Bitmap(m_videoWidth, m_videoHeight, m_stride,
                                PixelFormat.Format24bppRgb, pBuffer);

注意由于采集是至上而下扫描,而缺省的Bitmap是至下而上扫描,所以这时得到的表示帧的Bitmap是上下颠倒的,然而并不能使用图像处理函数直接将theFrame再颠倒过来,那样的话,改动不能作用到filter中传输的sample上,估计可能是因为rotate等图像处理函数会导致新生成一个位图。解决方法是新建一个位图用来绘制需要叠加的信息,再将新位图颠倒过来,绘制到theFrame上。

另外,为了减少系统消耗,新建的位图可以控制大小,只需容纳要叠加的文字或图片宽度即可。代码如下:
   // 信息字符距离帧图像边界的宽度
    const int INFO_BORDER_WIDTH = 5;

    Graphics gFrame = Graphics.FromImage(theFrame);

    // 获得信息字符串
    string s = "地点\n";
    s += DateTime.Now.ToString();

    // 获得绘制该字符串所需的面积
    Font drawFont = new Font("Arial", 8);
    SizeF strDim = gFrame.MeasureString(s, drawFont);

    // 若帧图像比信息图像小,则不绘制信息
    if (m_videoHeight < strDim.Height + INFO_BORDER_WIDTH + INFO_BORDER_WIDTH
       || m_videoWidth < strDim.Width + INFO_BORDER_WIDTH + INFO_BORDER_WIDTH)
    {
     gFrame.Dispose();
     return;
    }

    // 新建用于绘制信息的小图片
    Bitmap bimInfo = new Bitmap((int)strDim.Width + 1, (int)strDim.Height + 1);
    Graphics gInfo = Graphics.FromImage(bimInfo);
    gInfo.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    SolidBrush drawBrush = new SolidBrush(Color.White);
    gInfo.DrawString(s, drawFont, drawBrush, new Point(0, 0));

    // 将绘制信息的小图片上下翻转
    bimInfo.RotateFlip(RotateFlipType.RotateNoneFlipY);

    // 将小图片绘制到帧图像上
    Point bimInfoPoint = new Point(INFO_BORDER_WIDTH, m_videoHeight - INFO_BORDER_WIDTH - (int)strDim.Height);
    gFrame.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    gFrame.DrawImage(bimInfo, bimInfoPoint);

    // 释放对象
    drawFont.Dispose();
    drawBrush.Dispose();
    gInfo.Dispose();
    bimInfo.Dispose();
    gFrame.Dispose();

这个方法实现的文字叠加有一个小问题,就是当文字颜色与帧底色接近时,文字边缘会出现彩色,估计是DrawImage的算法导致的,目前我还不知道如何解决。

抱歉!评论已关闭.