使用 gitk 跟踪 git 项目源代码
看源代码是学习编程最快、最有效的方法之一,在 Linux 开源的大环境下,研究源代码就更加容易了。面对一个大一点的项目,我们可能无从下手,那么,何不从其雏形阶段开始研究呢?
我现在就在研究 Tualatrix 兄的 ubuntu-tweak 的源代码,以前 ubuntu-tweak 托管于 Google Code 的时候,Google Code 对各版本差异分析得很清楚,然而转向 github 之后,限于网速,看起来很不方便。
有什么跟踪本地 git 项目源代码的工具呢?diff 显然不是最好的方法,尤其涉及到文件移位之类的问题时。
Tualatrix 兄用的是 gitg,可是我用起来总是感觉缺点什么的样子,而且经常会莫名其妙的崩溃。偶然看 git 官方文档时,认识了 gitk,似乎是官方提供的工具,用起来真是越来越顺手。
先看一下两个软件的对比图:
gitk 基于 tk/tcl,所以用之前要安装这两个包,由于是官方软件,安装 git 时就会自动安装,不必另行安装。
从图中可以看出,基于 Gtk+ 的 gitg 界面更加漂亮,代码差异的彩色背景更加显眼,相比之下,基于 tk 的 gitk 显然简陋许多,大概 gitg 的作者也就是想写个 gitk 的 Gtk+ 版本吧。
不过,仔细看的话,就可以看出很多不同来,比如,中间的横条空间,gitg 是用作显示 Commit 的详情,这显然是浪费了宝贵的屏幕空间,尤其对于宽屏用户来说。
相对地,gitk 虽然中间的空间也用了,不过放置的却是实用的搜索功能。千万不要小看这个搜索条,它不但可以搜索 Headline、Comments、Author、Committer,还可以搜索哪些 Commit 对某些文件进行了修改,并且支持正则表达式、大小写匹配。
再来看一下 diff 功能,gitk 也比 gitg 强上很多,不但可以选择查看差异、新版、旧版的代码,还支持忽略空白符,设定 diff 周边行数。不要小看这个功能,在查看源代码的时候,这个功能对于理解上下文是很重要的。
如果这么强大的差异功能你还不满意,或者觉得视野空间太小的话,还可以右击文件,选择 External diff 来调用 meld 查看,当然前提是你安装了 meld。
右击文件,还可以对该文件加上高亮,这样标记已经读懂的文件比较方便。
通过这些介绍,可以看出,相比 gitg,gitk 更加成熟,功能更加强大。
默认启动 gitk 是打开 master 分支,如果想要查看其他分支,使用 gitk 分支名 即可,比如:
gitk origin
gitk 的命令行还有很多用法,详见 git 相关文档。
其实,gitk 只是 git gui 中的一个小工具,在命令行输入:
git gui
可以发现更多功能,当然,有些功能就不如终端下方便了。下面是 git gui 的效果:
关于 C++ 中模板类(Template Class)在多文件中的问题
最近 C++ 学到模板类了,老师要做一个模板类的题目。
一直以来我们都是保持着类声明和类实现分别写在头文件和 CPP 文件中这个不错的习惯,这次也没有例外,然而这次问题却出来了。
先是在 G++ 中提示:
undefined reference to `Array::Array(int, int const*)'
移到 VC++ 6.0 后又提示:
ex_08_1.obj : error LNK2001: unresolved external symbol "public: __thiscall Array<int>::~Array<int>(void)" (??1?$Array@H@@QAE@XZ)ex_08_1.obj : error LNK2001: unresolved external symbol "public: __thiscall Array<int>::Array<int>(int,int const *)" (??0?$Array@H@@QAE@HPBH@Z)
到底是怎么回事呢?老师说是编译器的 BUG,我却觉得没那么简单。 汗一个……VC++ 上更不用说了……
搜索了一下,才发现,C++ 中模板类(或者叫“类模板”)的声明和实现和普通类是不同的,模板类的声明有两种模式:包含编译模式和分离编译模式。
包含编译模式就是把声明和实现写在同一个文件中;分离编译模式当然就是写在不同文件中,不过用这种形式的时候,要在类的声明前加上 export 关键字。
我在 G++ 上试了一下,出现:
警告:关键字‘export’未实现,将被忽略
C++ 真是个复杂的东西,还是写在一个文件里吧……
数字图像处理(四)——均值滤波
上次提到产生高斯噪声的算法,我们知道,椒盐噪声是可以通过中值滤波来修复的,高斯噪声也可以通过均值滤波来还原。
顾名思义,均值滤波也是构建一个 n*n 的模板,然后取其平均值来替代模板中间的值。这样做出的效果明显不如用中值滤波修复椒盐噪声的效果好,不过当 n 取很大值的时候,图片看起来像是高斯模糊,不知道是不是一个原理……
看效果,n=3 时:
n=11 时:
算法更加简单,有以前的基础不成问题:
BmpPixmap &
BmpPixmap::mean_filter (int n)
{
assert (n >= 3 && n % 2);
int ii, jj, nn, sum [3];
BmpPixmap *temp = new BmpPixmap (*this);
for (i = n / 2; i < height - n / 2; i++) {
for (j = n / 2; j < width - n / 2; j++) {
for (nn = 0; nn < 3; nn++) {
sum [nn] = 0;
}
/*-----------------------------------------------------------------------------
* Calculate the average of the model.
*-----------------------------------------------------------------------------*/
for (ii = i - n / 2, nn = 0; ii <= i + n / 2; ii++) {
for (jj = j - n / 2; jj <= j + n / 2; jj++, nn++) {
sum [0] += pdata [ii][jj]->get_blue ();
sum [1] += pdata [ii][jj]->get_green ();
sum [2] += pdata [ii][jj]->get_red ();
}
}
temp->pdata [i][j]->set (sum [0] / (n * n), sum [1] / (n * n), sum [2] / (n * n));
}
}
return *temp;
} /* ----- end of method BmpPixmap::mean_filter ----- */
数字图像处理(三)——高斯噪声
与椒盐噪声相似,高斯噪声(gauss noise)也是数字图像的一个常见噪声,产生该噪声的算法也很简单。
上次说过,椒盐噪声是出现在随机位置、噪点深度基本固定的噪声,高斯噪声与其相反,是几乎每个点上都出现噪声、噪点深度随机的噪声。
该噪声效果如下:
这个算法比较简单,需要注意,颜色值不要超出范围(0-255),不然效果很可怕……
代码如下:
BmpPixmap &
BmpPixmap::gauss (int level)
{
assert (level >= 0);
BmpPixmap *temp = new BmpPixmap (*this);
int k, rand_temp, pixel [3];
/*-----------------------------------------------------------------------------
* Init the random seed with time.
*-----------------------------------------------------------------------------*/
srand (time (NULL));
/*-----------------------------------------------------------------------------
* Salt & Pepper.
*-----------------------------------------------------------------------------*/
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
rand_temp = rand () % level - level / 2;
pixel [0] = temp->pdata [i][j]->get_blue () + rand_temp;
pixel [1] = temp->pdata [i][j]->get_green () + rand_temp;
pixel [2] = temp->pdata [i][j]->get_red () + rand_temp;
for (k = 0; k < 3; k++) {
if (pixel [k] < 0) {
pixel [k] = 0;
} else if (pixel [k] > 255) {
pixel [k] = 255;
}
}
temp->pdata [i][j]->set (pixel [0], pixel [1], pixel [2]);
}
}
return *temp;
} /* ----- end of method BmpPixmap::gauss ----- */
数字图像处理(二)——中值滤波
中值滤波(median filter)是一种有效消除椒盐噪声的算法。
基本原理是,对图像中所有点进行遍历,对于每个点,取以其为中心的 n * n 的矩形区域,对矩形区域中点的灰度值进行排序,取其中间值替换当前点。
这样,如果这个点灰度值与周围点相差较大的话,就可以将其平滑化。
当然,这里要求 n 是个大于 1 的奇数。
在这里,我对算法进行了优化,使只有当前点是矩形区域灰度值的最大或者最小值的时候才进行替换,这样效果好了很多。
原始图像:
椒盐噪声:
中值滤波后:
可以看到,图像损失很小,只有边缘处有小的细节损失。同时,由于所加的噪点比较密集,少数地方仍然有噪点,这是因为矩形区域噪点太多,以至于中值本身也是个噪点了。
源代码:
BmpPixmap & BmpPixmap::median_filter (int n) { assert (n >= 3 && n % 2); int ii, jj, nn; Byte model [3][n * n]; BmpPixmap *temp = new BmpPixmap (*this); for (i = n / 2; i < height - n / 2; i++) { for (j = n / 2; j < width - n / 2; j++) { /*----------------------------------------------------------------------------- * Put n*n pixels around current pixels to the model. *-----------------------------------------------------------------------------*/ for (ii = i - n / 2, nn = 0; ii <= i + n / 2; ii++) { for (jj = j - n / 2; jj <= j + n / 2; jj++, nn++) { model [0][nn] = pdata [ii][jj]->get_blue (); model [1][nn] = pdata [ii][jj]->get_green (); model [2][nn] = pdata [ii][jj]->get_red (); } } /*----------------------------------------------------------------------------- * Sort the model. *-----------------------------------------------------------------------------*/ qsort (model [0], nn, sizeof (Byte), cmp_Byte); qsort (model [1], nn, sizeof (Byte), cmp_Byte); qsort (model [2], nn, sizeof (Byte), cmp_Byte); if (pdata [i][j]->get_blue () == model [0][nn - 1] || pdata [i][j]->get_blue () == model [0][0] || pdata [i][j]->get_green () == model [1][nn - 1] || pdata [i][j]->get_green () == model [1][0] || pdata [i][j]->get_red () == model [2][nn - 1] || pdata [i][j]->get_red () == model [2][0]) { temp->pdata [i][j]->set (model [0][nn / 2], model [1][nn / 2], model [2][nn / 2]); } } } return *temp; } /* ----- end of method BmpPixmap::median_filter ----- */
C++ 中出现“不能将成员函数声明为有静态链接“的解决方法
类中遇到快速排序,准备把排序函数声明为静态的,于是有了以下代码:
class BmpPixmap{…… static int cmp_Byte (const void *p1, const void *p2);……}; /* ----- end of class BmpPixmap ----- */
static intBmpPixmap::cmp_Byte (const void *p1, const void *p2){ return (* (Byte *) p1 - * (Byte *) p2);} /* ----- end of method BmpPixmap::cmp_Byte ----- */
结果出现了错误:
这个是因为声明的时候已经提过是静态的了,实现的时候就不能再说一遍了,把实现函数的 static 去掉即可。不能将成员函数‘static int BmpPixmap::cmp_Byte(const void*, const void*)’声明为有静态链接
数字图像处理(一)——椒盐噪声
椒盐噪声(salt & pepper noise)是数字图像的一个常见噪声,产生该噪声的算法也比较简单。
椒盐,按我的理解,椒就是黑,盐就是白,椒盐噪声就是在图像上随机出现黑色白色的像素。
那么传入两个参数,分别为黑白像素在图像上所占比例,就可以对图像进行修改。
我们可以使用 srand 函数,根据 time 产生一个随机种子(以免每次随机的结果相同),然后使用 rand 函数产生随机数,rand 产生的随机数是 0 到 RAND_MAX 之间的整数,可以通过使用 double (rand ()) / RAND_MAX 产生一个 0 到 1 之间的浮点型。
这样,当这个随机数小于 pepper 时,就把该点调黑,大于 1 - salt 时,就把该点调白,就可以产生随机的椒盐噪声了。
效果如图:
源代码:
#include #include #include "bmp_pixmap.h" /* *-------------------------------------------------------------------------------------- * Class: BmpPixmap * Method: salt_pepper * Description: Add salt and pepper noise to the pixmap. *-------------------------------------------------------------------------------------- */ void BmpPixmap::salt_pepper (double salt, double pepper) { double temp; /*----------------------------------------------------------------------------- * Salt & Pepper should be between 0 and 1. *-----------------------------------------------------------------------------*/ salt -= int (salt); pepper -= int (pepper); /*----------------------------------------------------------------------------- * Init the random seed with time. *-----------------------------------------------------------------------------*/ srand (time (NULL)); /*----------------------------------------------------------------------------- * Salt & Pepper. *-----------------------------------------------------------------------------*/ for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { temp = double (rand ()) / RAND_MAX; if (temp > 1 - salt) { pdata [i][j]->set (255, 255, 255); } else if (temp < pepper) { pdata [i][j]->set (0, 0, 0); } } } return ; } /* ----- end of method BmpPixmap::salt_pepper ----- */
CMake 生成动态链接库的方法
使用 CMake 管理程序项目真的很方便,现在感觉 CMake 已经是编程的一部分一样。
上次说的数字图象处理的实现,当然也是使用 CMake 进行管理。
然而编着编着,却觉得把源码全放在一个目录里是件很恼人的事情,同时也不利于测试和再利用,于是产生了把 BMP 相关类作成一个动态链接库的想法。
CMake 做到这一点很简单。
首先,把所有要做成库的源代码放在一个目录里,比如我这里叫做 bmp_pixmap ,然后在这个目录下建立 CMakeLists.txt,加入以下内容:
SET (SRC_LIST bmp_info_header bmp_file_header bmp_pixel bmp_pixmap bmp_pixmap_fill bmp_pixmap_noise_salt_pepper) ADD_LIBRARY (bmp_pixmap SHARED ${SRC_LIST})
其中 SRC_LIST 是源文件列表,bmp_pixmap 是库的名称,也就是 libbmp_pixmap,SHARED 表示动态库,静态的话只需要改成 STATIC 即可。
然后,对于调用动态库的源文件 main.cpp 所在的目录,比如我这里是 bmp_pixmap 目录的上级目录 src ,也要建立一个 CMakeLists.txt,加入以下内容:
ADD_SUBDIRECTORY (bmp_pixmap) LINK_DIRECTORIES (bmp_pixmap) SET (SRC_LIST main) ADD_EXECUTABLE (main ${SRC_LIST}) TARGET_LINK_LIBRARIES (main bmp_pixmap)
因为 src 是 bmp_pixmap 的父目录,所以加上 ADD_SUBDIRECTORY 指令,LINK_DIRECTORIES 则指明链接库所在位置,TARGET_LINK_LIBRARIES 表示对目标 main 链接 libbmp_pixmap 这个库。
最后,项目根目录下的 CMakeLists.txt 是这样的:
CMAKE_MINIMUM_REQUIRED (VERSION 2.6) PROJECT (DIP) ADD_SUBDIRECTORY (src bin) ADD_SUBDIRECTORY (config)
这样就可以编译了。
可见,CMake 管理项目所需要写的配置文件十分之少,常用的命令也就那么几个,相比 AutoTools ,实在可以说是极度傻瓜化了……
用 CMake ,我骄傲哇~
试试用 C++ 实现数字图像处理
看到同寝的在学数字图像处理,好像很好玩啊……
正好正在学 C++,决定用 C++ 实现一下(他原来用的是 C、C++ 混编,代码惨不忍睹……)。
C++ 真的是个很麻烦的东西啊,定义一个类要费那么长时间,读写文件也没有 C 那么轻松,真怀疑它的用处了……
还是 Python 最简洁,C 我也很喜欢,真不明白那些自己用 C++ 写程序的人,怎么受得了这种笨重的搭建速度……现在做 C++ 作业,一个没什么用的小程序都要写一下午……
不说了,代码在 http://github.com/iven/dip/
写了个提取手机屏幕数据的程序 fb2bmp
我的 E680i 已经买了三年了,一直想要研究它,却苦于技术不足。网上的手机程序,大多是二进制包,想要学习也没有办法。
以前在 Windows 下,甚至可以通过一个叫做 MotoVision 的程序,把手机当摄像头用,可惜根本找不到源代码……
昨天查了查资料,发现小 i 的屏幕色深是 16 位的,也就是每个像素点的颜色值存储为两个字节,那么整个屏幕的数据就是 320*240*2/1024=150 KB,每个像素点分为 RGB 三色,存储方法为 RRRRRGGG GGGBBBBB (16 位 565 方式),那么根据最近学的一点数字图象处理的知识,很容易就可以把它转换成 BMP 格式。
小 i 的操作系统是 Linux,屏幕设备文件是 /dev/fb0,也就是 framebuffer,这也是我把程序叫做 fb2bmp 的原因。只要通过 telnet 把 /dev/fb0 拷贝到电脑上,得到的就是拷贝瞬间的屏幕数据。
fb2bmp,可以将 fb0 的数据转换成 16bit 和 24bit 的 BMP 文件,16bit 比较好办,加上个文件头即可,需要注意的是要加上 3 个 DWORD 类型的掩码,表示 RGB 三种颜色分别占哪几位。24bit 则需要对数据进行移位,然后再加上文件头。
项目已经放在 http://github.com/iven/e680_fb2bmp/ ,有兴趣可以去看看。
补上图:











