更换邮箱地址

实在是太懒了,随便一拖,又是一个月没写过东西了……

新的一年开始了,在新的一年,肉壳要做的第一件改变就是更换自己使用多年的gmail地址为me@colinzhang.com……目的就是为了耍帅……

从几天起,所有给原gmail邮箱发邮件的朋友,都会收到一份邮箱更改通知。目前只有简体中文版,未来再添加英文和繁体中文版吧。不过估计会因为懒,拖一段时间……

新年了,祝大家新年快乐……刚看了一下草稿箱,有几篇文章还没有编辑完,近期就写一个Github在Eclipse下的简易使用指南吧……

另外,这段时间,我还申请了一个Github账号,欢迎大家follow……

https://github.com/Rokeer

Java,使用Jung包读取GraphML数据

最近在做一个Project,跟微博啥的有关,肉壳的工作就是给微博用户打分,看谁最重要,基本上就是简单的修改了一下Page Rank算法和HITS算法。不过第一步就是要把搭档给我的数据读出来。因为都是用户关系用网络表示,为了方便处理,前期操作都是把数据写在GraphML格式文件中。GraphML也是一种标记语言,跟HTML,XML什么的差不多,里面都是一些标签。有兴趣的话,大家自己Google一下就可以了……

搭档们用的都是R和Python,里面有包可以直接读GraphML,但是木讷的我不会用R和Python,只能在Java里找相关的包,结果还真找到一个叫Jung的包。这个包功能非常强大,可以对GraphML增删改查,还可以计算网络的PR,HITS什么的,可谓非常强大……不过今天就讲一些简单的,就是如何将GraphML文件中的数据读出来,就是这么简单……

首先,我们看一下GraphML的文件格式,

<graphml xmlns="http://graphml.graphdrawing.org/xmlns"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
  <key id="d0" for="node" attr.name="color" attr.type="string">
    <default>yellow</default>
  </key>
  <key id="d1" for="edge" attr.name="weight" attr.type="double">
	<default>0.0</default>
  </key>
  <graph id="G" edgedefault="directed">
    <node id="n0">
      <data key="d0">green</data>
    </node>
    <node id="n1"/>
    <node id="n2">
      <data key="d0">blue</data>
    </node>
    <node id="n3">
      <data key="d0">red</data>
    </node>
    <node id="n4"/>
    <node id="n5">
      <data key="d0">turquoise</data>
    </node>
    <edge id="e0" source="n0" target="n2">
      <data key="d1">1.0</data>
    </edge>
    <edge id="e1" source="n0" target="n1">
      <data key="d1">1.0</data>
    </edge>
    <edge id="e2" source="n1" target="n3">
      <data key="d1">2.0</data>
    </edge>
    <edge id="e3" source="n3" target="n2"/>
    <edge id="e4" source="n2" target="n4"/>
    <edge id="e5" source="n3" target="n5"/>
    <edge id="e6" source="n5" target="n4">
      <data key="d1">1.1</data>
    </edge>
  </graph>
</graphml>

首先,key标签定义了Vertex和Edge的meta信息,以便以后获取到这些信息后将他们读出来。<graph id=”G” edgedefault=”directed”>定义里这个图是个有向图,不过我代码里用的是个无向图(undirected),大家使用的时候需要注意一下。之后运行一下下面的代码就好了。

GraphMLReader<undirectedgraph, Node, Edge> gmlr = new GraphMLReader<undirectedgraph, Node, Edge>(new VertexFactory(), new EdgeFactory()); //创建一个GrahpML的Reader
final UndirectedGraph graph = new UndirectedSparseMultigraph();

gmlr.load(filename, graph); //读取graph,并将内容写进graph对象

BidiMap vertex_ids = gmlr.getVertexIDs(); //获取Vertex的id
<Map> edge_meta = gmlr.getEdgeMetadata(); //获取Edge的内容

