Posted on 06-07-2009
Filed Under (技术) by waterlin

最近写了一个神经网络的数字图像识别的程序,刚一开始,被位图的读写搞得晕头转向的。想当年还蛮熟悉的,太久没弄了,知识总是会忘记的!现在写下来,算是记一记笔记,以后再回忆就不会那么痛苦了!

位图文件由三部分组成:文件头 + 位图信息 + 位图像素数据,具体的结构如下图所示:

1、位图文件头。位图文件头主要用于识别位图文件。以下是位图文件头结构的定义:

typedef struct tagBITMAPFILEHEADER { // bmfh
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;

其中的bfType值应该是”BM”(0x4d42),标志该文件是位图文件。bfSize的值是位图文件的大小;bfOffBits是指从BITMAPFILEHEADER开始,直到位图像素数据存储点的内存大小(距离),即用bfOffBits – sizeof(BITMAPFILEHEADER)就能得到BITMAPINFO在位图中实际所占有的空间大小

2、位图信息中所记录的值用于分配内存,设置调色板信息,读取像素值等。

以下是位图信息结构的定义:

typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;

可见位图信息也是由两部分组成的:位图信息头 + 颜色表。

2.1 位图信息头

位图信息头包含了单个像素所用字节数以及描述颜色的格式,此外还包括位图的宽度、高度、目标设备的位平面数、图像的压缩格式。以下是位图信息头结构的定义:

typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;

2.2 颜色表

颜色表一般是针对16位以下的图像而设置的,对于16位和16位以上的图像,由于其位图像素数据中直接对对应像素的RGB(A)颜色进行描述,因而省却了调色板。而对于16位以下的图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个索引到调色板去取得相应的RGB(A)颜色。颜色表的作用就是创建调色板。

颜色表是由颜色表项组成的,颜色表项结构的定义如下:

typedef struct tagRGBQUAD { // rgbq
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;

其中需要注意的问题是,RGBQUAD结构中的颜色顺序是BGR,而不是平常的RGB。

3、位图数据

最后,在位图文件头、位图信息头、位图颜色表之后,便是位图的主体部分:位图数据。根据不同的位图,位图数据所占据的字节数也是不同的:对于8位位图,每个字节代表了一个像素;对于16位位图,每两个字节代表了一个像素;对于24位位图,每三个字节代表了一个像素;对于32位位图,每四个字节代表了一个像素;而对于单色位图来说,每一位代表一个像素。

这里有两点特别需要强调的:

1) 位图数据的字节数组是从图像的最下面一行开始逐行向上存储的,所以在选取源位图的实际范围的时候需要特别注意!

我习惯先用一个函数,把位图数据读成一个和位图结构、方向相似的矩阵,即最先读出的位图数据,是矩阵的最后一行。

2) 存取位图数据的字节数组有个问题需要引起开发人员的注意:字节数组中每个扫描行的字节数必需是4的倍数(即是32位的倍数),如果不足要用0补齐。

举例说,我有一个20 * 20个点的单色位图。在保存位图的时候,第一行有20个点,虽然只需要用20位的数据来保存就可以了;但是,这个时候,不足32位,则需要用12位0来补足。

这样,总共需要 20 * (20 + 12) = 640 位来保存这一行,即需要用640/8 = 80个字节来保存整幅图像。

VC知识库里的这篇文章提供了一个位图操作的类,可以借鉴一下!

(0) Comments    Read More   
Posted on 29-06-2009
Filed Under (技术) by waterlin

据说绿坝里的图像识别用的是OpenCV这个库,作为图像处理专业出身的我,免不了对这个东西产生了一些兴趣。下载OpenCV下来用一用,看看这个东西效果如何。

更多的信息,请访问OpenCV的Wiki站点,例如如何在VC里编译OpenCV的官方文档等等。

下面就是我在Windows XP下,用Visual Studio 2005来使用OpenCV库的设置步骤:

第一步,下载和安装OpenCV库,根据操作系统下载相应的版本。

第二步,把OpenCV库的可执行文件路径加到系统的环境变量PATH里,在我这里是C:\Program Files\OpenCV\bin。

第三步,在Visual Studio 2005里进行必要的全局设置:

1) 在Visual Studio里,选择”Tools -> Options”;

2) 在弹出的对话框里,再选择”Projects -> VC++ Directories”;

3) 在上面的对话框里,从”Show Directories for”下拉框里选择”Library files”;

4) 在Library files列表里, 添加这样一个路径”C:\Program Files\OpenCV\lib”;

4.png

5) 从2)的对话框里选择”Include Files”下拉框,然后再添加以下目录:

“C:\Program Files\OpenCV\cv\include”
“C:\Program Files\OpenCV\cxcore\include”
“C:\Program Files\OpenCV\otherlibs\highgui”
“C:\Program Files\OpenCV\cvaux\include”
“C:\Program Files\OpenCV\otherlibs\_graphics\include”

5.png

6) 选择下拉框里的”source files”,然后把下面的路径加进去:

“C:\Program Files\OpenCV\cv\src”
“C:\Program Files\OpenCV\cxcore\src”
“C:\Program Files\OpenCV\cvaux\src”
“C:\Program Files\OpenCV\otherlibs\highgui”
“C:\Program Files\OpenCV\otherlibs\_graphics\src”

6.png

当然,你应该把上述路径替换成你自己的路径。就这样,Visual Studio 2005里的全局变量就配置好了。

第四步,完成了上述配置,就创建一个OpenCV工程来试一把。

创建一个名叫OpenCVHello的”Win32 Application”或是”Win32 console application”工程,如果想节省编译时间,建议把Precompiled header这个选项给选上。

把以下几个文件include进去,并且要放在stdafx.h文件后面,否则很可能会编译出错。

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

编译一下,应该可以成功。然后我们在主函数_tmain()输入一些OpenCV代码来试试:

IplImage *img = cvLoadImage(“Image.bmp”);
cvNamedWindow(“Image:”,1);
cvShowImage(“Image:”, img);
cvWaitKey();
cvDestroyWindow(“Image:”);
cvReleaseImage(&img);

编译一下,应该会提示一些链接错误的信息。这个时候,从”Project” -> “Properties”打开项目工程的属性,在”Linker” -> “Input” -> “Additional Dependencies”里添加下面这些lib库:

cxcore.lib cv.lib highgui.lib cvaux.lib cvcam.lib

7.png

这样应该就可以编译了。整个代码看起来就像这样:

8.png

以后有空再深入研究一下OpenCV库的更多用法。

(1) Comment    Read More   
Posted on 19-06-2009
Filed Under (技术) by waterlin

Turbo Vision库是一个tui库,在Windows下有很多种安装方法。你可以用Cygwin, MinGW+MSYS来编译。详细可以看看doc/install里的安装文档。

注意下载相应平台下的版本,Windows下,下载相应的BC++和MinGW版本;而Linux下或是Cygwin下,也有相应的版本。

在Windows下,可以在Cygwin里很简单地进行安装:

$ ./configure
$ make
$ make install

安装完了后,进到目录example里,再把这些例子编译一把:

$ make

如果编译成功了,就可以直接跑一跑这些例子了:

$./demo/demo.exe

(0) Comments    Read More   
Posted on 25-05-2009
Filed Under (技术) by waterlin

整天在自己的电脑上写代码,然后再用ftp上传到服务器(没办法,服务器没有SVN这种高级玩意)。每次上传都不知道哪个文件修改了,导致我得停下来检查一下哪些文件上传了,十分痛苦。

另外,自己在本地写的一些小程序,还是需要经常备份一下,以防止哪天脑残修改出了一大堆的错误回溯不了就麻烦了。

因此,很有必要在本地也搭建一个代码版本管理工具,来帮助我们进行代码、文档的管理工作。

