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读呢……哭了……

iPad mini到货咯!这不是评测……

经过当时订购iPad mini时的一波三折,真的要给这玩意儿跪下了,不过2号开始发售,7号就拿到自己的机器着实感觉很好,也是自己第一次追苹果的玩意儿……感谢龙哥帮忙在家收快递……虽然之前有iPad 2和iPod photo,但也都是些机缘巧合的机会才买的。所以这边文章就发几张图显摆显摆而已。都说了不是评测文章了……

特意在到货当天去Apple Store买了个Smart cover,深灰色,因为背壳是黑的,感觉配其他颜色的cover太狗了……只有浅灰和深灰还行……

这就是正面咯,随便装了几个应用……话说,由于终于搞到信用卡了,而且未来个人发展方向是以香港为重,所以把Apple ID的区域转成香港了,值得说一下的是,App store大陆区是可以充值人民币的,但是比较狗的是,充值只能按规定限额充,我没记错的话是50,100,200,300和500?反正就是一些很难受的价格,让你买完自己想买的应用后,还剩下那么点零钱,可是这点零钱是不能退款的,于是就恶性循环了……这点虽然很不合理,但是Apple在大陆就是这么个情况,只能再绑定信用卡之后连带着花光最后的余额。只有将余额花光才能转区……

由于转区之后,商店不同,导致原来在大陆购买的应用都看不到了,虽然旧的应用还能用,但是没办法从香港的App store更新,所以才有双Apple ID的解决方案,就是一个号买大陆,另一个号绑定在其他国家,这样就能在需要更新应用的时候,来回切换账号无压力。具体操作,如果大家有兴趣就留言,留言多了就写个教程啥的。但是我已经真心想放弃大陆的ID了,所以那些钱就算捐给慈善了,反正花的也不多……

背面的黑色金属,挺好看,手感还不错,没什么可说的……

由于是在官网订货,可以免费刻字,不过因为在香港,只有繁体字,所以就用繁体了,是不是有种肉壳的胡思八道的官方纪念品的感觉?那就把这玩意儿送给创始人吧……好球……