//graph对象此时只有Vertex和边的连接关系,我们需要把Vertex和Edge的附加信息写进去
for (Node n : graph.getVertices()) {
	n.setUserID(vertex_ids.get(n));
	n.setPageRank(0.2);
	n.setAuth(1);
	n.setHub(1);
}
for (Edge e : graph.getEdges()) {
	e.setCapacity(Double.parseDouble(edge_meta.get("d1").transformer.transform(e))); //读取的d2信息是在GraphML文件里定义的
}

经过这么一番简单操作,graph对象就已经包含了各个Vertex和Edge的关系了……就是这么简单……Vertex和Edge对象是自己写的,下面再贴个NodeFactory和EdgeFactory的代码。

class VertexFactory implements Factory {
	private int n = 0;

	public Node create() {
		return (new Node(n++));
	}
}

class EdgeFactory implements Factory {
	private int e = 0;

	public Edge create() {
		return (new Edge(e++));
	}
}

需要注意的时候,无向图读取以后,不知道是不是因为我不会用,每条Edge的from和target读不出来,用有向图就能读出来,好奇怪……不过大家到也不用担心,因为graph有个方法叫getEndpoints,可以获取到特定边的两个顶点,然后再操作就可以了……

另外,最近在研究GitHub,虽然早就注册了,但是一直没用过……现在想想,太狗了……

关于Apple ID转区的两个小问题

首先,如果你的苹果设备越狱了,而且觉得应用本来就不应该花钱购买的话,麻烦你关掉这个页面,因为我可能会说一些中伤你们的话,所以最好还是不要看为好,省得你心里不舒服,骂起来了的话,我心里也不舒服……

大家都知道,苹果的App Store中的应用在中国大陆区的应用相比较其他国家会少了很多,而且音乐啥的也不能购买,如果你觉得音乐也不应该花钱购买的话,麻烦你关掉这个页面,因为我可能会说一些中伤你们的话,所以最好还是不要看为好,省得你心里不舒服,骂起来了的话,我心里也不舒服……

对于这个问题,很多人的解决方法就是开两个Apple ID,一个美国区一个中国区,然后切换使用。不过这种办法对于懒人并且有一些强迫症的肉壳来说实在是有点心里不舒服。所以前段时间决定把Apple ID转来香港区,因为无论是音乐、应用,都还是挺全的了。

不过在转区的时候,遇到的第一个问题就是,大陆区当时账号充值的余额没有花完,必须花完了才能转区,但是操蛋的苹果,如果不用信用卡的话,充值只能选择50,100,200,300。说实话,对于苹果里那些有零有整的应用价格,很难完全把这些充值花完,可是操蛋的苹果又不给退款,所以只能在最后剩下几块钱的时候,绑定信用卡,然后再买个应用,用信用卡支付剩余的钱。然后就可以安心转区了。

转来香港区,第一时间就是买了GTA III的十周年纪念版,然后给iPad mini装了几个以前用的应用,但是在查阅异构项目中,会遇到一个很奇怪的问题,就是,无法找到在大陆区已经购买的并在香港区重新购买的应用。今天就此问题,问了一下苹果的客服,得到的答案,以我的理解是这样的:1,如果在其他地区购买的应用,如果已经安装在设备中,转区后不能直接升级。2,如果在转后地区重新下载该应用,则可以升级该应用。3,只要原地区该应用还在继续上架,则在新地区可以免费下载该应用,无需重新购买。

所以,如果大家想转区,就尽情的转吧,就是转完之后,安装之前安装过的应用需要点功夫罢了,不过,那又怎样?

C#,用基本全局阈值法求图像二值化时的阀值

最近在学习Emgu CV,并重新复习C#,在图像处理中,有一个过程叫“二值化”,简单来说就是将图片的每个像素转换成1或0,以方便后面的边缘检测,但是在二值化的过程当中,有个很复杂的问题就是确定二值化的阀值,怎么获得这个阀值呢?肉壳在网上找了一些方法,其中一种叫基本全局阀值法。SkySeraph在他的文章中还提到了其他几种方法,不过都是用C++实现的,因为我比较低端不会C++,所以一直能抽一种自己需要的方法,修改成C#语言了……