推荐使用SVN作为代码管理工具,搭个svn server,客户端用Tortoise svn,可以整合在资源管理器上面,还可以试试搭一个trac,在线比较差异和查看更改很方便。

下面我们来看看如何在Windows下搭建一个subversion服务器来方便自己的工作。

1) 搭建一个subversion服务器

在Windows下,推荐使用VisualSVN。这个发行版本的安装最简单了,包含了所有我们需要的模块,如subversion,Apache以及一个控制终端。安装很简单,一步一步安装完成即可。

2) 安装一个svbversion的客户端

在Windows下推荐用TortoiseSVN,我不觉得在命令行下一行一行地敲svn命令是一件很开心的事~~

3) 管理你的内容

现在我们只要在VisualSVN里,创建一个代码Repositories,比如说,我现在要写一个Python的工程,创建一个名叫PythonCode的Repositories,设置好相关的属性后,我就用TortoiseSVN来check out这个Repositories。Check Out的地址就是TortoiseSVN在Repositories属性里提供给你的URL地址,类似于:

https://WWW-81ECC445A0F:8443/svn/PythonCode/

当然,你可以把计算机名换成localhost,即修改成如下地址:

https://localhost:8443/svn/PythonCode/

如果你喜欢用eclipse的话,用Subclipse作为svbversion的客户端也不错:

就这样,你在本地能清楚地看到你这次修改了哪些文件,只要把这些文件上传到服务器即可。这下就不用每次抓狂地回忆究竟修改了哪个文件!

(1) Comment    Read More   
Posted on 06-05-2009
Filed Under (技术) by waterlin

最近,一直在苦苦寻找一个最适合自己的bug追踪系统。我自己平时写的一些小工具,有一些bug需要追踪管理一下,用记事本显得格式太随意了,不好管理。

试了很多有名的工具,如Bugzilla,Mantis,感觉都太厚重了,团队用倒是蛮合适的。

后来想着用XML定义一个日志数据库,一个Bug开一个文件,这样可以详细记录Bug的内容及解决过程、方法等。再写一个前端,用来管理组织这些XML文件。但我个人的bug量不多,更多的时候,是随手写一点想法,这种XML严谨的组织方式,并没有让我觉得更轻松。

尝试着用Emacs Muse记录了一段时间,有一个缺点,就是我写下来的解决方法里,有很多是代码,如果我不加<verse></verse>标签,Muse会尽量地帮我重新转义一下。总的来说,Muse还是偏排版多一点,不适合于记录随想随写的东西。

最后,我发现用Perl的pod来做自己的bug追踪系统挺好的。Pod虽然是个文档系统,但是只要灵活地运用标签也是能做简单的bug追踪系统。Pod的优点是,当你不需要用命令的时候,直接输入你的内容即可,总体来说,比较简洁。

我的pod格式定义如下:

=pod

=head1 project 1

=head2 Bug #000001

=head3 Bug #000001的简单描述或标题

Bug #000001的详细描述,所有的有关内容。。

=head3 Bug Status::Fixed

=head3 Bug解决方法记录

=over indentlevel

=item 解决步骤一

解决步骤一的内容。

=item 解决步骤二

解决步骤二的内容。

=item Bug Fix summary

Solution of Bug #000001, the summary of this bug is:

Try to readcord the document in time and in style.

这里就写一写把Bug搞定后的总结。

=back

=head2 Bug #000002

=head3 Bug #000002的简单描述或标题

Bug #000002的详细描述,所有的有关内容。。

=head3 Bug Status::Active

=head3 Bug解决方法记录

=over indentlevel

=item 解决步骤一

解决步骤一的内容。

=item 解决步骤二

解决步骤二的内容。

=item Bug Fix summary

Solution of Bug #000002, the summary of this bug is:

Try to readcord the document in time and in style.

这里就写一写把Bug搞定后的总结。

=back

=head2 Bug #000003

=head3 Bug #000003的简单描述或标题

