| Dahua 的个人资料笑对人生,傲立寰宇照片日志列表 | 帮助 |
|
3月28日 HSFRSince the era of ancient Greece, people have realized that our world is not plane. It consists of multiple layers of distinct granularities. Viewing the universe in different scales would lead us to a greatly different pictures. This notion motivates one of our most important paper this year. In this paper, we try to break the convention in face recognition literatures, which typically consider the face as a plain structure. Admittedly, to select a proper scale and conduct the recognition in that scale is a simple and effective way in the past. However, the rapid development of our society would soon put an end to these old-style methods and call for new methodologies. On one hand, automatic face recognition techniques are being widely deployed, accompanied with increasing demands on the accuracy and robustness of face recognition systems. It is obvious that current mainstream systems are incapable of satisfying the requirements, especially in adverse environment. On the other hand, recent progress in high-performance computers and the popularity of high-resolution digital photos has laid down a solid foundation for a new generation of methods. I believe that the aforementioned factors will bring forth a significant innovation in the field of face recognition. In the new times, face recognition is characterized by the following feature: multi-layer structure based on high resolution images. You may say that, similar ways such as multi-modality fusion are not new in the community. However, they are not true-sense multi-layer approaches, instead, most of them rely on merely multi-parts of the same layer. In this paper, we have initiated the exploration in high-resolution face recognition by opening up the microscopic realm of the face, and developed interesting perspectives on the mutually complementary roles played by different granularities. We hope that this paper will inspire a rethinking in the face recognition field. It is only a beginning. However, the revival of face recognition domain would be in sight with the efforts from the excellent researchers all over the world.
第五次大改关于那个C++库,到现在还没有release,可能有些人等得不耐烦了。
今天,又对多维数组的索引核心进行了新的修改。这已经是这一块的第五次结构性修改了。对于数组类来说,元素访问和子数组访问是最基本的功能。基本原理虽然简单,但是一个好的设计确非常困难。
最难的地方,不在于一个正确的实现,而是要高效的实现。元素访问是对数组最频繁的操作,一次简单的矩阵运算,就可能进行上亿次索引,因此对于每个指令都要斤斤计较。如果,仅仅是几种简单的形式,比如A(i, j)这样子,事情还是很好办的。可是,大家可以看看matlab的灵活多样的索引方式:
A(1:2:end, 2), A(find(B > 0), [1,2,3:4]+1 ,[3:4]), .......
并且支持高维数组。要在C++下面实现这样丰富的索引功能,就很头疼了。如果要灵活,可能要加入一些判断和附加结构,这就大大增加了运行时间。
好在现代的编译器对于模板的支持越来越强,借助强大的泛型设计,可以在不损耗运行时间的情况下,达到类似matlab的丰富和灵活。这个目标实施的代价就是设计复杂度的提高:大量运用泛型技巧,各种模板类相互交织, 把许多运行时的判断推到编译期。
不过,对于使用者,这些都是隐藏的,易用性也是保证的,就像你使用matlab那样,尽管matlab的内部架构异常复杂,但你不用管。
做正确有时很容易,做到完美,就是对毅力的最大考验了。
3月26日 被困雨中香港连日阴雨,到今天还没有舒展开来。今天出门的时候, 没有下雨,便懒得带伞了。在到实验室的路上,又下起雨来。赶紧躲到chan-hostel门前暂避。不到十分钟,就有一男一女两个职员出来,把我视为可疑人士,一番盘问。
虽说那两位职员忠勇可嘉,然其判断力却未必值得称许。以我当时的规矩行止,被列为可疑,受此待遇,实乃奇冤也。本来雨中山景,别有一番情致,经此一事,雅兴荡然无存,待雨稍弱,便冒雨前行了。
大地回春,万物复萌,本是一年中最具生气之季节。然在我心中,喜秋风之豪迈远胜春雨之阴郁。可是,若以更高远的视界审度年复一年的四季交替,春去秋来,方知春乃秋之所倚。春雨未必令人愉悦,可是它的默默滋养,却是成长之源。没有春之孕育,何来秋之收获呢。
杜甫的《春夜喜雨》对春雨之总结,确实是千古绝唱:
好雨知时节,当春乃发生;
随风潜入夜,润物细无声。 一个“喜”字道出春雨之真谛。
3月22日 Next Plan大检查顺利结束了,发现还有很多事情要做,似乎总有做不完的工作。
接下来还要干很多事情:
把Computer Vision Core Library写完,已经付出无数心血了,现在在全面测试,很枯燥,但是我不能release一个没有质量保证的东西。
继续完成Statistical Learning Toolbox的version 4。
根据和老板讨论的计划,在未来几个月,把以往的工作整理为3到4篇Transaction paper,投到PAMI上。
建立一个和FRGC接轨的测试平台,尽快submit第一批结果。
5月上旬到奥地利参加ECCV'2006,6月下旬到美国纽约参加CVPR'2006。
筹备新的专利的申请。
参加TOEFL考试,今年年底要申请了, bless me。
写毕业论文,准备毕业答辩。
3月19日 面临大考离检查还有不到24小时了,这个检查对于实验室的发展休戚相关,汤老师说:we can't afford to fail。用汉语来说,就是只许成功,不许失败。
来香港这一年多来,还是第一次承受如此大的压力:这一次,我的工作不仅关系我自己个人,还关系到整个集体。如果失败,不仅对于我个人,而且对于整个实验室都是不堪设想的。
责任,在从小学到大学的作文中,常常说起,可是,这次是切身体会到这两个字的沉甸甸的分量。
3月17日 几个有趣的C++例子最近在blog上写的几篇关于programming的文章,有些朋友抱怨看不大懂。这一次讨论几个问题,相信大家只要学过C++,就能看到大概了。
Topic 1: 紧凑,再紧凑。
这个例子是最简单的例子了,从这里,只是想展示C++相比于其它语言的一个最大的优点,通过运用它的丰富的运算符体系,可以写出非常简洁和紧凑的代码。字符串拷贝,就是把一个以'\0'结尾(null terminator)的字符数组,复制到目标数组。
假设 szsrc 指向源字符串,szdst指向目标字符串,那么通常的写法是
int i = 0;
for(i = 0; szsrc[i] != '\0'; ++i) { szdst[i] = szsrc[i]; } szdst[i] = szsrc[i]; // copy the null terminator 利用指针的增量运算符,可以简化为
while( *szsrc != '\0' ) *szdst++ = *szsrc++;
*szdst = *szsrc; // copy the null terminator 进一步利用,赋值运算符具有返回值,以及C/C++的条件判断中把非零值判为true,零值判为false的情况,可以进一步简化到:
while ( *szdst++ = *szsrc++ );
这样写,连最后copy null terminator都去掉,因为它是先赋值后判断,前面两个例子是先判断后赋值。
这已经非常简洁了,可是如果szsrc和szdst是直接定义为数组,而不是指针,比如是写成 char szsrc[N] 之类的,那么szsrc就是右值,不能做增量运算了,上面的写法通不过编译。这里可以通过小小的技巧,就能不移动指针而解决问题:
for(i = 0; i[szdst] = i[szsrc]; ++i);
// or
for(i = 0; (i++)[szdst] = i[szsrc]; );
// or
i = 0;
while((i++)[szdst] = i[szsrc]); 这里利用了C/C++一个简单特性:p[i] 等价于 *(p + i) 等价于 i[p]。
Topic 2: 让运算符疯狂起来。 先问一个小问题,C++里面,在符合语法的写法中,最多可以连写几个加号?
答案:在编辑器,和你键盘寿命允许范围内,任意多个。:-D
最简单的例子:
int i = 0;
++++++i; 这时 i 变成 3, 编译器是这样解析这句话的: ++ ( ++ ( ++i ) );
如果前面放奇数个加号呢,或者把加号放到右面呢,对不起,这是违反语法的。
+++++++i; // wrong expression
i++++++; // wrong expression i+++++++; // wrong expression 说明:产生这种情况,在于无论前置或者后置的++都只能作用于左值(对可被改变的变量的引用),++i返回左值,因此可以连续下去,i++返回右值,因此无法再被作用。
依据这个原理,我构造了一个可以被运算符任意蹂躏,却依旧合法的类型,给它起了个名字:MyGod
struct MyGod
{ MyGod& operator ++ (int){ return *this; } MyGod& operator ++ () { return *this; } MyGod& operator -- (int){ return *this; } MyGod& operator -- () { return *this; } MyGod& operator + () { return *this; } MyGod& operator - () { return *this; } }; MyGod g;
这时候,
++++++g;
g++++++; +++++++g; g+++++++; 都是合法的了。而且还可以随意拓展到任意的组合形式: +++----+++++g++++++------;
-----+++++++------g++--++----+++++---++-+-+---++-; 这两句看上去怎么都不像合法的语句,可是在MyGod的类型定义下,它们确实合法!
还有一点不爽,比如-g+g,等有两个或更多操作数的,就不支持了。为了解决这个问题,创造更高的灵活性,可以对这个类进行补充。
struct MyGod
{ MyGod& operator ++ (int){ return *this; } MyGod& operator ++ () { return *this; } MyGod& operator -- (int){ return *this; } MyGod& operator -- () { return *this; } MyGod& operator + () { return *this; } MyGod& operator - () { return *this; } MyGod& operator + (MyGod&) {return *this; } MyGod& operator - (MyGod&) {return *this; } }; 这就perfect了。这时,我们可以对单个或者成组的操作数和运算符进行任意排列,都是合法的:
g----+++++g-----+++++-----g;
++++++------g----++--+++++g---+++++-+--+---g++--++++---;
上面两句都可以通过编译了。
在你写程序写到穷极无聊的时候,可以放心在你的代码中插入任意多的上面的这些“乱七八糟”的代码。我可以保证两件事情:
1) 插入这些东西后,你的代码可以依然通过编译; 2) 在你的程序的release版,这些代码不会对性能产生任何影响。在现代编译器中,上面的代码你就算写上100万句,编译器都不会在release版中产生一行汇编指令,更不会占用哪怕一个指令周期的运行时间。 因为 MyGod 的这些运算符的定义,除了让这些乱搞的语法合法化,不做任何事情,release版中,编译器通过简单的优化,就会把这种不干任何事情的代码完全清理掉的,(我在常用的编译器下,观察过相应的汇编级代码,这些句子确实没有产生任何影响)。
今天说的东西,请勿用于严肃的项目开发中,否则,如果你在代码审查中激怒了老板,我概不负责哦 3月15日 关于一个bug的讨论最近在测试正在写的这个库的时候,发现一个问题,调了好一段时间,始终有点莫名其妙,因此程序执行的逻辑是没有问题的。
后来才逐步确定是因为dll导致的问题——跨越模块边界的内存分配和释放。内存是在主程序分配,而在dll内释放。由于主程序和dll实际上使用了RTL的两组不同的分配纪录。主程序用malloc分配的内存,是记录在主程序的分配表中的,在dll的free函数从dll的分配表找不到对应的记录,因而报错。
可是,一个动态链接库的类,在构造时分配,在析构时释放,这些内存操作理应都在dll里面完成,怎么会出现分配和释放跨越模块边界的问题呢。这里面,其实涉及到模板类的问题。当一个模板类继承自一个非模板基类的时候,非模板基类的虚析构函数负责统一的内存释放操作,而模板子类的构造函数根据具体子类的特点分配特定的内存。因为非模板基类是export到dll里面的,而模板子类的则在主程序中实例化。因而造成这种跨越模块边界的情况。
解决办法也很简单,在dll内封装一个统一的分配函数进行分配操作,并export到dll。这样分配和释放就在dll模块中一致完成了。
因为这个过程错误不在程序执行流程上,而是模块体系的分配上,依靠跟踪查找肯定一头雾水,因此这个bug还是相当隐蔽的。这个bug是下面多个因素综合作用的结果:
1) C++ Runtime Library 中部分函数比如malloc/free使用了静态结构; 2) 这些静态结构在不同module中会具有多个不同副本; 3) 即使使用new/delete,也会在内部调用这些函数; 4) 在模板类继承非模板类时,模板和非模板的实例化时机不同,导致基类子类分置不同模块。 这个问题还是挺有启发意义的。 3月13日 祝福各位正在申请的朋友这段时间,有好几位朋友正在申请。现在,部分学校的结果已经出来了,在和他们的交流中,我也感觉到这些朋友们愈发焦灼的心情。
虽然,我不能给他们很实用的帮助,还是在这里真诚地祝福他们拿到自己理想的offer。
朋友们,请你们勇敢地面对挑战,我相信,你们的努力和付出,一定会有丰厚的回报的。
再次祝福你们。 3月10日 幼稚有时候这两个字是很刺耳的。从行动上说,某些事情自己都知道,也许很荒谬的,或者没有效果的。可是,仍旧要做。
此谓,知易行难。
可是,童心未泯,确实是一种可贵的状态,至少在我看来是这样——它让追求理想的热情不会被现实榨得荡然无存。
我理解和尊重很多人追求平凡和稳定生活的观点,但是,我自己有我自己对人生的价值取向——创造一个传奇的人生:
非凡的成就,脱俗的爱情。
这是一个遥远的目标,需要用毕生的奋斗去一步步实现。很多时候,不得不和现实进行着妥协——就是为了找到一条可行的道路达到目标。
我的生活中有很多朋友,他们给我很多的关心,支持和帮助,这都让我很感激,我觉得,我是一个幸运的人。
可是,路漫漫,有些时候,还是感到一丝孤独——有些东西,是没有人理解的。 无论前路如何,我始终坚守着这样的信念:
让我的人生与众不同。I will have a different life! 3月5日 期待C++0X的到来C++语言的上一个国际标准是在98年提出的,到现在将近8年,一直没有新的标准。在这段时间里,C#经历了从无到有,现在已经发展到第三代标准C# 3.0了。如果再不思进取,也需要退出历史舞台了。不过最近C++ Community正在热烈讨论新一代C++标准,C++0x似乎呼之欲出了。
和C#相比,C++的一个很大的问题在于,内建的库太少了,甚至需要为很简单的操作写一大堆。虽然第三方库浩如烟海,但是相互之间并不兼容,这里面产生很多问题。虽然,作为一个国际标准,加在里面的东西不宜过于庞杂,但是C++当前标准中这么贫乏的标准库,确实需要enrich一下了。
刚刚看到 C++0x Standard Library wishlist (draft revision 06),里面提到一些可能加入新标准的东西,有一些确实很吸引的。我觉得比较感兴趣的:
1. 增强对字符串的支持。比如内建对内码转换,正则表达式,和从字符串到数字的转换,以及字符串格式化的支持。
2. 加入对多线程的支持(在现有C++国际标准,里面没有线程这个概念的,对于多线程开发的支持,比如Win32 Thread, POSIX,都是针对专门的操作系统,由各个开发商提供)
3. 加入对XML的支持,XML作为当前描述语言的defacto standard,加入对它的支持也是时候了。不过,个人认为,它是不是重要到要进入国际标准,还是值得商榷的。
4. 加入对GUI的支持。这个,我是绝对赞同的,一个标准化的GUI编程架构,对于GUI Application的太重要了。虽然现在也有一些号称跨平台的GUI Library, 比如wxWidget,不过实在是,呵呵。但是,这个问题我想阻力非常大,这个加入标准后,原有的GUI程序,怎么迁移呢。GUI这种东西牵扯太多,很难保持对各种主流GUI Framework的后向兼容。可是这种兼容做不好,这个特性就会失败了。这确实考验C++标准委员会的大牛们的智慧了。
5. 文件系统和进程的支持。
6. 加入对线性代数,比如矩阵和向量运算的支持。呵呵,这对于我们这行的人确实是大喜事。不过,在一个通用语言的国际标准加入这种专门化的支持,还是显得有点奇怪。其实,我觉得更加适合的方式,就是另外推出一个国际标准的线性代数库。要不就用我在写的这个吧,哈哈。
7. 加入对特殊函数的支持,比如gamma函数,beta函数,t-统计,gauss-分布。加入对任意精度整数和实数的支持。C++的提案人中怎么那么多数学家啊,呵呵。
8. 二进制对象的标准序列化支持。这对于文件的读写就有了更统一的接口了。
9. 元数据(metadata)支持。如果加入了,大快人心阿。那样的话,C#里面强大的reflection,C++里面也有了。对于架构动态系统的人来说,真是最大的福音了。不过,会不会对性能造成影响呢。
10. lambda-expression的支持。这样可以简化对成组的元素实施操作的代码的撰写。
11. 增加对图(图论里面的图)的支持。
12. Design by contract。这对于模板类的撰写太重要了,可以在early stage就对模板的进行更充分语法的检查。而现在要有效检查语法,必须等到对模板进行实例化的阶段,非常费事。
13. 对物理单位运算的支持,比如速度 x 时间 = 长度, etc。这个蛮interesting的,在modern C++ design里面有更多介绍。
还有很多东西。。。。。。
总体感觉,这像是很多学者提出来的,学术性浓厚,对商业应用的照顾就有点缺乏了。只有Microsoft,Borland等等最后把新的标准植入新版的开发环境,这个标准才能真正意义地推广开来。
|
|
|