在DirectShow的视频图像上叠加线条和文字

在DirectShow的视频图像上叠加线条和文字

最近一直在从事工业测量方面的开发工作,难免会用到各种各样的相机,其中支持DX的USB相机开发起来比较方便,由于工作需要经常要在视频图像上叠加线条和文字,图1便是我最近一段时间写的一套工业检测系统,图像是从USB相机中实时获取的。看到网上有些帖子也在讨论这个问题,现在给出我的一个非常简单的思路并附上源代码(vc++6.0编译通过,需要连接USB相机,可用普通摄像头来代替。地址:http://xiaolang86.download.csdn.net/)。

图1

用过DirectShow的就知道,用DirectShow连接相机并绘制视频图像十分方便,只需要把当前窗口的句柄传给IVideoWindow过滤器,然后设置一下图像绘制的区域就可以实现了,但是这样一来要在图像窗口上叠加一些线条和文字就比较难了。我的思路是,只用DirectShow来连接相机和获取数据,绘制则自己来写,在DC里面实现。大家可以参考我上传的DDShowDemo的程序。具体步骤如下:

1. 设置环境变量:

DShow里面的静态库很多,如果只是需要连接相机,只有几个库就可以了。根据我个人的实际我只用到了Winmm.lib,strmiids.lib,quartz.lib三个库,第一个好像是windows的库。头文件的话我建议把DX里所有的头文件都拷过来,大家也可以把我的源代码目录下的Include/DX这个文件夹全部拷贝过去。具体在VC6.0里面的设置,大家可以去Project->Setting里面看一下。

2. 连接相机:

(1)首先介绍一下连接相机的类:

连接相机是利用CCaptureVideo类,这个类是根据DX中的Demo改编过来的,在网上都可以下到,我的程序中做了一些改动,大家可以直接将源程序中的CaptureView.cpp和CaptureView.h文件拷贝到自己的工程中。在CCaptureVideo类中其实还嵌套了一个CSampleGrabberCB的友元类,该友元类里的BufferCB函数是用来获取每一帧的图像的。

在CCaptureVideo的cpp文件中引入了两个头文件:

#include "DDShowDemoView.h"

#include "GlobalVar.h"

第一个是要绘制的视图的头文件,大家可以改成自己的;第二个是放一些全局变量的头文件,大家可以去看一下定义,需要介绍的是定义在GlobalVar.h里面的一个结构体,个人认为非常有用:

//struct

typedef struct tagCallBackInfo

{

double dblSampleTime;

long lBufferSize;

BYTE *pBuffer;

BITMAPINFOHEADER bih;

} CALLBACKINFO;

这个结构里面定义了采样时间,图像大小,图像数据,图像信息头。并定义了一个实例:CALLBACKINFO cb. 定义好之后,如果要对图像进行某些操作,我们关心的就只是cb.pBuffer就可以了,并且这是一个全局变量在程序的任何地方都可以引用,非常方便。

(2)具体代码

在App中定义一个相机实例CCaptureVideo m_cap;注意需要把theApp进行extern声明,这样可以在其它地方访问m_cap,当然也可以把m_cap放到上面说的全局定义文件中。

在View类的InitialUpdate函数中添加如下代码:黑体字所示

void CDDShowDemoView::OnInitialUpdate()

{

CView::OnInitialUpdate();

//Contact Camera

//zhou's comment:if put this->GetSafeHwnd(),

//DDShow will draw itself, but no vector can be drawed up the buffer,so //give it NULL

HRESULT hr = theApp.m_cap.Init(0,NULL);

//Start Invalidate

SetTimer(0,20,NULL);

}

需要说明的是,如果在Init函数中把当前视图的句柄传进去,那么绘制的工作就可以由DShow来帮你是实现了,这个是我所不希望的,所以我传NULL进去。大家可以跟进Init函数里去看一看,其实真正将图像和当前视图联系起来是函数SetupVideoWindow(),在这个函数里面又需要把视图句柄传进去,如黑体字代码。这不是矛盾吗?大家可以试一下,如果在SetupVideoWindow函数里面也传NULL进去,效果是一样的,但是DX会认为你指定一个视图绘制数据,它会帮你开启一个ActiveWindow的窗口。

HRESULT CCaptureVideo::SetupVideoWindow()

{

HRESULT hr;

//can not be NULL, or will active activewindow

hr = m_pVW->put_Owner((OAHWND)g_pView->m_hWnd);

// hr = m_pVW->put_Owner((OAHWND)m_hWnd);

if (FAILED(hr))return hr;

hr = m_pVW->put_WindowStyle(WS_CHILD);

if (FAILED(hr))return hr;

ResizeVideoWindow();

hr = m_pVW->put_Visible(OATRUE);

return hr;

}

连接好相机之后,就需要通知视图有视频流数据过来,需要刷新。这里的刷新通过开启一个Timer进程来实现。这个是我最近才改动的,之前在做视频开发的时候,我都是将视图刷新放到CSampleGrabberCB的BufferCB函数中,效果也还不错,但是后来换了一种品牌的相机之后,程序也可以获取数据,但是整个程序占用CPU非常高,达到80%以上,才改成在视图里面开启一个时间进程,在视图内部刷新。大家可以看到在OnTimer函数里面就一句话:Invalidate(false):

void CDDShowDemoView::OnTimer(UINT nIDEvent)

{

if( nIDEvent == 0 )

Invalidate( false );

CView::OnTimer(nIDEvent);

}

这样相机就连接成功,现在需要自己动手写一个绘制函数了。

3. 绘制数据

在视图类中添加一个DrawImgBuffer函数

void CDDShowDemoView::DrawImgBuffer(CDC *pMemDC, BYTE *pBuffer, BITMAPINFOHEADER *pbih, CRect rtInput, CRect rtOutput, HWND hwnd )

{

// If we haven't yet snapped a still, return

if (!pBuffer)

return;// FALSE;

HDC hdcDraw = pMemDC->GetSafeHdc();//::GetDC( hwnd );

//select into dc

CBitmap *pOldbitmap = (CBitmap*)pMemDC->SelectObject( pBuffer );

PAINTSTRUCT ps;

::BeginPaint(hwnd, &ps);

::SetStretchBltMode(hdcDraw, COLORONCOLOR);

StretchDIBits(

hdcDraw,

rtOutput.left, rtOutput.top, rtOutput.Width(), rtOutput.Height(),

rtInput.top, rtInput.left, rtInput.Width(), rtInput.Height(),

pBuffer,

(BITMAPINFO*) pbih,

DIB_RGB_COLORS,

SRCCOPY );

::EndPaint(hwnd, &ps);

::ReleaseDC( hwnd, hdcDraw );

}

接着在OnDraw函数里面加上这个函数就好了:

void CDDShowDemoView::OnDraw(CDC* pDC)

{

CDDShowDemoDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CMemDC *pMemDC = new CMemDC(pDC);

CRect rt(0,0,1280,1024);

if( cb.pBuffer )

{

DrawImgBuffer( pMemDC, cb.pBuffer, &cb.bih, rt,rt, this->GetSafeHwnd() );

//just for test:zhoulm's demo

//you can put your line and text there:

CFont font;

font.CreatePointFont( 120, _T("Arial") );

CFont *pOldFont = pMemDC->SelectObject( &font );

pMemDC->SetBkMode(TRANSPARENT);

pMemDC->SetTextColor(RGB(0,255,0));

pMemDC->TextOut( 100, 100, "zhoulm's Demo! Welcome to:www.whudpcv.cn" );

pMemDC->SelectObject( pOldFont );

}

if( pMemDC )

{

delete pMemDC;

pMemDC = NULL;

}

}

注意这里一定要用MemDC来绘制,而不能用微软自带的DC。MemDC定义在MemDC.h文件中,大家需要把这个文件也加入到工程中来。在这里绘制的时候,就可以看到CALLBACKINFO结构体是多么的方便了,直接访问cb.pBuffer就好了,信息头也直接使用cb.bih就好。

编译,完成!看看最后效果吧:

 

时间: 2024-10-01 15:04:06

在DirectShow的视频图像上叠加线条和文字的相关文章

在YUV图像上根据背景色实现OSD反色

所谓的OSD其实就是在视频图像上叠加一些字符信息,比如时间,地点,通道号等, 在图像上叠加OSD通常有两种方式: 一种是在前端嵌入式设备上,在图像数据上叠加OSD, 这样客户端这边只需解码显示数据即可.另一种是PC客户端在接收到前端设备图像,解码之后,进行叠加.这两种都是比较常见的方式. OSD具有字符型(Font-Based)和位图型(Bit-Map)两种类型. 字符型OSD:为了节约显示缓存,早期及低成本的解决方案中使用字符型OSD发生器,其原理是将OSD中显示内容按照特定的格式(12×18

html中如何在图片上叠加一个视频进行播放

问题描述 html中如何在图片上叠加一个视频进行播放 问题是这样的:html中我有一张图片记做A.png,想把一个视频播放的按钮Button.png放在该图片中央,点击按钮,视频会将原图片A.png中覆盖掉并播放,播放完后,视频移出图片.诸位朋友们能指导一下吗?十分感谢 解决方案 容器relative定位,放入图片,button absolute定位,视频容器也absolute定位就行了,视频容器z-index大于button的,这样播放视频时就会遮盖住button了,停止视频时清空视频容器的i

android 调用系统摄像头录制视频后 返回界面时,在界面显示这个视频图像

问题描述 android 调用系统摄像头录制视频后 返回界面时,在界面显示这个视频图像 android 调用系统摄像头录制视频后 返回界面时,在界面显示这个视频图像(显示一个图标也就是控件),点击这个视频图像则播放视频(在这个图标上也就是这个控件),谁能提供下思路?

VS2010 C++学习(5):基于DirectShow的视频预览录像程序

VS2010 C++学习(5):基于DirectShow的视频 预览录像程序   学习VC++编制的基于DirectShow视频捕获程序,主要练习基于DirectShow程序的应用.   一.           主要内容:   1.        基于DirectShow视频预览: 2.        基于DirectShow视频录像:   二.           设计实现: (一).安装DirectShow 首先我们安装DirectShow SDK,由于现在directShow没有和dir

顺义教委携手华平共建视频图像综合管理平台

随着经济的发展和社会的进步,北京顺义区的教育也迈上了新的台阶.据初步统计,目前全区有中小学.幼儿园.中等职业学校115所,大学8所,培训机构86个,在校生近10万人,教职工13000余人.多年教育信息化的推进,使得全区各类高教.普教.基教的IT基础设施得到广泛普及和完善.近年来顺义区教委陆续建设了覆盖全区各类学校的视讯系统,校园安防监控系统,考场巡查系统等等. 但是各个系统均独立运行,无法同时并用.随着信息系统应用的不断增强,如何将各个孤立的视频图像子系统有机结合,发挥视讯.监控融合的整体优势,

国庆阅兵式首次采用电信3G网络传输视频图像

10月10日消息,北京电信透露了其国庆阅兵式通信保障详情,据悉,本次阅兵式首次采用了其3G视频监控,实现了用3G手机即可灵活掌握监控到的受阅部队车辆和装备在行进过程中的实景情况,这也是3G手机首次在中国阅兵史上发挥重大作用. 首次用3G网络传送阅兵视频图像 今年是3G元年,而国庆通信保障工作中,首次采用了北京电信为受阅部队提供的基于CDMA2000-EVDO技术的3G视频监控服务. 北京电信介绍说,由于准备充分,2009年10月1日凌晨,国庆受阅部队从出发至抵达集结地点的视频图像通过北京电信的E

手把手教你制作AppPreview视频并上传到appStore进行审核

手把手教你制作AppPreview视频并上传到appStore进行审核   注意,你需要使用iMovie才能够制作AppPreview视频文件,用QuickTime录制的无效!   最终效果   1. 新建一个事件     2. 创建应用程序预览   3. 导入视频文件(该视频文件需要你用QuickTime事先进行录制,此处不赘述)   4. 导入音频文件   5. 将视频文件音频文件拖到编辑区域   6. 加载转场文件   7. 分离文件并添加转场文件   8. 剪辑结束   9. 导出并生成

css-如何在html图片上方叠加一个半透明颜色层,并在半透明颜色层上叠加文字

问题描述 如何在html图片上方叠加一个半透明颜色层,并在半透明颜色层上叠加文字 问题是这样的:在用html写网页,现在有一张图片,需要置于最底层,然后在图片上方叠加一个半透明颜色层,并在半透明颜色层上叠加文字. 效果就像这张图片一样: 我写的代码如下: li div class="img-wrapper" img src="0.jpg" alt="" width="110" height="110" bo

java视频新闻上传播放

问题描述 java视频新闻上传播放 SSH2框架,做一个新闻的写入数据库,读取到页面.新闻中包含视频,可以播放的,要怎么做? 解决方案 可以用html5还可以用标签 解决方案二: 直接用百度的Ueditor富文本插件得了 解决方案三: 视频先存到服务器上,然后把路径添加到数据库里面,在读取的时候,在转换一下..