Category Archives: Techniques

camera多线程程序

最近写的camera图像采集程序是一个多线程程序,一个主线程创建了两个image grab线程。两个grab线程分别控制两组fps和resolution不同的camera,由于capture的桢率太高,120fps和30fps,所以无法实时存下image。因此我开辟了大量的内存,将capture的image先存到内存了,然后再不断的创建save image线程来存image,当一定内存区域的data存下来得时候,该save线程就把内存给free掉。

花了很多的时间才想到这个策略,实际上也是很有效的。然后写程序的时候,碰到了更多的问题。对于两个grab线程,我用了WaitForMulitipleThreads()来结束,而save线程,因为要考虑到实时性(save线程是在grab image的for循环里创建的,先grab一定数量的image, 然后创建save线程,然后再循环去grab),所以没有用WaitForSingleThread()来结束,直接创建了线程就不管了。这时候出现了很多问题,

1。我是在grab for循环里创建save线程的,也就是在for 循环里pack传给save线程的参数(内存指针,一些camera 参数,存image的路径等等),每次循环只更新部分参数。这样结果造成,参数在传给save线程之前是正确的,但是当save线程执行时,这些参数在save线程外得到了更新(因为thread函数传入的是一个void指针),在save线程里访问这些参数时,有可能被改变了,也有可能正在被刷新,这样造成了指针无法访问,char*出现了乱码。
解决方法,如果知道要创建的save线程数量,就开辟相应足够的空间来把这些传入参数统统存下来,每个save线程有各自独立的输入参数空间,这样就可以了。

2。grab线程只是grab image,然后new memory,创建save 线程就退出了。如果save线程的参数空间是new来创建的,这时候当grab线程结束,把save线程的参数空间给delete的时候,有些save线程还没有结束(磁盘操作是很花时间的),这样save线程就会报错了,参数丢失了。
解决方法,当每个save线程执行时,先把输入参数copy到该save线程自己的线程空间堆栈了,这时候如果输入参数空间被delete了,自己函数空间了也有备份,就一点问题都没有了。

就这些东西花了一个星期才搞兴趣,自己还是太笨了。

有点开始做research的感觉了

现在有点开始做research的感觉了。从上研究生到现在已经4年了,根本没有过在做research的感觉,感觉做的都是别人告诉你应该做的东西,用一些别人告诉你应该用的算法,当然大部分还是自己看paper知道的应该用的算法,但是自己的主动性还是不强,全身心参与的不是很多。

但是现在感觉有些发生了变化。这一个学期以来,发现都是自己决定买做实验用到的设备,小到一个螺丝钉,双面胶,一把手锯,大到一个camera,一个server,完全由自己亲自去买。读paper也是,自己去找相关的paper,自己感兴趣的paper。但是,看了一些paper后(!-_-, 自己看的还是太少)还是不知道要做什么。每当有个小的想法时,就会发现别人已经做过了,而且做得东西比自己想的还要多,效果也非常好。顿时有很沮丧的感觉。

如果一个人的努力能读出phd的话,也就不需要老板了。老板毕竟是老板,终究还是阅历丰富学识渊博,毕竟也纵横“江湖”比我多“几载”。虽然上个学期他也没什么idea,但是现在经过和老板的讨论,终于发现了一个很有意义的课题。有时候觉得自己要做个个方面,搭环境、设计算法、写程序,这些对自己都很陌生的,而且完全由自己掌握,自己不免会很兴奋。给自己加油,争取做出些有意思的东西来。

不能debug程序

今天在编译下载的SIFT程序时,一直弹出这个对话框,无法调试,忙了一晚上都没搞定。不知道这是怎么回事?

NoSymbolicInformationError

查了一下微软的msdn,说,

This dialog box appears when you attempt to debug a project that has no symbolic debug information available. This may happen if:
You attempt to debug a Retail configuration of a project rather than the Debug configuration.
You’ve changed the Debug configuration settings in the Property Pages dialog box.
You are opening an .EXE as a project.

Matlab也用了IPP?

今天debug程序的时候,查看了一下程序运行时调用的modules,发现调用下面几个:

ippcv20.dll C:\Program Files\MATLAB\R2006b\bin\win32\ippcv20.dll
ippcvw7.dll C:\Program Files\MATLAB\R2006b\bin\win32\ipp20\ippcvw7.dll
ippi20.dll C:\Program Files\MATLAB\R2006b\bin\win32\ippi20.dll

mkl_p4.dll C:\Program Files\MATLAB\R2006b\bin\win32\mkl_p4.dll

我的程序根Matlab没有关系,怎么会调用matlab路径下的东西?而且,matlab下怎么会有IPP和MKL的动态库,版本还那么老,难道Matlab也用了IPP和MKL来做在Intel CPU上的优化?

GNU Scientific Library (GSL)

GSL是一个开源的科学计算库,里面包含了矩阵运算、排列组合、多项式求解、随机数生产、FFT、概率tonji、线形拟合、小波变换等等,基本覆盖了科学计算的方方面面,效率应该是很高的(都是牛人写的,这一点应该没有疑问)。
Linux: http://www.gnu.org/software/gsl/
Windows: http://gnuwin32.sourceforge.net/packages/gsl.htm

自己发现Gsl也是很偶然的,在找SIFT implementation的时候看到了别人在SIFT的时候用了Gsl。就这样花了一些时间看了看Gsl,发现他还是很powerful的,不过有些运算也没法做,比如sparse matrix求解,这还得用taucs。Anyway,还是很有收获的。

开篇

本来是在MsnSpace写一些想记在笔记本上的东西,可是那个上面的人太多,而且总是有些人让我很不爽。今天在水源上看到有人介绍blogger,而且和google account结合起来,看起来很方便,很是喜欢。以后就在这里聊聊自己的一些体会,全当自娱自乐。

