OpenCV 2.4.2 imdecode/cvDecodeImage 的 BUG及解决方案

OpenCV是很好用的开源库,不过,还是有一些BUG的~

比如,今天遇到的问题是,imdecode的执行速度很慢。

照理来说,imdecode是从内存解析一幅图像,应该比cvLoadImage还快(或者至少不慢)。

但实际上,执行的时候却是imdecode慢很多(一张图片要1秒以上)。而且很奇怪的是,在某些机器很快,某些机器就很慢。而且调用了不同版本的OpenCV速度也不同。

为什么呢?本着质疑的原则,开始查看OpenCV的源代码。

imdecode的实现在modules\highgui\src\loadsave.cpp中。结果,发现opencv也是先将内存数据写到文件然后再读取的……这不是偷懒么orz

不过,逻辑上没有问题,算法上却犯二了……OpenCV2.4.2及之前版本在实现这个函数的时候,申请了一个临时文件(C:\user\用户名\AppData\Local\Temp\下的ocvXXXX.tmp文件,其中XXXX是0~F的16进制数)。然后写这个文件,然后读。关键是,没有删除!原因是因为临时文件可能不存在(本意是如果形如ocvXXXX.tmp的文件都存在了,那么就不能再新建了,所以返回空不作操作,实际上不会走到这一步),所以最后不一定需要删除文件。于是写OpenCV的小朋友这里为了程序稳定就没有删除临时文件。如图所示:

temp2

结果就是:如果调用imdecode次数越多,速度越慢。超过65535次则每次需要枚举65535个临时文件是否存在。。这个时间对系统而言大致是1秒吧~

当然,写OpenCV的小朋友还是意识到了这个问题,至少2.4.5开始这部分代码就改成判断临时文件名是否为空,不为空则删除了。这样就不会产生临时文件堆积的问题了~

 

anyway,结论就是:

如果想从内存里面直接解析一幅图像,还是乖乖自己写到文件再读取吧~可以模仿opencv去向系统申请临时文件的说~(GetTempPathA和GetTempFileNameA函数)

那些戏剧性的事情~

1)高一暑假学游泳,属于刚刚能游50米的那种;然后高二开学学校举行游泳比赛,因为班级成员人数不足被拉去凑数(4×50接力)。。结果,一共就4个班凑齐了4个人游接力。因为我游得最慢,所以虽然我们班其它三个人速度不错,但是还是屈居第二。结果,戏剧性的一幕出现了,第一名的队伍被判犯规(好像是说中途碰到了泳池壁),被取消成绩,于是我们就成为了第一名……所以,我还是获得过游泳比赛冠军的:)虽然现在扔进水里就会被淹死了吧= =

2)高一参加科技节的凝胶滴定实验(生物),就是老师示范一遍,大家模仿一遍,看谁的实验结果最好看……按照班级顺序进行比赛的,所以到我们班(10班,最后一个)。其实大家都做得差不多。然后老师打分,结果好多都同分。这时候学生会的人就要老师给出一二三名,老师看了看评分表,然后看了看我们(只剩我们刚做完实验还没回班级),就说,那就他们第一吧:) 于是,就这么拿到了这个比赛的第一名= = 后来,班主任还让我用这个第一名去申请学校科技新苗,我觉得比较rp,所以就没申。

finding a job

目前找工作的公司及相关进展:

阿里:笔试(因为试卷原因没印出来)->面试*2->offer
微软:笔试->挂
google:机试*2(第一次被判抄袭orz)->面试*1->面试*2->面试*2->挂
腾讯:电面*2->笔试->面试*2->offer
百度:笔试->面试*3->offer
联想:面试(没去面,因为人在上海)
虹软:笔试->面试->等消息
爱奇艺:笔试->面试(两次让去面试都有事情冲突……)
雅虎北研:笔试->面试*3->面试(技术总监)->等消息
网易有道:笔试(因为要先听宣讲会,而宣讲会人满了只能在外面等,于是直接翘了)
hulu:笔试->挂
微策略:笔试->面试*2->终面->offer
创新工厂:笔试->挂

目前已挂:微软、hulu、创新工程、google
目前已翘:联想、爱奇艺、网易有道
目前已拒:阿里、微策略、百度、雅虎北研
目前等消息:虹软(目测皆挂)
目前已签:腾讯
last update:20131220

test for code


