Author Archives: fli10

配置系统所支持的最大内存

lab买的server内存大了也麻烦,整个8G内存居然camera的驱动就不认了,只好拔掉4根内存条,或者将OS从windows2003server Enterprise转成winxp32bit,这时PTgrey的camera才能用(据说ptgrey做的camera还是最好的)。这些哥们设计驱动的时候估计压根就没有想到有人将这么多个camera同时连到一个server上,就算想到了估计也没有想到会在机子里装这么多内存,可是我们就是这么干的。搞得这一星期来我就不停的重起机子,在server,winxp64,winxp32之间不停的切换,感觉自己在无偿得为ptgrey做测试,到现在提交的问题一个也没有解决,郁闷不是一两星期了。

其中有一个问题得到了confirm,就是现在他们的驱动在32bit的OS下,只能支持小于4G的内存,大于4G的话程序就不能运行。今天那个Paul给我发邮件说,其实不用每次将内存拔下来的,只用这样这样那样就可以了。就是修改系统的BOOT.INI文件,在

[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows 2003 Server, Enterprise Edition" /fastdetect

后面加个/maxmem=3000就行了,3000指的是3000M内存。如果你的机子装了多OS,这里会有好几条信息,对应着系统启动时不同的选择信息,随便删掉一个,那个对应的系统就没法启动了。有时安装OS时会产生冗余的启动选择项,就可以跑到这里来,删掉就可以了。

RANSAC简单实用

最近经常看到RANSAC的字眼。最先是在使用dynamic silouette作multi-camera calibration的paper里看到的,他们使用改进的RANSAC算法来估计Epipolar Geometry的参数;后来又在vision的课上看到了RANSAC,用来做从两副图像生成paranoma image,后来看到RANSAC主要被用来估计fundamental matrix的7个参数;再后来就在各式各样的matlab工具箱里看到RANSAC。总之一句话,RANSAC是个很简单的但很有效的算法,以后要经常使用些。

“We approached the fitting problem in the opposite way from most previous techniques. Instead of averaging all the measurements and then trying to throw out bad ones, we used the smallest number of measurements to compute a model’s unknown parameters and then evaluated the instantiated model by counting the number of consistent samples.

—- RANSAC: An Historical Perspective, Bob Bolles & Marty Fischler

一个用RANSAC估计Homography的算法为:

How to use manifests and re-distributable assemblies?

http://www.codeguru.com/forum/showthread.php?t=408061


Q: I have an MFC application that runs on my computer, but when I try to run it on another PC I receive an error message that the application failed to initialize and I should re-install it. What should I do?
A: By default, Visual C++ 2005 builds all native C/C++ applications as isolated applications, i.e. self-describing applications that use manifest files to describe their dependencies to VC++ libraries. The problem occurs because your application doesn’t have a manifest, or it has dependencies to assemblies that don’t exist on the target PC, or they have a different version number. Basically you have to do two things to solve the problem:

  • Distribute a manifest resource file along with your application
  • Deploy the re-distributable assemblies that your application depends upon

Q: What is a manifest resource?
A: A manifest resource is an XML file that describes the dependencies of your application. Such dependencies can include the most current version of the Windows common controls, as well as library assemblies, such as MFC, ATL or CRT assemblies.
Your manifest should have the same name as the application and the extension "manifest" and should specify the version number of your assembly (executable or dynamic library), processor architecture, name of the assembly and platform type; a description of your assembly is also recommended.

Code:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="CompanyName.ProductName" type="win32" /> <description>Description of your application.</description> </assembly>

Q: How do I specify dependencies?
A: You have to add a element to the XML-based manifest. For instance, if you want your application to use the Windows common controls with the XP-like style, add a dependency to the assembly called "Microsoft.Windows.Common-Controls":

Code:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="CompanyName.ProductName" type="win32" /> <description>Description of your application.</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly>

Q: I now understand what a manifest resource is, but what are re-distributable assemblies?
A: These are assemblies provided as dynamic link-libraries that you can deploy with your application, because they are required for the application to work. Assemblies are provided in several configurations, Release and Debug, but you can only re-distribute the release configurations (can be found in Visual Studio 8 installation folder, VC\redist).
Visual C++ 2005 supports a new deployment model for Windows client applications based on isolated applications and side-by-side assemblies. Basically, assemblies can be:

  • shared (they are globally registered in the system, installed in the Global Assembly Cache – GAC folder in Windows – and available to all applications) or
  • side-by-side, described with a manifest, distributed with the application and available only to that application

In Visual C++ 2005, library assemblies (such as MFC, ATL, CRT) have been rebuilt as shared side-by-side assemblies and installed in the native assembly cache, WinSxS folder in Windows. That means they are not globally registered in the system, but are globally available to the applications that specify a dependency with a manifest file.
The target machine where you run your application may already have the required dependencies installed. You can look-up for them in the WinSxS folder. Assemblies are grouped here on categories, each with its own folder. Folder names start with the platform name, followed by Microsoft, category (Windows, VC80, MSXML, Tools), assembly name, a token number, version and additional identifiers. The manifest files for these assemblies are located in the Manifest subfolder of WinSxS and have the same name as the folder of the assembly group they contain information about.
Q: How do I specify dependencies for my application in the manifest file?
A: Suppose your application uses MFC as a shared library, so it has at least a dependency on MFC and one on the C runtime library and C++ runtime library (these two part of the CRT assembly group). In this case your manifest file should look like this:

Code:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="CompanyName.ProductName" type="win32" /> <description>Description of your application.</description> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50727.42' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC80.MFC' version='8.0.50727.42' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> </assembly>

If the target machine already has these assemblies and the version info (process architecture, version, public key token) matches, you don’t have to redistribute anything, because your application will be able to use the assemblies from the native assembly cache (WinSxS). Since you cannot be sure of that you should distribute these assemblies with your application (in the same folder with the application). Windows will first looks-up for assemblies in the current folder and then in WinSxS and GAC, so distributing them in the working folder ensures those assemblies are used.
To distribute the correct assemblies after building the application, go to the Visual Studio 8 installation folder in VC\redist and select your target platform folder, i.e. x86 or amd64. Inside, you will see folders for ATL, MFC, CRT, MFCLOC and OPENMP.
The Microsoft.VC80.MFC folder contains 4 DLLS and a manifest file, called Microsoft.VC80.MFC.manifest. You must copy at least MFC80.DLL (or MFC80U.DLL if you built for UNICODE) to your application working folder. You must make sure that the version number of the MFC assembly specified in this manifest matches the one you put in your application manifest and the one of the DLL itself (this should be implicit, but should check that from the file properties, Alt + Enter > Version).
The Microsoft.VC80.CRT contains 3 DLLs and the manifest. Of these three DLLs you need at least msvcr80.dll (C runtime library) and msvcp80.dll (C++ runtime library). The same caution for the version number must be taken.
With all these taken care of, your application should correctly run on any target machine.

Everything You Need To Know To Start Programming 64-Bit Windows Systems

Matt Pietrek

One of the pleasures of working on the bleeding edge of Windows® is poking around in a new technology to see how it works. I don’t really feel comfortable with an operating system until I have a little under-the-hood knowledge. So when the 64-bit editions of Windows XP and Windows Server™ 2003 appeared on the scene, I was all over them.

The nice thing about Win64 and the x64 CPU architecture is that they’re different enough from their predecessors to be interesting, while not requiring a huge learning curve. While we developers would like to think that moving to x64 is just a recompile away, the reality is that we’ll still spend far too much time in the debugger. A good working knowledge of the OS and CPU is invaluable.

In this article I’ll boil down my experiences with Win64 and the x64 architecture to the essentials that a hotshot Win32® programmer needs for the move to x64. I’ll assume that you know basic Win32 concepts, basic x86 concepts, and why your code should run on Win64. This frees me to focus on the good stuff. Think of this overview as a look at just the important differences relative to your knowledge of Win32 and the x86 architecture.

One nice thing about x64 systems is that you can use either Win32 or Win64 on the same machine without serious performance losses, unlike Itanium-based systems. And despite a few obscure differences between the Intel and AMD x64 implementations, the same x64-compatible build of Windows should run on either. You don’t need one version of Windows for AMD x64 systems and another for Intel x64 systems.

I’ve divided the discussion into three broad areas: OS implementation details, just enough x64 CPU architecture to get by, and developing for x64 with Visual C++®.

http://msdn.microsoft.com/msdnmag/issues/06/05/x64/default.aspx

Vision的第一次HW

第一次作业做两幅图像的fusion,用Laplacian Pyramid 的方法。自己写卷积函数,上采样下采样函数,还有Pyramid函数。搞不懂vison的老师为什么还要我们实现这么老的算法,上学期都已经学过Poisson Image Editing了,这学期反而退化去实现这个Pyramid算法,简直没有脾气。

输入两幅图像,还有mask图像:

 融合结果为下左,接着相加的结果为下右:

被程序给郁闷了

郁闷,不能release image

Unhandled exception at 0x7c901230 in Prog1.exe: User breakpoint

程序停在free.c的return HeapAlloc(_crtheap, 0, size);这一行

如果ignore,and continue,则会碰到

Insufficient memory (Out of memory) in function cvAlloc, .\cxalloc.cpp(111)

….

搞了快6个小时才发现,image循环的for loop写错了,写成了

for(int i = 0; i < src->widthStep; i ++)

这样image的数据就写出届了,搞得image的data crash了,因而不能release。还好现在都搞定了,只用了0.2s,删掉了4个字母。 

准备学习Emacs

以前一直都是用vim的,而且觉得vim的功能很强大,用起来也很方便,所以很排斥emacs。最近学习lisp,发现用vim写lisp程序还是不太方便。用vim写好的lisp程序还要另外打开lisp的编译器才能编译,有点不爽,决定看看emacs。不过就准备学习一下emacs的简单功能,学多了没时间也容易忘,呵呵。

A Tutorial Introduction to GNU Emacs
http://www2.lib.uchicago.edu/~keith//tcl-course/emacs-tutorial.html
A Emacs+Lisp Tutorial
http://xahlee.org/emacs/emacs.html

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;
    ……
}