Bug #000003的详细描述,所有的有关内容。。

=head3 Bug Status::Suspended

=head3 Bug解决方法记录

=over indentlevel

=item 解决步骤一

解决步骤一的内容。

=item 解决步骤二

解决步骤二的内容。

=item Bug Fix summary

Solution of Bug #000003, the summary of this bug is:

Try to readcord the document in time and in style.

这里就写一写把Bug搞定后的总结。

=back

=cut

把上面的例子代码存成一个文档,比如说,我喜欢存为WaterBug.txt,后缀用.txt是为了方便用其它编辑器查看。

用pod2html的命令生成文档给其他人观看:

pod2html –infile WaterBug.txt –outfile WaterBug.html –title WaterBug

当然,你可以为这个文档写一个你自己的Style Sheet,生成一个打着你的logo的个性化文档:

pod2html –infile WaterBug.txt –outfile WaterBug.html –title WaterBug –css stylesheet.css

在定义我的pod格式时,我分别用ActiveSuspendedFixedOn-hold四种状态来标明Bug的状态,即”正在进行”、”还未开始”、”已经搞定”、”暂时放着”等四种状态,这些状态关键字都是以::开头进行标识。

以这些简单的标记来记录文档,我可以随手写在任何文本文件里,包括Google Docs这些在线文档,即使将来要转成其它格式的文档,也可以轻松地用perl来实现转换。

要查找特定状态的bug,只要搜索一下::Fixed或是::Suspended或是::Active或是::On-hold即可。

(1) Comment    Read More   
Posted on 07-04-2009
Filed Under (技术) by waterlin

如果要在Windows下写界面的话,有许多的C++界面库,例如VC++里自带的MFC库。但是,如果使用了这些库,当你要把你的界面程序移植到其它平台,那将是一件非常痛苦的过程。QT是一个非常优秀的C++界面库,跨平台、架构好、易使用。现在就简单介绍一下怎么在Windows下用MinGW和MSYS来编译QT程序。

1) 安装MinGWMSYS

2) 安装Qt

下载相应的安装文件,一路安装就OK了。安装完Qt后,在Windows系统的环境变量里添加Qt的路径,我这里是:

C:\Qt\4.4.3\bin

这样就可以在cmd里的任何位置使用Qt的命令了。

3) 把Hello World这段代码拷进去,Qt的帮助文件里有:

#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QPushButton hello(“Hello world!”);

hello.show();
return app.exec();
}

为方便编译,可以把这段代码的文件单独保存到一个文件夹里。

4) 用qmake来新建工程

qmake -project
qmake

在目标代码的文件夹里运行上面的两个命令,第一个命令会生成一个QTHello.pro的文件,第二个命令qmake会根据这个.pro文件来创建平台相关的makefile文件。

5) 在MSYS里跑make这个命令进行编译

如果编译顺利的话,就会在这个文件夹下面新建debug和release这两个子文件夹,里面放的是你make后生成的可执行文件。

(1) Comment    Read More   
Posted on 12-03-2009
Filed Under (技术) by waterlin

有的时候,我们在本地测试一些网络系统,需要绑定一个域名来进行测试(有的系统就只支持域名访问),但因为是测试用的机器,并不是真正的服务器,没有必要把真正的域名解析到测试机器的IP上。

这个时候,我们可以不用修改域名解析的记录,而修改浏览器所在机器的Hosts文件,指向你的Apache所在机器的IP,一样能出色的完成任务。

Linux的话,修改/etc/hosts文件。

Windows的话,Hosts文件的存放位置为:

Windows 95/98/Me             c:\windows\hosts
Windows NT/2000/XP Pro    c:\winnt\system32\drivers\etc\hosts
Windows XP Home             c:\windows\system32\drivers\etc\hosts

比如,你要把域名localhost.localdomain这个假域名解析到你内部网服务器的IP 10.67.6.54,你只要在Hosts文件里加上这么一句就可以了:

