Month: February 2013

rand函数不可重入

写C代码的时候,srand(int seed) 和 rand() 是常用的伪随机数生成函数。
这两个函数的使用方法很简单,但是一个可能被忽略的细节是,rand() 依赖一个内部的、全局的状态变量。所以 rand() 是不可重入,也是不是线程安全的 (thread-safe) 。

如果多个线程同时调用 rand() 函数,那么无论你如何使用 srand(int seed) 都无法保证结果是可以重现的。每次运行程序,各个线程中 rand() 函数生成的伪随机数序列都和上次不同。

在调试的时候,不能重现的结果会是比较棘手的障碍。

幸好,我们可以用C++11 提供的伪随机数生成器 Pseudo-random number generation (这么翻译好机械-_-!)用法很容易在网络上找到,这里有一个最简单的例子。

#include 
//.....
{
std::default_random_engine gen(0);
int a_random_number = gen();
}

default_random_engine维护自己的内部状态,各个线程都用同样的参数初始化default_random_engine,就可以得到一致的伪随机数序列了。

Tips 2013-02-17

  • 如果有需要把工程从Linux下面移植一份到Windows下,却又不熟悉Visual Studio的各种配置,那么用CMake来管理工程是一个不错的选择。从Makefile改写CMakeLists.txt并不麻烦,而且CMake可以自动生成VS的工程文件,很好用。
  • 用 floor 和 ceil 这类函数最好先对参数做显示的类型转换,否则VS会报错。
  • isinf 和 isnan 能不能则不用,VS没有现成好用的对应版本。
  • 关于把一份Git工程同步到SVN的版本库里去的方法,网上讨论的很多,比如这个: http://stackoverflow.com/questions/661018/pushing-an-existing-git-repository-to-svn 但是如果你的Git的工程已经有了悠久历史,那么在rebase那一步你可能会有非常多的conflicts要处理。一个小办法是每次出现了冲突都用这一行代码:
    $git checkout . --theirs && git add . && git rebase --continue

    当然前提是当前目录下面没有不在git管理下的其他文件。这个虽然不解决根本问题,但是会方便很多。

总是有想要重构自己实验工程的想法,看起来工程的框架还是不太好。我总觉得好的框架应该是很容易修改的,现在每次想要往工程里新加一组实验就觉得有些代码碍手碍脚。如果不想有重复代码函数粒度就太小,而且接口复杂不可读,时间一长就看不出它们都是干什么的了。否则就有大段的重复代码,十分难看。如果把实验操作部分放到Bash脚本里面,移植又是一个问题。很少看到讲这种不大的工程怎么去搭框架的问题,苦于自己技术水平不够,想想真是头疼…

[OpenCV]detectMultiScale

I met a problem when using the interface ‘detectMultiScale’ of OpenCV. The rectangles it gives out may not be fully inside the frame of the original image. As a result, if these rectangles are applied directly on the original image to crop out the detected objects, your programs crash.

These are the interfaces

virtual void detectMultiScale( const Mat& image,
                               CV_OUT vector& objects,
                               double scaleFactor=1.1,
                               int minNeighbors=3, int flags=0,
                               Size minSize=Size(),
                               Size maxSize=Size() );

and

virtual void detectMultiScale( const Mat& image,
                               CV_OUT vector& objects,
                               vector& rejectLevels,
                               vector& levelWeights,
                               double scaleFactor=1.1,
                               int minNeighbors=3, int flags=0,
                               Size minSize=Size(),
                               Size maxSize=Size(),
                               bool outputRejectLevels=false );

I am copying what I wrote for a pull request on Github, this ‘may-be issue’ can be fixed easily by modifying one line in the source file

modules/objdetect/src/cascadedetect.cpp

Replace this one

Size processingRectSize( scaledImageSize.width - originalWindowSize.width + 1, scaledImageSize.height - originalWindowSize.height + 1 );

with this line

Size processingRectSize( scaledImageSize.width - originalWindowSize.width , scaledImageSize.height - originalWindowSize.height);

My explanation goes here, ignore the line numbers if they look wrong to you.
“Actually, in the code, the workflow is more complicated. In the file cascadedetect.cpp

This is the line building the final detected rectangle

995 rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height));

the winSize is assigned here

969 Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor));

while the maximum value of x and y can be find here, they are related to the processingRectSize.

971         int y1 = range.start * stripSize;
972         int y2 = min(range.end * stripSize, processingRectSize.height);
973         for( int y = y1; y < y2; y += yStep )
974         {
975             for( int x = 0; x < processingRectSize.width; x += yStep )

Say the original image size is O, the original window size is W, scaling factor is F. O and W is integer and F is a decimal usually larger than 1. The width and height are assumed to be the same for example.

If we calculate the right-most point of the detected rectangle, it should be:

the maximum x is: (cvRound(O/F) - W), current winSize is W*F, following the line 995 we get:

cvRound( (cvRound(O/F) - W) * F ) + W*F

This can be larger than O, say O is 600, F is 4.177250, W is 24, the number we can get above is 601.254 which is larger than 600."

Hope these help.