Tail Recursions

http://www.cs.sfu.ca/CC/310/pwfong/Lisp/2/tutorial2.html

Recursive functions are usually easier to reason about. Notice how we articulate the correctness of recursive functions in this and the previous tutorial. However, some naive programmers complain that recursive functions are slow when compared to their iterative counter parts. For example, consider the original implementation of factorial we saw in the previous tutorial:

(defun factorial (N)
  "Compute the factorial of N."
  (if (= N 1)
      1
    (* N (factorial (- N 1)))))

It is fair to point out that, as recursion unfolds, stack frames will have to be set up, function arguments will have to be pushed into the stack, so on and so forth, resulting in unnecessary runtime overhead not experienced by the iterative counterpart of the above factorial function:

int factorial(int N) {
  int A = 1;
  while (N != 1) {
    A = A * N;
    N = N - 1;
  }
  return A;
}

Because of this and other excuses, programmers conclude that they could write off recursive implementations …

Modern compilers for functional programming languages usually implement tail-recursive call optimizations which automatically translate a certain kind of linear recursion into efficient iterations. A linear recursive function is tail-recursive if the result of each recursive call is returned right away as the value of the function. Let’s examine the implementation of fast-factorial again:

(defun fast-factorial (N)
  "A tail-recursive version of factorial."
  (fast-factorial-aux N 1))

(defun fast-factorial-aux (N A)
  "Multiply A by the factorial of N."
  (if (= N 1)
      A
    (fast-factorial-aux (- N 1) (* N A))))

Notice that, in fast-factorial-aux, there is no work left to be done after the recursive call (fast-factorial-aux (- N 1) (* N A)). Consequently, the compiler will not create new stack frame or push arguments, but instead simply bind (- N 1) to N and (* N A) to A, and jump to the beginning of the function. Such optimization effectively renders fast-factorial as efficient as its iterative counterpart. Notice also the striking structural similarity between the two.

When you implement linearly recursive functions, you are encouraged to restructure it as a tail recursion after you have fully debugged your implementation. Doing so allows the compiler to optimize away stack management code. However, you should do so only after you get the prototype function correctly implemented. Notice that the technique of accumulator variables can be used even when we are not transforming code to tail recursions. For some problems, the use of accumulator variables offers the most natural solutions.