十一月的前两个星期都在帮实验室老师做一个与图像处理有关的项目,项目规模虽然不大,但牵涉的方面很广,同时也是我第一次使用C++完整的开发一个软件,因此觉得有东西可以总结。
该项目是在VS2008中使用MFC开发,图像采集设备包括一个工业监控摄像头和一块大恒DH-CG410视频采集卡,图像处理方面使用了OpenCV2.0框架。由于客户端数据需要在服务器汇总,因此系统还具备一套完整的Socket通讯机制。此外,还使用了ADO数据库操作相关的技术。
1、OpenCV2.1, VC2008, ffmpeg之间的冲突。系统需要将采集的视频输出保存,虽然视频采集卡的SDK都会提供视频保存的函数,但灵活性不足,我们使用OpenCV的视频保存功能,可以对视频进行相关处理后再保存。但OpenCV2.1, VC2008, ffmpeg之间的冲突使cvWriteFrame函数始终不能正常工作,详情可以看这篇帖子:
OpenCV2.1写入视频出错--关于ffmpeg的问题
解决的办法是自行重新编译ffmpeg,或者降回OpenCV2.0
2、视频采集卡的选择。由于硬件是由另外一方提供,在这事上走了弯路。起初提供的是一个杂牌的视频采集卡,SDK功能较弱,DSP初始化时间长,采集的视频图像有形变(正常的监控视频画面比是768:576,而这个是702:576),弃之。换用大恒DH-CG410采集卡,各方面表现良好,但价格却是之前那个的三倍。
对于支持DirectShow的视频采集卡,在OpenCV上的开发将更简单,OpenCV网站上有一个此类采集卡的列表,其中以微视的产品为主。
3、YUY2转RGB888。第一块杂牌采集卡,采集的是YUY2色彩空间的(DH-CG410可以选择多种色彩空间)图像,因此需要将其转换到RGB才能被OpenCV的IplImage结构所接受。YUY2是YUV色彩空间中的一种,详细介绍以及各种转换算法可以参考MSDN:
使用8位YUV格式的视频呈现
4、Socket通讯。过去写的Socket程序都是实验性的,而这次写成一个软件时,则有更多的细节问题需要注意。并且,第一次使用winsock的异步模式,避免手动编写阻塞线程,使程序结构看起来更加清晰合理。收获最大的是对TCP连接建立时的三次握手和连接关闭状态的进一步理解,这对编写正确的Socket程序很有帮助,相关的参考文档:
Netstat状态分析
TCP连接状态和Netstat输出
close_wait状态和time_wait状态
5、MFC自定义控件。这一点只是小试牛刀,因为需要一个图像+文字的显示区,为了实现复用,决定自己封装一个控件。控件继承自CStatic,用OpenCV的DrawToHDC函数将图像绘制到指定区域,再动态的生成几个CStatic用于显示文字。其中遇到的一个问题是,控件的OnDraw函数不会自动触发,由于OnDraw是被OnPaint调用,解决办法是在控件的MESSAGEMAP中加入WM_PAINT消息,并手动实现虚函数OnPaint如下:
void CCustomWnd::OnPaint()
{
CPaintDC dc(this);
OnDraw(&dc);
}
关于MFC自定义控件的参考:
hello world级别MFC自定义控件
6、Unicode字符集与ANSI字符集的转换。选择Unicode作为系统的字符编码集,每个字符占16位,其对应的是wchar_t类型,而一些老的SDK依然使用ANSI字符集,每个字符占8位,对应char类型,因此牵涉到短字符和宽字符的转换,这是在C++编程中常见的问题。以下参考资料对这个问题有很好的解释:
C++字符类型总结&CString,BSTR,LPCTSTR之间关系和区别
宽字符集(unicode)说明以及转换函数
最后,要感谢Google老师!
--End--



从一个普通人的角度来看你说到的最后一个问题:字符编码。
每次涉及到相关问题时我就很苦恼,因为很绕人。于是就想,世界都用Unicode多好……
哈哈,幻想罢了~
想询问一些事情,能否给我们一个E-mail地址?或者方便的话,请您直接给我们一封来信?
呵呵,偶打酱油的
抛开你文章写的很好不谈,你这个博客的主题是什么啊?很炫啊。你是的是自己的服务器还是wordpress.com这样的博客托管空间啊?
@未来之风, Blog最底部的一行内容,可以回答你的这个几个问题。
@StevenWang, 没想到这个GAE这么神通广大,谢谢了。