10.67.6.54     localhost.localdomain

根据Windows和Linux系统的规定,在进行DNS请求以前,系统会先检查自己的Hosts文件中是否有这个域名地址的映射关系。如果有则调用这个IP地址映射,如果没有再向已知的DNS服务器提出域名解析。也就是说Hosts的请求级别比DNS高。

灵活地使用这个Hosts文件,还能达到以下目的:

1) 加快域名解析

对于要经常访问的网站,我们可以通过在Hosts中配置域名和IP的映射关系,这样当我们输入域名,计算机就能很快解析出IP,而不用请求网络上的DNS服务器。

2) 方便局域网用户

在很多单位的局域网中,会有服务器提供给用户使用。但由于局域网中一般很少架设DNS服务器,访问这些服务要输入难记的IP地址,对不少人来说相当麻烦。现在可以分别给这些服务器取个容易记住的名字,然后在Hosts中建立IP映射,这样以后访问的时候我们输入这个服务器的名字就行了。

3、屏蔽网站

现在有很多网站不经过用户同意就将各种各样的插件安装到你的计算机中,有些说不定就是木马或病毒。对于这些网站我们可以利用Hosts把该网站的域名映射到错误的IP或自己计算机的IP,这样就访问不了。我们在Hosts写上以下内容:

127.0.0.1     屏蔽的网站的域名

0.0.0.0       屏蔽的网站的域名

这样计算机解析域名就解析到本机或错误的IP,达到了屏蔽的目的。

4、顺利连接系统

对于Lotus的服务器和一些数据库服务器,在访问时如果直接输入IP地址那是不能访问的,只能输入服务器名才能访问。那么我们配置好Hosts文件,输入服务器名就能顺利连接了。

最后要指出的是,Hosts文件配置的映射是静态的,如果网络上的计算机更改了请及时更新IP地址,否则将不能访问。

(1) Comment    Read More   
Posted on 24-06-2008
Filed Under (技术) by waterlin

最近Blogger被GFW封了,可是更奇怪的是,我用代理都上不了!

Blogger提示如下错误:

Server Not Found


Error 404

我觉得很奇怪,尽管被封了,可是用代理也应该要能上呀;即使上不了,也不可能是404这种错误吧。

研究了好久,最后用这种方法解决了:

把“在自定义域上发布”切换到”blogspot.com发布”上,修改一下,保存;然后再切换到“自定义域”,在高级设置里“您的域”填上”blog.waterlin.com”,保存。即重新做一次域名绑定的操作。

OK.肯定之前不小心改动了域的设置,现在一切恢复正常了。

(0) Comments    Read More   
Posted on 10-06-2008
Filed Under (技术) by waterlin

前段时间,在美国使用CVS的时候窘了一把。老美说上传了一个task给我,要我好好干。结果我cvs update一下,死活找不到新的文件,还跑回去跟老美理论。

事后cvs update –help一把,才知道应该用cvs update -d这个命令。

cvs update -d的含义:Build directories, like checkout does,即创建仓库里面存在而工作目录里面没有的目录。

通常,用cvs update的话,只作用于你工作目录里面已经存在的文件和目录。

以后要注意体会cvs各个命令的细微差别。

(0) Comments    Read More   
Posted on 24-04-2008
Filed Under (技术) by waterlin

我的域名是在cesky注册的,不知道为什么,这几天想修改DNS老是修改不成功,提示一些莫名其妙的错误。于是上网搜了一下答案:

cesky是二级平台,中间数据传输可能有问题,直接去域名管理平台即可。
新网:
www.paycenter.com.cn
万网:

http://diy.hichina.com/cgi-bin/login

新网互联:

http://mgt.dns.com.cn/

一般你注册域名的时候,会设有一个域名管理密码,你用你的域名作为帐号、域名管理密码作为密码,从而就可以登陆这些顶级平台直接管理你的域名了。不过,里面的操作比较危险,一定要小心。

(0) Comments    Read More