Single Camera Calibration

最近做了single camera calibration,程序很快就搞定了,但是结果验证却花了近一个星期的时间,各个坐标系的转化搞得我晕头晕脑的,正确的结果还以为是错的。

calibration直接调用opencv里的函数,实现的是zhang’s A flexible new technique for camera calibration的算法,矫正的参数用pov-ray生成的image验证了一把,还是很准的。

我在pov-ray里定义的camera为:
location <5, -8, -16>
look_at 0
angle 60
resolution 800×600
right 1.33
up 1

所以intrinsic parameters 应该为:

[fx 0 cx]     [692.8203 0 400]
[0 fy cy] =  [0 692.8203 300] (fx = fy = 600 * (2 / 3) * 3 ^ 0.5 = 692.8203.)
[0  0   1]     [0 0        1        ]

calibration的结果为:

693.979 0 399.431
0 692.647 300.201
0 0 1

extrinsic parameters应该为:

calibration的结果为:

-0.954613 1.60057e-005 -0.297849
-0.12835 -0.902411 0.411317
-0.268776 0.430877 0.861455

T’ = 0.0100281 -0.000391165 18.578

从上面的结果来看zhang’s的算法还是很准的,难怪opencv都用他的算法。只是extrinsic parameters产生的结果让我迷了很长时间,我一直以为translation matrix T应该就是camera location <5, -8, -16>,但是结果是 <0.0100281 -0.000391165 18.578>。实在想不明白,最后还是到yahoo opencv论坛上问了一把,才知道这个R,T都是在定义在camera coordinate下面的,所以最终的T是用R*t’得到的,因为要将该向量转化到camera coordinate下面。因为这郁闷了很长一段时间,现在总算搞明白了。

Win32程序函数调用时堆栈变化情况分析

http://ubee.cn/cxkf/Windows/200611/310.shtml

在经典的汇编语言教程中,函数调用时堆栈的使用都是着重讲解的问题。如今随着高级语言的越来越完善,单纯使用汇编开发的程序已经不多了。但对函数调用时堆栈动向的了解仍有助于我们明晰程序的执行流程,从而在程序编写和调试的过程中有一个清晰的思路。
一.调用约定
在Win32中,有关函数的调用主要有两种约定。
1._stdcall
        以__stdcall方式调用的函数有以下特征:
    •  参数由右至左压栈
    • 调用返回时,堆栈由被调函数调整
2.__cdecl
__cdecl约定是C/C++函数的默认调用约定。它有以下特征:
    • 参数由右至左压栈
    • 调用返回时,堆栈由调用者调整
二.Win32函数调用过程
1.    压入参数
这里依据以上的调用方式将调用者给出的参数一一压入堆栈。
2.    压入断点
当程序执行到Call指令的时候,当前语句的地址作为断点地址压入堆栈。
3.    跳转
eip的值被重新设置为被调函数的起始地址。
4.    mov ebp, esp
这里ebp被用来在堆栈中寻找调用者压入的参数,同时作为调用者堆栈指针的一个备份。在此前还应该执行一条:
push ebp
把ebp中原来的数值保存。
5.    sub esp,N
这里N是函数内局部变量的总字节数加上一个整数,一般为40。此后esp即为被调函数的堆栈指针了。
6.    初始化esp ~ esp-N之间的N字节空间
这是对堆栈中已分配给局部变量使用的内存空间的初始化,一般全部设置为0xcc。
7.    顺序执行函数内语句。
此时函数的堆栈位于所有局部变量的内存空间之后,二者之间一般有40字节的隔离带。
8.返回
为保障调用的正常返回,函数内应当保证规范使用堆栈,使即将返回的时候esp的值恢复为执行第一条语句前的状态。说明白点,就是每一条push都要有相应的pop。
调用返回的过程如下:
mov esp, ebp
执行后,esp恢复为调用者的堆栈指针,栈顶除断点地址外,还存有原ebp的值和调用时压入的参数。
然后依次弹出ebp的值和断点地址。如果是__cdecl约定则直接返回调用者,调用者将负责调整堆栈,丢弃调先前压入的参数。如果是__stdcall则这个工作由被调函数来执行。
程序样例如下:
……
0040B8E8   push        1            ;压入参数
0040B8EA   call        00401028        ;调用函数
……
00401028   jmp         0040b7c0        ;跳转到函数入口
……
0040B7C0   push        ebp            ;保存ebp
0040B7C1   mov         ebp,esp        
0040B7C3   sub         esp,44h        ;设置函数的堆栈指针,此函数中有4
;字节的局部变量
0040B7C6   push        ebx
0040B7C7   push        esi        
0040B7C8   push        edi
0040B7C9   lea         edi,[ebp-44h]    
0040B7CC   mov         ecx,11h
0040B7D1   mov         eax,0CCCCCCCCh
0040B7D6   rep stos    dword ptr [edi]    ;初始化局部变量空间
0040B7D8   mov         eax,dword ptr [ebp+8]
0040B7DB   mov         dword ptr [ebp-4],eax
……
0040B7DE   pop         edi            ;弹出曾压栈的数据
0040B7DF   pop         esi
0040B7E0   pop         ebx
0040B7E1   mov         esp,ebp        ;恢复调用者的堆栈
0040B7E3   pop         ebp            ;弹出原ebp值
0040B7E4   ret         4            ;返回并将堆栈向上调整4字节。
;此处为__stdcall约定,所以由函数调
;整堆栈
相应的C代码如下:
void __stdcall fun(int);
int main(void)
{
    ……    
fun(1);
……
    return 0;
}
void __stdcall fun(int para)
{
    int localpara = para;
    ……
}