class Solution {
public:
struct info
{
int id;
int step;
};
void gen(vector &vstr,vector *c, int id,vector> &res)
{
vector v;
vector> tres;
if(c[id].size()==0)
{
v.push_back(vstr[id]);
res.push_back(v);
return;
}
int i,j;
for(i=0;i> findLadders(string start, string end, unordered_set &dict) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector> res;
vector v;
if(start==end) //start is end
{
v.push_back(start);
res.push_back(v);
return res;
}
unordered_map mp;
unordered_map::iterator iter_m;
unordered_set::iterator iter_s;
vector vstr;
dict.insert(start);
dict.insert(end);
int id=0,i,j,k;
for(iter_s=dict.begin();iter_s!=dict.end();++iter_s)
{
vstr.push_back(*iter_s);
mp.insert(make_pair(*iter_s,id));
id++;
}
int nStart, nEnd;
iter_m = mp.find(start);
nStart = iter_m->second;
iter_m = mp.find(end);
nEnd = iter_m->second;

int len = start.length();
int nTotal = mp.size();
vector *c = new vector [nTotal];
int *step = new int [nTotal];
for(i=0;i q;
q.push(temp);
while(!q.empty())
{
cur=q.front();
q.pop();
if(cur.step>=nMin) continue;
string str = vstr[cur.id];
for(i=0;isecond;
if(step[id]<=cur.step) continue; if(step[id]!=cur.step+1) { temp.id=id; temp.step=cur.step+1; q.push(temp); step[id]=cur.step+1; if(id==nEnd) nMin = cur.step+1; //find end } c[id].push_back(cur.id); } } } if(c[nEnd].size()==0) //no result { delete[]c; delete[]step; return res; } gen(vstr,c,nEnd,res); delete[]c; delete[]step; return res; } };

home hot home

魔都真热!

话说最近魔都连着4天40℃+,于是今天的39.6℃就显得不那么热了。到底有多热呢?下面举两个小例子:
1)回家当然就要舒舒服服洗个热水澡啦~于是打开龙头,咦,热水器这么快就热了?虽然温度比往年差了点,年久了老化了吧:)于是洗了一分钟不到,突然被烫了……原来刚才那是常温的水,后来才是真的热水啊~
2)晚上发现有点起风了,于是很happy的跑到阳台上去吹风,结果:阵阵热浪扑面而来,这感觉就跟站在空调外机外面吹一样。要不要这么热啊!都已经晚上了诶!

anyway,看来得7×24小时空调了……往年那个37度不开空调盖被子睡觉的少年啊,你现在怎么就成了35度就热坏了的死胖子了呢!

不过,home sweet home,最后的暑假开始了。。第0x00天

汉明距离的快速计算方法

首先,所谓汉明距离,是说两个01串之间不相同的0和1的个数。
比如: 1 1 0 1 1 和 1 0 1 0 1 的汉明距离就是3(中间三位不相同)
那么,怎么快速计算汉明距离呢?
这里给出三个方法,均以两个unsigned __int64的数a和b的汉明距离来做例子:

1)参考文章:http://crane.is-programmer.com/posts/17830.html

unsigned __int64 nHammingDist=a^b;

nHammingDist = (nHammingDist & 0x5555555555555555UI64) + ((nHammingDist>>1) & 0x5555555555555555UI64);
nHammingDist = (nHammingDist & 0x3333333333333333UI64) + ((nHammingDist>>2) & 0x3333333333333333UI64);
nHammingDist = (nHammingDist & 0x0f0f0f0f0f0f0f0fUI64) + ((nHammingDist>>4) & 0x0f0f0f0f0f0f0f0fUI64);
nHammingDist = (nHammingDist & 0x00ff00ff00ff00ffUI64) + ((nHammingDist>>8) & 0x00ff00ff00ff00ffUI64);
nHammingDist = (nHammingDist & 0x0000ffff0000ffffUI64) + ((nHammingDist>>16) & 0x0000ffff0000ffffUI64);
nHammingDist = (nHammingDist & 0x00000000ffffffffUI64) + ((nHammingDist>>32) & 0x00000000ffffffffUI64);

2)如果上述汉明距离需要频繁计算,那么,打表法不失为一种好方法。考虑到打表的大小要尽可能贴近L1缓存限制,所以考虑8bit计算一次:

static int Ham_count[256]={0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};

unsigned __int64 temp=a^b;
uchar *uch=(uchar*)&temp;
int i,nHammingDist=0;
for(i=0;i<8;i++) { nHammingDist+=Ham_count[uch[i]]; }

3)如果CPU支持sse4.2指令集的话,可以用sse扩展指令快速计算(intel core 2以上CPU/amd 推土机以上CPU)

#include //需要这个头文件(VS2008及以上的VS。gcc之类的不清楚)
int nHammingDist=_mm_popcnt_u64(a^b);

那么,上述三种快速算法的时间代价分别是多少呢?
测试方法:1,000个256bit数,每个在100,0000个256bit数中间找最近的那个数。计算总计花费的时间。(单核2.8GHz intel core i5 460m)
下面是实验结果:
方法1: 56s
方法2: 53s
方法3: 34s

由此可见,打表法比折半计算稍快(实际如果多线程同时处理的话,方法2会比方法1快10%以上,因为方法1需要ALU计算,而方法2基本不需要ALU)
方法3的利用sse4.2指令的方法是最快的,但需要CPU支持(不过按照电脑每5年左右会淘汰一次的角度来看,过几年就都支持了)

总结:算法再快,不如CPU硬件实现快……

《跳跃大搜查线》&《神探伽利略》

两部都是和J.C有关的日剧,同样都是大红大紫的人气日剧,但是风格完全不同。

先来说说大搜查线吧。

最初看的是movie1《湾岸署史上最恶的3日间》,然后就被乐得不行了。开篇几个J.C坐在车里,等着一个人出现:那个人是罪犯?是嫌疑人?都不是,是警视副总监。。。所以副总监是要被双规了么?非也,只是地区派出所去接副总监去参加高尔夫表演赛。那为什么要再三确认长相呢?因为怕认错人出洋相啊!这倒没什么,后面一条河上发现了一具尸体,然后这边的J.C就开始嘀咕了:这尸体是在河上,河水在流动,所以说,如果过一会如果尸体流到河对岸去了就不是我们的管辖区域了对吧:)那要不等它漂一会?……总之,之前J.C为人民服务的崇高形象(参考目暮警官等人),瞬间就被颠覆了。