因为今天也是我第一次用Emgu,所以不确定最终获得阀值的使用方法是否正确,大家帮忙看一下吧,错了别怪我……

/*=====基本全局阈值法=======*/
int BasicGlobalThreshold(int[] pg, int start, int end)
{
    int i, t, t1, t2, k1, k2;
    double u, u1, u2;
    t = 0;
    u = 0;
    for (i = start; i < end; i++)
    {
        t += pg[i];
        u += i * pg[i];
    }
    k2 = (int)(u / t); // 计算此范围灰度的平均值    
    do
    {
        k1 = k2;
        t1 = 0;
        u1 = 0;
        for (i = start; i <= k1; i++)
        { // 计算低灰度组的累加和
            t1 += pg[i];
            u1 += i * pg[i];
        }
        t2 = t - t1;
        u2 = u - u1;
        if (t1 != 0)
            u1 = u1 / t1; // 计算低灰度组的平均值
        else
            u1 = 0;
        if (t2 != 0)
            u2 = u2 / t2; // 计算高灰度组的平均值
        else
            u2 = 0;
        k2 = (int)((u1 + u2) / 2); // 得到新的阈值估计值
    } while (k1 != k2); // 数据未稳定,继续
    return (k1); // 返回阈值
}

这个是基本算法pg是直方图,start和end表示直方图的起始位置和结束位置,这段代码基本没改动过,只是把C++里的指针给弄没了……

//gray_image是变量
int i, thre;
int[] pg = new int[256];
for (i = 0; i < 256; i++) pg[i] = 0;
int w = gray_image.Width; // 获得图像的长和宽
int h = gray_image.Height;
//直方图统计
int[] hist_size = new int[1] { 256 }; // 建一个数组来存放直方图数据
IntPtr HistImg = CvInvoke.cvCreateHist(1, hist_size, Emgu.CV.CvEnum.HIST_TYPE.CV_HIST_ARRAY, null, 1); // 创建了一个空的直方图
IntPtr[] inPtr1 = new IntPtr[1] { gray_image };
CvInvoke.cvCalcHist(inPtr1, HistImg, false, System.IntPtr.Zero); // 计算inPtr1指向图像的数据
for (i = 0; i < 256; i++)
{
    pg[i] = (int) CvInvoke.cvQueryHistValue_1D(HistImg, i); // 将直方图数据放入数组
}
thre = BasicGlobalThreshold(pg, 0, 256); // 确定阈值
CvInvoke.cvThreshold(gray_image, gray_image, thre, 255, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY); // 二值化

大概就是这样……

做一个不木讷的程序员

哈哈,曾经被Louis提醒过,说程序员容易变得沉闷和木讷,想必高老师、老王和李老师都有印象吧?自从那次谈话,我就下决心不要做一个木讷沉闷的人……但是程序员还是得做,不是?

这个博客在刚刚开始写的时候本来想写一些技术文章的,后来文章越来越不技术,因为自己根本就没啥技术……虽然学了4年计算机了,但是,感觉自己还是跟4年前差不多,因为有时根本记不起来自己以前都做过啥,怎么温故知新?所以,从今天起,肉壳决定开始总结一些技术性资料、话题,写在博客里,也当是记笔记了,未来好复习。当然,我绝对不会抄袭别人的文章,这点还是可以放心的……如果大家看到其他地方有我这里的文章,那肯定是他抄我的!狗日的……

作为一个新开端,蛋疼的再建立一个新分类,就叫木讷技术宅?另外,由于戏五毛的对象已经去世了,所以这个分类也没啥留下的必要了,所以跟记日本分类合并了……

最近在用Emgu做一个车牌定位程序,所以新分类可能会从这个程序入手。现在肉壳正在抱着paper读呢……哭了……