| Dahua 的个人资料笑对人生,傲立寰宇照片日志列表 | 帮助 |
|
2月28日 CVPR 2006 结果揭晓!凌晨3点半,突然接到志峰的电话,说结果出来了。于是把欢子拉到自己房间一起看结果。
开机太慢了,这段时间打电话问了一些师兄,传出的都是不好的消息,于是心里变得特别紧张。
打开网站一看,终于看到自己的结果了:
中了 1篇oral + 1篇poster
基于今年CVPR的严峻形势和激烈竞争,这个结果还算蛮不错了。
在未来几个月,暂时没有会议了,简单回顾一下:
来香港一年半,投了18篇paper,中了13篇(6篇oral + 7篇poster),其中
按作者次序:
第一作者 9篇
第二作者 3篇 第三作者 1篇 按会议:
ICCV 1篇
CVPR 4篇 (其中 2篇 oral) ECCV 2篇 (其中 2篇 oral) ICIP 5篇 (其中 1篇 oral)
ICME 1篇 (其中 1篇 oral) 对于所取得的成绩,真的要感谢很多人的帮助和支持。
感谢我的父母,感谢汤老师和刘老师,感谢水城,感谢实验室的兄弟姐妹,感谢不在身边的朋友。
Research的路还很长,现在还仅仅是个开始。喜悦自然是免不了的,不过还是要安定下心来,虚心学习。 2月27日 开放性架构CvCommonLib 发展到现在,很多基本功能已经可以比较稳定地使用了。但是,我的目标并不仅仅是做成一个可供最终用户使用的支持性类库,而是一个开放性的平台。在我的理解中一个开放性的架构应该具备下面三个重要的特点:
1) 有足够的基本设施,帮助用户在其基础上进行上层应用的开发。这个目标基本是可以达到了。
2) 一个灵活而且易于维护的架构体系。关于这点,我个人觉得,CVCL的设计虽不能说是尽善尽美,但是基本上是一个架构清晰,和具有充分可扩展性的体系。 3) 方便用户对实现层进行修改。这一点还存在问题。在当前的架构体系下,虽然也能清晰地指出如果要修改某个核心要素的实现,应该写在什么地方。这对于一个封闭性的有一个统一的团队长期跟进的软件来说,是可以的了。可是,如果作为一个开放性的平台,如果要修改和替换核心元素时还要在源代码级别进行修改,就有点不可接受了。 为了解决这个问题,我决定把体系从双层架构:核心支持 - 上层应用,解开为耦合更加松散的三层架构:核心实现 - 协议层 - 上层应用,把核心实现从协议层分离。最终目的,就是能够达到核心实现的动态挂接。
具体说来,可以这样描述:
一个公共的协议层,它由一批模板类和访问接口组成,向上规定了上层应用对库的基本访问接口,同时向下,规定了底层实现的挂接接口。上层应用,看成是客户端,通过访问接口获取支持;下层实现,看成是服务端,通过挂接接口接入协议层,提供支持。
关于具体的设计,还有一些问题,需要更精密的思考:
1) 关于数据访问,比如大数组的元素索引,是要被高密度调用的,一次事务可能要完成十亿次甚至更大量的元素访问。间接层次的引入,对于高密度调用的简单函数在效率上是不可接受的。从这个考虑,我把数据索引功能,直接绑定在协议层。在编译期,数据索引的代码会直接内联到受支持的代码中。这样,就不会带来任何效率上的损失。
2) 关于实现层的动态挂接,我把核心实现规划成为粒度适中的几个基本块,并且为它们分别提供了轻量级的挂接接口。核心实现代码的作者,把核心代码封装成为动态链接模块,并对外expose协议规定的接口。这里面,选择合适的模块粒度是很必要的。如果粒度太大,就是每个模块涵盖的方面太广,比如一个模块把矩阵运算和图像处理全部包括了,则给实现层的作者提了太高的要求。他们往往只是一个方面的专家,很难提供多方面的支持;而且这样做,每个模块的挂接接口就会非常庞杂。如果粒度太小,一个模块只包括某个第一功能,比如加法一个模块,减法一个模块;那么要配备齐全足够对上层提供支持的功能,势必需要收集数量巨大的模块,非常凌乱。
3) 另外提供一个简单易用的配置器,可以动态对各个模块实施切换和配备,而不需要对协议层重新编译链接。
4) 为了让最终用户能够直接使用,在发布的库中,至少对各个模块要提供一个基本的实现,并且提供一个默认的配置。这样,一般的用户就能无需设置直接使用。而高级的用户,则可以自己实现专有的模块,通过配置器轻易地加入系统,而不需要重新进行全盘的编译构建。这样,这个库就兼具了傻瓜相机和高级相机的好处了。
2月24日 把空对空进行到底CVPR的最终结果28号就发布了。在此之前,blog不发风花雪月的东西,只谈学术和programming。
科学和艺术从来都是不可分家的,从前看待数学和物理,总是感觉其中非常奥妙,非常美。最近一段时间忙于编程,同样也觉得这也是一种很有艺术的事情。身边的朋友,也在为course project忙着写程序,不过从他们的言谈中,似乎他们对programming不是这么感觉的,呵呵。
最近为了测试自己的库,写了一个图像处理器。因为,要不断加入新的功能,我希望它尽可能地flexible,并且支持多种操作模式。这个过程,我进行了好几次改写,抽象程度不断加大。 第一次抽象:
把处理代码从GUI事件响应中分离出来,封装成一个个任务(Task),每个菜单命令,调用一个task。
第二次抽象:
我发现以后每添加一个处理任务,就要人工的在菜单栏加一项。如果以后还有任务列表,工具栏,这样就会导致每次加入一个新任务,就要在GUI上多次更改,会非常麻烦。于是把任务封装成插件(Plugin),并且通过抽象工厂,在加载任务时,自动完成相应的界面配置。简单地说,每个plugin通过一定的接口,告诉主框架自己叫什么名字,图标是什么,支持哪种类型的操作等等。主框架会通过一个配接器在加载插件的时候,根据插件提供的信息,自动把项目加入主菜单,弹出菜单,工具栏,任务列表等等地方。
进一步,可以考虑增加对注册表消息的在线监控,这样就能达到非常理想的即插即用的状态。
在这一步抽象里面,处理任务完全和主框架隔离,彻底地接口化了。
第三次抽象:
这时主框架和界面构建还是耦合得很紧密的,这对于以后更改GUI不利。这时,我把GUI的建立过程,通过一个IGUIBuilder的接口进行抽象。主框架在加载插件的时候,调用透过一个抽象的Builder架构GUI界面。以后换掉界面的时候,只要把builder地实现体更改就好了,不影响框架和任务。
通过这一步抽象,GUI显示层,和任务层之间,完全变成了纯虚接口的连接,实现了第一级别的空对空架构。
第四次抽象:
还有一层耦合没有分离出来,就是对用户消息的相应。比如,按一下鼠标,键盘之类的响应,还是紧密地写在主程序的消息相应函数中的。可是,软件可能支持多种操作形式,比如在普通状态下,区域选择的状态下,画图的状态下,用户的点一下鼠标的意义就有很大差别。如果使用大量的判断语句和分支,将使得程序结构混乱。在这里,我把每种操作模式,抽象为interactor,使用IInteractor实施接口化,对于用户处理过程的消息的监视和处理,抽象为observer,使用IObserver实施接口化。在这个过程中, interactor负责具体的用户输入的接收,并且向链接在其上的observer发送通知,observer具体进行处理。
在Win32/MFC下面,可以通过建立非可视窗口的方式,截获用户的各种操作。
通过这一步抽象,用户输入和相应处理,也变成了纯虚接口的连接,实现了第二级别的空对空架构。这给多种操作模式的动态切换带来了极大方便。
当然,我的抽象还是针对具体应用,比如一个图像处理器,进行的低层次的抽象。比如COM/COM+,就是对整个世界进行接口化抽象。对于这些体系的设计者的大师级的气度,一直非常景仰。 2月22日 生命中新的一天这是新的一天,阳光灿烂。感谢每一个给了我支持和鼓励的朋友,真的谢谢了。
还有着很多的期待,很多的梦想,等着我通过奋斗去实现。
醉过方知酒浓,爱过方知情重。
在海边,我想了很多很多。没有跌宕的人生,是不完整的。在自己还很年轻的时候,为什么不能敞开自己的胸怀,去经历,去体验呢?一直以来,我追求卓越,追求成功,追求完美。在这段旅程中,在某些方面创造了让人称羡的成绩,可是,似乎离自己真正的梦想渐行渐远。我希望着创造一个传奇的人生,可是却没有尝试失败的勇气。无限风光在险峰,不历奇险,安得奇遇!
虽然伤痛,今天仍旧是我的生命中值得庆祝的。因为,我打破了心灵中的藩篱,直面失败和风险。真实的人生,应该在失败中成长;多彩的生活,应该在风雨中铸造。
从梦中醒来,我们看到的是朝气蓬勃的清晨; 从安乐窝中离去,我们迎来的是色彩斑斓的世界。 2月17日 CVCL: A new milestone
昨天晚上离开的时候,我统计了一下正在写的Computer Vision Common Library,源文件已经达到52000行。5万行是一个新的milestone,刷新了自己在一年多前达到的单个project 3万行的纪录。
这次是出于项目需要重新写了一个用于computer vision的库,核心就是一个数组类(矩阵类)和位图类。可是为了达到设计目标,整个支持体系有大概120个类,1800个函数。
我希望这个东西能够让更多的人应用,因此这次的设计目标是很明确的:
1. 为懒人设计,让写C++像写Matlab那么轻松。 最终目标就是,Matlab一句话能完成的东西,这里同样也只需要用类似的语法写一句。到现在为止,Matlab基本运算已经移植了一半以上。通过精心设计的索引层,提供了非常丰富的索引功能, 比如你在Matlab写下 A(1:2:10, 3:5) = B(3:2:12, 4:2:8), 基于这个library,可以类似写下 A(RangeEx(1,2,10), Range(3,5)) = B(RangeEx(3,2,12), RangeEx(4,2,8))。Matlab大部分的基本功能,都在库中提供了相应的支持。使得从Matlab到C++的翻译变得非常简单。
2. 高效的运行速度。 Computer Vision是运算密集型的应用,如果为了漂亮的易用性,损害运行效率是得不偿失的。类库一方面建基于Intel的IPP和MKL,充分利用CPU的指令流水线结构和高速缓存,在矩阵运算中实现了比Matlab的矩阵运算高一倍以上的速度。同时在很多密集调用的功能,进行精心优化,使得使用类库的运行效率不低于手工优化的C代码的效率。
3.很好的可扩展性和可移植性。 使用高度标准化的代码,和platform independent的实现,使得类库能够在多种平台下方便移植。所有的头文件中的东西都和平台无关,连math.h和stdlib.h这样的看上去像是标准的头文件都没有包含(因为这些头文件实质是平台有关的),以实现高度的可移植性。
看起来一切都很美妙,但是实施这些优点不是免费的午餐,易用性,高效率,可扩展性和移植性背后的代价就是非常复杂的类库内部设计。平心而论,我不是一个追求代码规模的人,类库中只要某种代码的样式重复出现几次,肯定会独立出来,以避免代码冗余。可以说,我写的代码的冗余度是非常低的。可是多个目标的同时实现,不可避免出现冲突,为了解决这些问题,需要大量运用许多C++标准中的高级特性,比如基于模板的代理器映射之类的东西,使得结构趋于复杂。但是一个矩阵类的支持架构就接近两万行代码。如果大家在大学时,按照教科书实现了一些只有两三百行的简单矩阵类,对于这个就也许感觉有点难以置信了。
这里仅仅举一个例子,比如一个矩阵可能是column major也可能是row major的,要访问某个元素,自然有所不同。通常的做法可能写个if语句判断一下,可是这至少增加两个指令周期的运行时间,对于大部分的代码,这完全无所谓。可是对于两个1000x1000的矩阵相乘,就要完成10亿次元素访问,这时一次访问的每个指令周期都是非常重要的。这里可以使用template proxy的方法把这个if语句的运行时间去掉。这只是一个例子,但是他说明了一个同时达到多个目标的设计架构,和一个简单的教科书那样的设计,有着多大的差别。
这一个多月来,发现自己的C++有了一些长进,对于更大规模的代码的驾驭能力有了新的提高,到现在整套代码还是得到有序的控制,没有出现失控的迹象。比如欢子测试中发现了一些bug,有几个隐藏的比较深,还是能够在较短的时间内从几万行代码中定位修正,这也得益于优良而清晰的架构体系。
以后有机会,会探讨一些具体的设计问题,和大家交流。 2月15日 Valentine's Day in 2006 has passedIt is a special day,which has passed 3 hours ago.
Nothing except something worth mentioning here.
- something on my shoulder
- someone in my heart
that is what I was looking at on the V day, through my eyes, through my mind.
I am pursuing, I am creating a brighter V day next year, from this year, from this month, from today.
Finally, wish all of you a happy Valentine's Day.
|
|
|