大搜查线的主题是揭露J.C中官僚腐败以及不合理的机构设置,总局和地方警署的冲突(大案要案都要总局主管,分局只能负责端茶送水),以及青岛和室井之间不得不说的故事(大雾)。先说说日本的J.C设置吧,搜查一课负责命案大案的破案工作,地方分局负责在警戒线外维护秩序,这点连柯南里都很明显(目暮警官就是搜查一课的警官哦~),我们的主人公青岛就是分局的一个小喽啰,只是因为J.C人手不够所以被录用了。可别小看了主人公,他之前可是一个IT公司的销售冠军,只是因为觉得公司太官僚太腐败了所以quit要当J.C,先是当了个巡警,两年后通过考试当上了正式J.C(录用的原因是J.C人手不够来者不拒……)。结果,这个小人物愣是仗着自己的一腔热血破获了各种奇怪的案件,虽然功劳基本都不归他,而且还一直被要求写检查(因为总是打破常规触犯规矩),不过却收获了妹纸和基友的好评(大雾)。男女主角在片中感情成份不多,即使最终movie也没有kiss没有表白,只是一个拥抱而已……倒是男男主角(!)整天眉来眼去的。作为搜查一课的搜查官(初始状态,后面越来越nb),整天有事没事去湾岸分局逛一圈,弄得人家局长都心惊胆战以为自己犯事了……跟男主角约定:你在下面,我在上面,各自深入(弥天大雾)。放在今天来看,绝对的搅基王道片啊,只是当年大家还都比较单纯罢了……

anyway,大搜查线是一部打工J.C的日常生活的电视剧。虽然也有破案,但是破案完全是次要的,传统的方法,没有精心设计的密室,也没有复杂的犯罪手法,但却是最真实的。片中搞笑部分很多,值得慢慢回味。

——————————————————————————————————————————————————————————————————————————

相比大搜查线,《神探伽利略》就完全不一样了。主角是个副教授(真的只是副教授嘛?那教授不得nb翻天),因为受到成为J.C的大学同学的委托然后辅助破案,然后就上钩了一直被要求协助破案……对找出罪犯没有任何兴趣,只关注手法,因此都是奇怪的案件,比如某人脑袋突然自焚啦,比如月亮从西边升起啦,比如苍老师无外力作用猝死啦(?)。最初看《伽利略》是看了《嫌疑人X的献身》,觉得好奇妙的推理和逻辑啊,于是一发不可收拾,一下看完了全部的TV,包括刚刚完结的TV版第二季。作为物理学副教授,当然要以实验为主啦,所以片中经常出现汤川学副教授为了重现bug(大雾)于是做了很多实验,一次次失败后终于成功的片段,这告诉我们:失败是成功之母,你没那么多经费或者没人报销就不要投身物理学了(大雾)。

虽然主人公有很强的逻辑思维能力(智商),但是情商基本为0,以至于送别自己喜欢的妹子时送的是锗(碳硅锗锡铅),原子排列和钻石一样。至于为什么不送钻石么,是因为之前有个罪犯(也是个高智商的男子)对女主角示好并送了女主硅做成的挂饰。因为犯了大忌(敢抢男主的妹纸,必须死),所以犯了事被抓起来了,而男主觉得至少得送个更高级的,于是送了锗……多么奇怪的逻辑啊,直接送个钻石女主就归你了啊!~不过第二季里面倒是表现了一些他和第一季女主的CP,于是第二季的女主吉高由里子无论怎么卖萌卖肉(你没看错)都吸引不了男主的目光了。悲剧啊~

最奇葩的还数男主角每次灵光一闪时的行动:找一块大的地方写一堆公式,然后作沉思状。至于公式内容么,其实和案件手法没半毛线关系,某一集他自己也说了:我只是默写了某初中数学的一个公式而已。。。所以日本人的初中数学都学了啥呀!

anyway,伽利略的看点是男主很帅(福山雅治大叔~),以及案件手法的物理还原很精彩。娱乐性不及大搜查线,但是吸引程度相当。

——————————————————————————————————————————————————————————————————————————
结论就是:一个月就看了两部日剧这么多集外加这么多剧场版,难怪paper中不了!给我乖乖学术去!