<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/windstorm" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/windstorm" type="application/rss+xml"></fs:self_link><lastBuildDate>Wed, 25 Apr 2012 07:53:33 GMT</lastBuildDate><title>WindStorm</title><description>computer，IT，Linux</description><image><url>http://www.feedsky.com/feed/windstorm/sc/gif</url><title>WindStorm</title><link>http://www.kunli.info</link></image><link atom:type="text/html">http://www.kunli.info</link><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/feed/atom/</id><link xmlns="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://www.kunli.info/feed/atom/"></link><generator xmlns="http://www.w3.org/2005/Atom" uri="http://wordpress.org/" version="3.0">WordPress</generator><pubDate>Wed, 25 Apr 2012 07:53:33 GMT</pubDate><item><title>Google Drive the Dropbox clone? Not at all</title><link atom:type="text/html">http://www.kunli.info/2012/04/25/google-drive-dropbox-clone/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1667</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2012/04/25/google-drive-dropbox-clone/">&lt;p&gt;People thinking &amp;#8220;Google Drive is just another data sync client and basically a clone of Dropbox&amp;#8221; simply don&amp;#8217;t get it. For Google, Data sync is not the key at all, web intent is the key, and it&amp;#8217;s been there for a while:&lt;/p&gt;
&lt;p&gt;http://blog.chromium.org/2011/08/connecting-web-apps-with-web-intents.html&lt;/p&gt;
&lt;p&gt;In my mind, Google Drive is totally different from Dropbox because of chromium and its web store. Yeah sure, search is nice, as well as easy share to G+ and integration with Google Doc. However, none of them is killer feature. Search and OCR is already doable in Evernote. It&amp;#8217;s not new at all.&lt;/p&gt;
&lt;p&gt;So you may ask, why Google Drive is interesting? Why would I choose it? Google introduced the web store long time ago and it&amp;#8217;s still not that hot. Why? Your data is scattered all over different places and it&amp;#8217;s very inconvenient to manage them. You have tons of choices over there while they are not well organized at all. That&amp;#8217;s where Google Drive is expected to play a role. The API, although still being simple, is introduced in the same day. There are already 17 web apps supporting it and based on my limited use, some of them are really handy. It could only get better.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1667&quot;&gt;&lt;/span&gt;&lt;br /&gt;
When the iCloud was out, a lot of people were debating the strategical/philosophical difference between Google and Apple in terms of cloud service, and majority of them think Apple is right. Apple is doing something more like Dropbox, with better integration. Sure, For pure Apple users, your device is the center of the universe, you don&amp;#8217;t need to care about what&amp;#8217;s going on there, just use it. It&amp;#8217;s a pretty neat user experience, for sure, and it&amp;#8217;s probably still more practical for the internet as it exists today. &lt;/p&gt;
&lt;p&gt;Unfortunately, it only works for pure Apple users, and what do I mean by &amp;#8220;pure&amp;#8221; is that, you are using Apple product in home, in work, and in wherever you need your data. So for lots of people, while you think you are &amp;#8220;pure&amp;#8221; Apple user because you have iPhone and Macbook, it&amp;#8217;s usually not true. Your data is in Apple&amp;#8217;s garden, and you just can&amp;#8217;t get it when you really need it for many other scenarios without MacOS.&lt;/p&gt;
&lt;p&gt;For Google, the Web is the center of the universe. Google is betting on ubiquitous Internet access in the not-too-distant future, and it expects you to be on Cloud all the time. What about those devices? Be it Android, iPhone, conceptual glasses or whatever you name it, they are just carriers. Therefore, you don&amp;#8217;t need to care about the OS, hardware, or physical form of the device in front of you. They are just tools for you to access cloud, and they only differ from each other in terms of convenience.&lt;/p&gt;
&lt;p&gt;I can&amp;#8217;t tell which one is better, for now. Turns out that both are doing just fine. However, Google, as a service provider, has to adopt the way they are doing now. Why? Business market. You can&amp;#8217;t ask enterprise to adopt you by using your device. Apple doesn&amp;#8217;t care, it&amp;#8217;s a device provider. Google cares. Google has to provide a nice collaborative environment with excellent data sharing solution to enter this market, and you have to make a bunch of efficient tools specifically for the daily operation. Of couse you can&amp;#8217;t make them all, so what do you do? Provide a nice infrastructure(storage and communication mechanism), then welcome other teams to provide corresponding tools by publishing API. As long as they are good enough, people will come to your way.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s what Google Drive is doing. Yes, it does sync your data on multiple devices. But it&amp;#8217;s way more than that.&lt;br /&gt;
&lt;h3&gt;Random Posts&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>0</thr:total><description>People thinking &amp;#8220;Google Drive is just another data sync client and basically a clone of Dropbox&amp;#8221; simply don&amp;#8217;t get it. For Google, Data sync is not the key at all, web intent is the key, and it&amp;#8217;s been there for a while: http://blog.chromium.org/2011/08/connecting-web-apps-with-web-intents.html In my mind, Google Drive is totally different from Dropbox because of [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207160/windstorm/feedsky/s.gif?r=http://www.kunli.info/2012/04/25/google-drive-dropbox-clone/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;People thinking &amp;#8220;Google Drive is just another data sync client and basically a clone of Dropbox&amp;#8221; simply don&amp;#8217;t get it. For Google, Data sync is not the key at all, web intent is the key, and it&amp;#8217;s been there for a while:&lt;/p&gt;
&lt;p&gt;http://blog.chromium.org/2011/08/connecting-web-apps-with-web-intents.html&lt;/p&gt;
&lt;p&gt;In my mind, Google Drive is totally different from Dropbox because of chromium and its web store. Yeah sure, search is nice, as well as easy share to G+ and integration with Google Doc. However, none of them is killer feature. Search and OCR is already doable in Evernote. It&amp;#8217;s not new at all.&lt;/p&gt;
&lt;p&gt;So you may ask, why Google Drive is interesting? Why would I choose it? Google introduced the web store long time ago and it&amp;#8217;s still not that hot. Why? Your data is scattered all over different places and it&amp;#8217;s very inconvenient to manage them. You have tons of choices over there while they are not well organized at all. That&amp;#8217;s where Google Drive is expected to play a role. The API, although still being simple, is introduced in the same day. There are already 17 web apps supporting it and based on my limited use, some of them are really handy. It could only get better.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1667&quot;&gt;&lt;/span&gt;&lt;br /&gt;
When the iCloud was out, a lot of people were debating the strategical/philosophical difference between Google and Apple in terms of cloud service, and majority of them think Apple is right. Apple is doing something more like Dropbox, with better integration. Sure, For pure Apple users, your device is the center of the universe, you don&amp;#8217;t need to care about what&amp;#8217;s going on there, just use it. It&amp;#8217;s a pretty neat user experience, for sure, and it&amp;#8217;s probably still more practical for the internet as it exists today. &lt;/p&gt;
&lt;p&gt;Unfortunately, it only works for pure Apple users, and what do I mean by &amp;#8220;pure&amp;#8221; is that, you are using Apple product in home, in work, and in wherever you need your data. So for lots of people, while you think you are &amp;#8220;pure&amp;#8221; Apple user because you have iPhone and Macbook, it&amp;#8217;s usually not true. Your data is in Apple&amp;#8217;s garden, and you just can&amp;#8217;t get it when you really need it for many other scenarios without MacOS.&lt;/p&gt;
&lt;p&gt;For Google, the Web is the center of the universe. Google is betting on ubiquitous Internet access in the not-too-distant future, and it expects you to be on Cloud all the time. What about those devices? Be it Android, iPhone, conceptual glasses or whatever you name it, they are just carriers. Therefore, you don&amp;#8217;t need to care about the OS, hardware, or physical form of the device in front of you. They are just tools for you to access cloud, and they only differ from each other in terms of convenience.&lt;/p&gt;
&lt;p&gt;I can&amp;#8217;t tell which one is better, for now. Turns out that both are doing just fine. However, Google, as a service provider, has to adopt the way they are doing now. Why? Business market. You can&amp;#8217;t ask enterprise to adopt you by using your device. Apple doesn&amp;#8217;t care, it&amp;#8217;s a device provider. Google cares. Google has to provide a nice collaborative environment with excellent data sharing solution to enter this market, and you have to make a bunch of efficient tools specifically for the daily operation. Of couse you can&amp;#8217;t make them all, so what do you do? Provide a nice infrastructure(storage and communication mechanism), then welcome other teams to provide corresponding tools by publishing API. As long as they are good enough, people will come to your way.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s what Google Drive is doing. Yes, it does sync your data on multiple devices. But it&amp;#8217;s way more than that.&lt;br /&gt;
&lt;h3&gt;Random Posts&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207160/windstorm/feedsky/s.gif?r=http://www.kunli.info/2012/04/25/google-drive-dropbox-clone/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">杂项</category><pubDate>Wed, 25 Apr 2012 15:53:33 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1667</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2012/04/25/google-drive-dropbox-clone/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207160/1226385</fs:itemid></item><item><title>小波变换和motion信号处理（一）</title><link atom:type="text/html">http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1459</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/">&lt;p&gt;这是《小波变换和motion信号处理》系列的第一篇，基础普及。&lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot; &gt;第二篇&lt;/a&gt;我准备写深入小波的东西，&lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot; &gt;第三篇&lt;/a&gt;讲解应用。&lt;/p&gt;
&lt;p&gt;记得我还在大四的时候，在申请出国和保研中犹豫了好一阵，骨子里的保守最后让我选择了先保研。当然后来也退学了，不过这是后话。当时保研就要找老板，实验室，自己运气还不错，进了一个在本校很牛逼的实验室干活路。我们实验室主要是搞图像的，实力在全国也是很强的，进去后和师兄师姐聊，大家都在搞什么小波变换，H264之类的。当时的我心思都不在这方面，尽搞什么操作系统移植，ARM+FPGA这些东西了。对小波变换的认识也就停留在神秘的“图像视频压缩算法之王”上面。&lt;/p&gt;
&lt;p&gt;后来我才发现，在别的很广泛的领域中，小波也逐渐开始流行。比如话说很早以前，我们接触的信号频域处理基本都是傅立叶和拉普拉斯的天下。但这些年，小波在信号分析中的逐渐兴盛和普及。这让人不得不感到好奇，是什么特性让它在图象压缩，信号处理这些关键应用中更得到信赖呢？说实话，我还在国内的时候，就开始好奇这个问题了，于是放狗搜，放毒搜，找遍了中文讲小波变换的科普文章，发现没几个讲得清楚的，当时好奇心没那么重，也不是搞这个研究的，懒得找英文大部头论文了，于是作罢。后来来了这边，有些项目要用信号处理，不得已接触到一些小波变换的东西，才开始硬着头皮看。看了一些材料，听了一些课，才发现，还是那个老生常谈的论调：国外的技术资料和国内真TNND不是一个档次的。同样的事情，别人说得很清楚，连我这种并不聪明的人也看得懂; 国内的材料则绕来绕去讲得一塌糊涂，除了少数天才没几个人能在短时间掌握的。&lt;/p&gt;
&lt;p&gt;牢骚就不继续发挥了。在这个系列文章里，我希望能简单介绍一下小波变换，它和傅立叶变换的比较，以及它在移动平台做motion detection的应用。如果不做特殊说明，均以离散小波为例子。考虑到我以前看中文资料的痛苦程度，我会尽量用简单，但是直观的方式去介绍。有些必要的公式是不能少的，但我尽量少用公式，多用图。另外，我不是一个好的翻译者，所以对于某些实在翻译不清楚的术语，我就会直接用英语。我并不claim我会把整个小波变换讲清楚，这是不可能的事，我只能尽力去围绕要点展开，比如小波变换相对傅立叶变换的好处，这些好处的原因是什么，小波变换的几个根本性质是什么，背后的推导是什么。我希望达到的目的就是一个小波变换的初学者在看完这个系列之后，就能用matlab或者别的工具对信号做小波变换的基本分析并且知道这个分析大概是怎么回事。&lt;/p&gt;
&lt;p&gt;最后说明，我不是研究信号处理的专业人士，所以文中必有疏漏或者错误，如发现还请不吝赐教。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1459&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;要讲小波变换，我们必须了解傅立叶变换。要了解傅立叶变换，我们先要弄清楚什么是”变换“。很多处理，不管是压缩也好，滤波也好，图形处理也好，本质都是变换。变换的是什么东西呢？是基，也就是basis。如果你暂时有些遗忘了basis的定义，那么简单说，在线性代数里，basis是指空间里一系列线性独立的向量，而这个空间里的任何其他向量，都可以由这些个向量的线性组合来表示。那basis在变换里面啥用呢？比如说吧，傅立叶展开的本质，就是把一个空间中的信号用该空间的某个basis的线性组合表示出来，要这样表示的原因，是因为傅立叶变换的本质，是。小波变换自然也不例外的和basis有关了。再比如你用Photoshop去处理图像，里面的图像拉伸，反转，等等一系列操作，都是和basis的改变有关。&lt;/p&gt;
&lt;p&gt;既然这些变换都是在搞基，那我们自然就容易想到，这个basis的选取非常重要，因为basis的特点决定了具体的计算过程。一个空间中可能有很多种形式的basis，什么样的basis比较好，很大程度上取决于这个basis服务于什么应用。比如如果我们希望选取有利于压缩的话，那么就希望这个basis能用其中很少的向量来最大程度地表示信号，这样即使把别的向量给砍了，信号也不会损失很多。而如果是图形处理中常见的线性变换，最省计算量的完美basis就是eigenvector basis了，因为此时变换矩阵T对它们的作用等同于对角矩阵( Tv_n = av_n，a是eigenvalue )。总的来说，抛开具体的应用不谈，所有的basis，我们都希望它们有一个共同的特点，那就是，容易计算，用最简单的方式呈现最多的信号特性。&lt;/p&gt;
&lt;p&gt;好，现在我们对变换有了基本的认识，知道他们其实就是在搞基。当然，搞基也是分形式的，不同的变换，搞基的妙处各有不同。接下来先看看，傅立叶变换是在干嘛。&lt;/p&gt;
&lt;p&gt;傅立叶级数最早是Joseph Fourier 这个人提出的，他发现，这个basis不仅仅存在与vector space，还存在于function space。这个function space本质上还是一个linear vector space，可以是有限的，可以是无限的，只不过在这个空间里，vector就是function了，而对应的标量就是实数或者复数。在vector space里，你有vector v可以写成vector basis的线性组合，那在function space里，function f(x)也可以写成对应function basis的线性组合，也有norm。你的vector basis可以是正交的，我的function basis也可以是正交的（比如sin(t)和sin(2t)）。唯一不同的是，我的function basis是无穷尽的，因为我的function space的维度是无穷的。好，具体来说，那就是现在我们有一个函数，f(x)。我们希望将它写成一些cos函数和一些sin函数的形式，像这样&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-3.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (3)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-3.gif&quot; alt=&quot;&quot; width=&quot;397&quot; height=&quot;18&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;again，这是一个无限循环的函数。其中的1，cosx, sinx, cos2x &amp;#8230;..这些，就是傅立叶级数。傅立叶级数应用如此广泛的主要原因之一，就是它们这帮子function basis是正交的，这就是有趣的地方了。为什么function basis正交如此重要呢？我们说两个vector正交，那就是他俩的内积为0。那对于function basis呢？function basis怎么求内积呢？&lt;/p&gt;
&lt;p&gt;现在先复习一下vector正交的定义。我们说两个vector v,w如果正交的话，应符合：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn.gif&quot; alt=&quot;&quot; width=&quot;243&quot; height=&quot;51&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那什么是function正交呢？假设我们有两个函数f(x)和g(x)，那是什么？我们遵循vector的思路去想，两个vector求内积，就是把他们相同位置上对应的点的乘积做一个累加。那移过来，就是对每一个x点，对应的f和g做乘积，再累加。不过问题是，f和g都是无限函数阿，x又是一个连续的值。怎么办呢？向量是离散的，所以累加，函数是连续的，那就是&amp;#8230;&amp;#8230;.积分！&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-1.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (1)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-1.gif&quot; alt=&quot;&quot; width=&quot;246&quot; height=&quot;41&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们知道函数内积是这样算的了，自然也就容易证明，按照这个形式去写的傅立叶展开，这些级数确实都是两两正交的。证明过程这里就不展开了。好，下一个问题就是，为什么它们是正交basis如此重要呢？这就牵涉到系数的求解了。我们研究了函数f，研究了级数，一堆三角函数和常数1，那系数呢？a0, a1, a2这些系数该怎么确定呢？好，比如我这里准备求a1了。我现在知道什么？信号f(x)是已知的，傅立叶级数是已知的，我们怎么求a1呢？很简单，把方程两端的所有部分都求和cosx的内积，即：&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-2.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (2)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-2.gif&quot; alt=&quot;&quot; width=&quot;564&quot; height=&quot;18&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后我们发现，因为正交的性质，右边所有非a1项全部消失了，因为他们和cosx的内积都是0！所有就简化为&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-4.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (4)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-4.gif&quot; alt=&quot;&quot; width=&quot;309&quot; height=&quot;42&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这样，a1就求解出来了。到这里，你就看出正交的奇妙性了吧:)&lt;/p&gt;
&lt;p&gt;好，现在我们知道，傅立叶变换就是用一系列三角波来表示信号方程的展开，这个信号可以是连续的，可以是离散的。傅立叶所用的function basis是专门挑选的，是正交的，是利于计算coefficients的。但千万别误解为展开变换所用的basis都是正交的，这完全取决于具体的使用需求，比如泰勒展开的basis就只是简单的非正交多项式。&lt;/p&gt;
&lt;p&gt;有了傅立叶变换的基础，接下来，我们就看看什么是小波变换。首先来说说什么是小波。所谓波，就是在时间域或者空间域的震荡方程，比如正弦波，就是一种波。什么是波分析？针对波的分析拉（囧）。并不是说小波分析才属于波分析，傅立叶分析也是波分析，因为正弦波也是一种波嘛。那什么是小波呢？这个&amp;#8221;小“，是针对傅立叶波而言的。傅立叶所用的波是什么？正弦波，这玩意以有着无穷的能量，同样的幅度在整个无穷大区间里面振荡，像下面这样：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/sine-wave.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1460&quot; title=&quot;sine-wave&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/sine-wave.png&quot; alt=&quot;&quot; width=&quot;226&quot; height=&quot;78&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那小波是什么呢？是一种能量在时域非常集中的波。它的能量是有限的，而且集中在某一点附近。比如下面这样：&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/wavelet.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1461&quot; title=&quot;wavelet&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/wavelet.png&quot; alt=&quot;&quot; width=&quot;226&quot; height=&quot;78&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这种小波有什么好处呢？它对于分析瞬时时变信号非常有用。它有效的从信号中提取信息，通过伸缩和平移等运算功能对函数或信号进行多尺度细化分析，解决了傅立叶变换不能解决的许多困难问题。恩，以上就是通常情况下你能在国内网站上搜到的小波变换文章告诉你的。但为什么呢？这是我希望在这个系列文章中讲清楚的。不过在这篇文章里，我先点到为止，把小波变换的重要特性以及优点cover了，在下一篇文章中再具体推导这些特性。&lt;/p&gt;
&lt;p&gt;小波变换的本质和傅立叶变换类似，也是用精心挑选的basis来表示信号方程。每个小波变换都会有一个mother wavelet，我们称之为母小波，同时还有一个scaling function，中文是尺度函数，也被成为父小波。任何小波变换的basis函数，其实就是对这个母小波和父小波缩放和平移后的集合。下面这附图就是某种小波的示意图：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.25.38-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1483&quot; title=&quot;Screen shot 2011-01-25 at 10.25.38 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.25.38-PM.png&quot; alt=&quot;&quot; width=&quot;601&quot; height=&quot;486&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;从这里看出，这里的缩放倍数都是2的级数，平移的大小和当前其缩放的程度有关。这样的好处是，小波的basis函数既有高频又有低频，同时还覆盖了时域。对于这点，我们会在之后详细阐述。&lt;/p&gt;
&lt;p&gt;小波展开的形式通常都是这样（注意，这个只是近似表达，严谨的展开形式请参考&lt;a href=&quot;http://www.kunli.info/2011/01/27/fourier-wavele…otion-signal-2/&quot; &gt;第二篇&lt;/a&gt;）：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1469&quot; title=&quot;CodeCogsEqn (5)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot; alt=&quot;&quot; width=&quot;186&quot; height=&quot;43&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中的&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1470&quot; title=&quot;CodeCogsEqn (6)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; alt=&quot;&quot; width=&quot;46&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;就是小波级数，这些级数的组合就形成了小波变换中的基basis。和傅立叶级数有一点不同的是，小波级数通常是orthonormal basis，也就是说，它们不仅两两正交，还归一化了。小波级数通常有很多种，但是都符合下面这些特性：&lt;/p&gt;
&lt;p&gt;1. 小波变换对不管是一维还是高维的大部分信号都能cover很好。这个和傅立叶级数有很大区别。后者最擅长的是把一维的，类三角波连续变量函数信号映射到一维系数序列上，但对于突变信号或任何高维的非三角波信号则几乎无能为力。&lt;/p&gt;
&lt;p&gt;2. 围绕小波级数的展开能够在时域和频域上同时定位信号，也就是说，信号的大部分能量都能由非常少的展开系数，比如a_{j,k}，决定。这个特性是得益于小波变换是二维变换。我们从两者展开的表达式就可以看出来，傅立叶级数是&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-7.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (7)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-7.gif&quot; alt=&quot;&quot; width=&quot;35&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;，而小波级数是&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (6)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; alt=&quot;&quot; width=&quot;46&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;3. 从信号算出展开系数a需要很方便。普遍情况下，小波变换的复杂度是O(Nlog(N))，和FFT相当。有不少很快的变换甚至可以达到O(N)，也就是说，计算复杂度和信号长度是线性的关系。小波变换的等式定义，可以没有积分，没有微分，仅仅是乘法和加法即可以做到，和现代计算机的计算指令完全match。&lt;/p&gt;
&lt;p&gt;可能看到这里，你会有点晕了。这些特性是怎么来的？为什么需要有这些特性？具体到实践中，它们到底是怎么给小波变换带来比别人更强的好处的？计算简单这个可能好理解，因为前面我们已经讲过正交特性了。那么二维变换呢？频域和时域定位是如何进行的呢？恩，我完全理解你的感受，因为当初我看别的文章，也是有这些问题，就是看不到答案。要说想完全理解小波变换的这些本质，需要详细的讲解，所以我就把它放到下一篇了。&lt;/p&gt;
&lt;p&gt;接下来，上几张图，我们以一些基本的信号处理来呈现小波变换比傅立叶变换好的地方，我保证，你看了这个比较之后，大概能隐约感受到小波变换的强大，并对背后的原理充满期待:)&lt;/p&gt;
&lt;p&gt;假设我们现在有这么一个信号：&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.29.15-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1484&quot; title=&quot;Screen shot 2011-01-25 at 10.29.15 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.29.15-PM.png&quot; alt=&quot;&quot; width=&quot;455&quot; height=&quot;218&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看到了吧，这个信号就是一个直流信号。我们用傅立叶将其展开，会发现形式非常简单：只有一个级数系数不是0，其他所有级数系数都是0。好，我们再看接下来这个信号：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.31.04-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1485&quot; title=&quot;Screen shot 2011-01-25 at 10.31.04 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.31.04-PM.png&quot; alt=&quot;&quot; width=&quot;500&quot; height=&quot;217&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;简单说，就是在前一个直流信号上，增加了一个突变。其实这个突变，在时域中看来很简单，前面还是很平滑的直流，后面也是很平滑的直流，就是中间有一个阶跃嘛。但是，如果我们再次让其傅立叶展开呢？所有的傅立叶级数都为非0了！为什么？因为傅立叶必须用三角波来展开信号，对于这种变换突然而剧烈的信号来讲，即使只有一小段变换，傅立叶也不得不用大量的三角波去拟合，就像这样：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.35.35-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1486&quot; title=&quot;Screen shot 2011-01-25 at 10.35.35 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.35.35-PM.png&quot; alt=&quot;&quot; width=&quot;631&quot; height=&quot;203&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看看上面这个图。学过基本的信号知识的朋友估计都能想到，这不就是Gibbs现象么？Exactly。用比较八股的说法来解释，Gibbs现象是由于展开式在间断点邻域不能均匀收敛所引起的，即使在N趋于无穷大时，这一现象也依然存在。其实通俗一点解释，就是当变化太sharp的时候，三角波fit不过来了，就凑合出Gibbs了:)&lt;/p&gt;
&lt;p&gt;接下来我们来看看，如果用刚才举例中的那种小波，展开之后是这样的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.42.59-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1488&quot; title=&quot;Screen shot 2011-01-25 at 10.42.59 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.42.59-PM.png&quot; alt=&quot;&quot; width=&quot;607&quot; height=&quot;567&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看见了么？只要小波basis不和这个信号变化重叠，它所对应的级数系数都为0！也就是说，假如我们就用这个三级小波对此信号展开，那么只有3个级数系数不为0 。你可以使用更复杂的小波，不管什么小波，大部分级数系数都会是0。原因？由于小波basis的特殊性，任何小波和常量函数的内积都趋近于0。换句话说，选小波的时候，就需要保证母小波在一个周期的积分趋近于0。正是这个有趣的性质，让小波变换的计算以及对信号的诠释比傅立叶变换更胜一筹！原因在于，小波变换允许更加精确的局部描述以及信号特征的分离。一个傅立叶系数通常表示某个贯穿整个时间域的信号分量，因此，即使是临时的信号，其特征也被强扯到了整个时间周期去描述。而小波展开的系数则代表了对应分量它当下的自己，因此非常容易诠释。&lt;/p&gt;
&lt;p&gt;小波变换的优势不仅仅在这里。事实上，对于傅立叶变换以及大部分的信号变换系统，他们的函数基都是固定的，那么变换后的结果只能按部就班被分析推导出来，没有任何灵活性，比如你如果决定使用傅立叶变换了，那basis function就是正弦波，你不管怎么scale，它都是正弦波，即使你举出余弦波，它还是移相后的正弦波。总之你就只能用正弦波，没有任何商量的余地。而对于小波变换来讲，基是变的，是可以根据信号来推导或者构建出来的，只要符合小波变换的性质和特点即可。也就是说，如果你有着比较特殊的信号需要处理，你甚至可以构建一个专门针对这种特殊信号的小波basis function集合对其进行分析。这种灵活性是任何别的变换都无法比拟的。总结来说，傅立叶变换适合周期性的，统计特性不随时间变化的信号; 而小波变换则适用于大部分信号，尤其是瞬时信号。它针对绝大部分信号的压缩，去噪，检测效果都特别好。&lt;/p&gt;
&lt;p&gt;看到这里，你应该大概了解了小波变换针对傅立叶变换的优点了。你也许对背后的原因还存在一些疑问，并希望深入了解一些小波的构建等知识，请移步本系列第二篇：&lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot; &gt;傅立叶变换，小波变换和motion信号处理（二）&lt;/a&gt;&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-02-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot;  title=&quot;小波变换和motion信号处理（二）&quot;&gt;小波变换和motion信号处理（二） (28)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2012-04-08 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot;  title=&quot;小波变换和motion信号处理（三）&quot;&gt;小波变换和motion信号处理（三） (2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>14</thr:total><description>这是《小波变换和motion信号处理》系列的第一篇，基础普及。第二篇我准备写深入小波的东西，第三篇讲解应用。 记得我还在大四的时候，在申请出国和保研中犹豫了好一阵，骨子里的保守最后让我选择了先保研。当然后来也退学了，不过这是后话。当时保研就要找老板，实验室，自己运气还不错，进了一个在本校很牛逼的实验室干活路。我们实验室主要是搞图像的，实力在全国也是很强的，进去后和师兄师姐聊，大家都在搞什么小波变换，H264之类的。当时的我心思都不在这方面，尽搞什么操作系统移植，ARM+FPGA这些东西了。对小波变换的认识也就停留在神秘的“图像视频压缩算法之王”上面。 后来我才发现，在别的很广泛的领域中，小波也逐渐开始流行。比如话说很早以前，我们接触的信号频域处理基本都是傅立叶和拉普拉斯的天下。但这些年，小波在信号分析中的逐渐兴盛和普及。这让人不得不感到好奇，是什么特性让它在图象压缩，信号处理这些关键应用中更得到信赖呢？说实话，我还在国内的时候，就开始好奇这个问题了，于是放狗搜，放毒搜，找遍了中文讲小波变换的科普文章，发现没几个讲得清楚的，当时好奇心没那么重，也不是搞这个研究的，懒得找英文大部头论文了，于是作罢。后来来了这边，有些项目要用信号处理，不得已接触到一些小波变换的东西，才开始硬着头皮看。看了一些材料，听了一些课，才发现，还是那个老生常谈的论调：国外的技术资料和国内真TNND不是一个档次的。同样的事情，别人说得很清楚，连我这种并不聪明的人也看得懂; 国内的材料则绕来绕去讲得一塌糊涂，除了少数天才没几个人能在短时间掌握的。 牢骚就不继续发挥了。在这个系列文章里，我希望能简单介绍一下小波变换，它和傅立叶变换的比较，以及它在移动平台做motion detection的应用。如果不做特殊说明，均以离散小波为例子。考虑到我以前看中文资料的痛苦程度，我会尽量用简单，但是直观的方式去介绍。有些必要的公式是不能少的，但我尽量少用公式，多用图。另外，我不是一个好的翻译者，所以对于某些实在翻译不清楚的术语，我就会直接用英语。我并不claim我会把整个小波变换讲清楚，这是不可能的事，我只能尽力去围绕要点展开，比如小波变换相对傅立叶变换的好处，这些好处的原因是什么，小波变换的几个根本性质是什么，背后的推导是什么。我希望达到的目的就是一个小波变换的初学者在看完这个系列之后，就能用matlab或者别的工具对信号做小波变换的基本分析并且知道这个分析大概是怎么回事。 最后说明，我不是研究信号处理的专业人士，所以文中必有疏漏或者错误，如发现还请不吝赐教。 要讲小波变换，我们必须了解傅立叶变换。要了解傅立叶变换，我们先要弄清楚什么是”变换“。很多处理，不管是压缩也好，滤波也好，图形处理也好，本质都是变换。变换的是什么东西呢？是基，也就是basis。如果你暂时有些遗忘了basis的定义，那么简单说，在线性代数里，basis是指空间里一系列线性独立的向量，而这个空间里的任何其他向量，都可以由这些个向量的线性组合来表示。那basis在变换里面啥用呢？比如说吧，傅立叶展开的本质，就是把一个空间中的信号用该空间的某个basis的线性组合表示出来，要这样表示的原因，是因为傅立叶变换的本质，是。小波变换自然也不例外的和basis有关了。再比如你用Photoshop去处理图像，里面的图像拉伸，反转，等等一系列操作，都是和basis的改变有关。 既然这些变换都是在搞基，那我们自然就容易想到，这个basis的选取非常重要，因为basis的特点决定了具体的计算过程。一个空间中可能有很多种形式的basis，什么样的basis比较好，很大程度上取决于这个basis服务于什么应用。比如如果我们希望选取有利于压缩的话，那么就希望这个basis能用其中很少的向量来最大程度地表示信号，这样即使把别的向量给砍了，信号也不会损失很多。而如果是图形处理中常见的线性变换，最省计算量的完美basis就是eigenvector basis了，因为此时变换矩阵T对它们的作用等同于对角矩阵( Tv_n = av_n，a是eigenvalue )。总的来说，抛开具体的应用不谈，所有的basis，我们都希望它们有一个共同的特点，那就是，容易计算，用最简单的方式呈现最多的信号特性。 好，现在我们对变换有了基本的认识，知道他们其实就是在搞基。当然，搞基也是分形式的，不同的变换，搞基的妙处各有不同。接下来先看看，傅立叶变换是在干嘛。 傅立叶级数最早是Joseph Fourier 这个人提出的，他发现，这个basis不仅仅存在与vector space，还存在于function space。这个function space本质上还是一个linear vector space，可以是有限的，可以是无限的，只不过在这个空间里，vector就是function了，而对应的标量就是实数或者复数。在vector space里，你有vector v可以写成vector basis的线性组合，那在function space里，function f(x)也可以写成对应function basis的线性组合，也有norm。你的vector basis可以是正交的，我的function basis也可以是正交的（比如sin(t)和sin(2t)）。唯一不同的是，我的function basis是无穷尽的，因为我的function space的维度是无穷的。好，具体来说，那就是现在我们有一个函数，f(x)。我们希望将它写成一些cos函数和一些sin函数的形式，像这样 again，这是一个无限循环的函数。其中的1，cosx, sinx, cos2x &amp;#8230;..这些，就是傅立叶级数。傅立叶级数应用如此广泛的主要原因之一，就是它们这帮子function basis是正交的，这就是有趣的地方了。为什么function basis正交如此重要呢？我们说两个vector正交，那就是他俩的内积为0。那对于function basis呢？function basis怎么求内积呢？ 现在先复习一下vector正交的定义。我们说两个vector v,w如果正交的话，应符合： 那什么是function正交呢？假设我们有两个函数f(x)和g(x)，那是什么？我们遵循vector的思路去想，两个vector求内积，就是把他们相同位置上对应的点的乘积做一个累加。那移过来，就是对每一个x点，对应的f和g做乘积，再累加。不过问题是，f和g都是无限函数阿，x又是一个连续的值。怎么办呢？向量是离散的，所以累加，函数是连续的，那就是&amp;#8230;&amp;#8230;.积分！ 我们知道函数内积是这样算的了，自然也就容易证明，按照这个形式去写的傅立叶展开，这些级数确实都是两两正交的。证明过程这里就不展开了。好，下一个问题就是，为什么它们是正交basis如此重要呢？这就牵涉到系数的求解了。我们研究了函数f，研究了级数，一堆三角函数和常数1，那系数呢？a0, a1, a2这些系数该怎么确定呢？好，比如我这里准备求a1了。我现在知道什么？信号f(x)是已知的，傅立叶级数是已知的，我们怎么求a1呢？很简单，把方程两端的所有部分都求和cosx的内积，即： 然后我们发现，因为正交的性质，右边所有非a1项全部消失了，因为他们和cosx的内积都是0！所有就简化为 这样，a1就求解出来了。到这里，你就看出正交的奇妙性了吧:) 好，现在我们知道，傅立叶变换就是用一系列三角波来表示信号方程的展开，这个信号可以是连续的，可以是离散的。傅立叶所用的function basis是专门挑选的，是正交的，是利于计算coefficients的。但千万别误解为展开变换所用的basis都是正交的，这完全取决于具体的使用需求，比如泰勒展开的basis就只是简单的非正交多项式。 有了傅立叶变换的基础，接下来，我们就看看什么是小波变换。首先来说说什么是小波。所谓波，就是在时间域或者空间域的震荡方程，比如正弦波，就是一种波。什么是波分析？针对波的分析拉（囧）。并不是说小波分析才属于波分析，傅立叶分析也是波分析，因为正弦波也是一种波嘛。那什么是小波呢？这个&amp;#8221;小“，是针对傅立叶波而言的。傅立叶所用的波是什么？正弦波，这玩意以有着无穷的能量，同样的幅度在整个无穷大区间里面振荡，像下面这样： 那小波是什么呢？是一种能量在时域非常集中的波。它的能量是有限的，而且集中在某一点附近。比如下面这样： 这种小波有什么好处呢？它对于分析瞬时时变信号非常有用。它有效的从信号中提取信息，通过伸缩和平移等运算功能对函数或信号进行多尺度细化分析，解决了傅立叶变换不能解决的许多困难问题。恩，以上就是通常情况下你能在国内网站上搜到的小波变换文章告诉你的。但为什么呢？这是我希望在这个系列文章中讲清楚的。不过在这篇文章里，我先点到为止，把小波变换的重要特性以及优点cover了，在下一篇文章中再具体推导这些特性。 小波变换的本质和傅立叶变换类似，也是用精心挑选的basis来表示信号方程。每个小波变换都会有一个mother [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207174/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;这是《小波变换和motion信号处理》系列的第一篇，基础普及。&lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot; &gt;第二篇&lt;/a&gt;我准备写深入小波的东西，&lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot; &gt;第三篇&lt;/a&gt;讲解应用。&lt;/p&gt;
&lt;p&gt;记得我还在大四的时候，在申请出国和保研中犹豫了好一阵，骨子里的保守最后让我选择了先保研。当然后来也退学了，不过这是后话。当时保研就要找老板，实验室，自己运气还不错，进了一个在本校很牛逼的实验室干活路。我们实验室主要是搞图像的，实力在全国也是很强的，进去后和师兄师姐聊，大家都在搞什么小波变换，H264之类的。当时的我心思都不在这方面，尽搞什么操作系统移植，ARM+FPGA这些东西了。对小波变换的认识也就停留在神秘的“图像视频压缩算法之王”上面。&lt;/p&gt;
&lt;p&gt;后来我才发现，在别的很广泛的领域中，小波也逐渐开始流行。比如话说很早以前，我们接触的信号频域处理基本都是傅立叶和拉普拉斯的天下。但这些年，小波在信号分析中的逐渐兴盛和普及。这让人不得不感到好奇，是什么特性让它在图象压缩，信号处理这些关键应用中更得到信赖呢？说实话，我还在国内的时候，就开始好奇这个问题了，于是放狗搜，放毒搜，找遍了中文讲小波变换的科普文章，发现没几个讲得清楚的，当时好奇心没那么重，也不是搞这个研究的，懒得找英文大部头论文了，于是作罢。后来来了这边，有些项目要用信号处理，不得已接触到一些小波变换的东西，才开始硬着头皮看。看了一些材料，听了一些课，才发现，还是那个老生常谈的论调：国外的技术资料和国内真TNND不是一个档次的。同样的事情，别人说得很清楚，连我这种并不聪明的人也看得懂; 国内的材料则绕来绕去讲得一塌糊涂，除了少数天才没几个人能在短时间掌握的。&lt;/p&gt;
&lt;p&gt;牢骚就不继续发挥了。在这个系列文章里，我希望能简单介绍一下小波变换，它和傅立叶变换的比较，以及它在移动平台做motion detection的应用。如果不做特殊说明，均以离散小波为例子。考虑到我以前看中文资料的痛苦程度，我会尽量用简单，但是直观的方式去介绍。有些必要的公式是不能少的，但我尽量少用公式，多用图。另外，我不是一个好的翻译者，所以对于某些实在翻译不清楚的术语，我就会直接用英语。我并不claim我会把整个小波变换讲清楚，这是不可能的事，我只能尽力去围绕要点展开，比如小波变换相对傅立叶变换的好处，这些好处的原因是什么，小波变换的几个根本性质是什么，背后的推导是什么。我希望达到的目的就是一个小波变换的初学者在看完这个系列之后，就能用matlab或者别的工具对信号做小波变换的基本分析并且知道这个分析大概是怎么回事。&lt;/p&gt;
&lt;p&gt;最后说明，我不是研究信号处理的专业人士，所以文中必有疏漏或者错误，如发现还请不吝赐教。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1459&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;要讲小波变换，我们必须了解傅立叶变换。要了解傅立叶变换，我们先要弄清楚什么是”变换“。很多处理，不管是压缩也好，滤波也好，图形处理也好，本质都是变换。变换的是什么东西呢？是基，也就是basis。如果你暂时有些遗忘了basis的定义，那么简单说，在线性代数里，basis是指空间里一系列线性独立的向量，而这个空间里的任何其他向量，都可以由这些个向量的线性组合来表示。那basis在变换里面啥用呢？比如说吧，傅立叶展开的本质，就是把一个空间中的信号用该空间的某个basis的线性组合表示出来，要这样表示的原因，是因为傅立叶变换的本质，是。小波变换自然也不例外的和basis有关了。再比如你用Photoshop去处理图像，里面的图像拉伸，反转，等等一系列操作，都是和basis的改变有关。&lt;/p&gt;
&lt;p&gt;既然这些变换都是在搞基，那我们自然就容易想到，这个basis的选取非常重要，因为basis的特点决定了具体的计算过程。一个空间中可能有很多种形式的basis，什么样的basis比较好，很大程度上取决于这个basis服务于什么应用。比如如果我们希望选取有利于压缩的话，那么就希望这个basis能用其中很少的向量来最大程度地表示信号，这样即使把别的向量给砍了，信号也不会损失很多。而如果是图形处理中常见的线性变换，最省计算量的完美basis就是eigenvector basis了，因为此时变换矩阵T对它们的作用等同于对角矩阵( Tv_n = av_n，a是eigenvalue )。总的来说，抛开具体的应用不谈，所有的basis，我们都希望它们有一个共同的特点，那就是，容易计算，用最简单的方式呈现最多的信号特性。&lt;/p&gt;
&lt;p&gt;好，现在我们对变换有了基本的认识，知道他们其实就是在搞基。当然，搞基也是分形式的，不同的变换，搞基的妙处各有不同。接下来先看看，傅立叶变换是在干嘛。&lt;/p&gt;
&lt;p&gt;傅立叶级数最早是Joseph Fourier 这个人提出的，他发现，这个basis不仅仅存在与vector space，还存在于function space。这个function space本质上还是一个linear vector space，可以是有限的，可以是无限的，只不过在这个空间里，vector就是function了，而对应的标量就是实数或者复数。在vector space里，你有vector v可以写成vector basis的线性组合，那在function space里，function f(x)也可以写成对应function basis的线性组合，也有norm。你的vector basis可以是正交的，我的function basis也可以是正交的（比如sin(t)和sin(2t)）。唯一不同的是，我的function basis是无穷尽的，因为我的function space的维度是无穷的。好，具体来说，那就是现在我们有一个函数，f(x)。我们希望将它写成一些cos函数和一些sin函数的形式，像这样&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-3.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (3)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-3.gif&quot; alt=&quot;&quot; width=&quot;397&quot; height=&quot;18&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;again，这是一个无限循环的函数。其中的1，cosx, sinx, cos2x &amp;#8230;..这些，就是傅立叶级数。傅立叶级数应用如此广泛的主要原因之一，就是它们这帮子function basis是正交的，这就是有趣的地方了。为什么function basis正交如此重要呢？我们说两个vector正交，那就是他俩的内积为0。那对于function basis呢？function basis怎么求内积呢？&lt;/p&gt;
&lt;p&gt;现在先复习一下vector正交的定义。我们说两个vector v,w如果正交的话，应符合：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn.gif&quot; alt=&quot;&quot; width=&quot;243&quot; height=&quot;51&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那什么是function正交呢？假设我们有两个函数f(x)和g(x)，那是什么？我们遵循vector的思路去想，两个vector求内积，就是把他们相同位置上对应的点的乘积做一个累加。那移过来，就是对每一个x点，对应的f和g做乘积，再累加。不过问题是，f和g都是无限函数阿，x又是一个连续的值。怎么办呢？向量是离散的，所以累加，函数是连续的，那就是&amp;#8230;&amp;#8230;.积分！&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-1.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (1)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-1.gif&quot; alt=&quot;&quot; width=&quot;246&quot; height=&quot;41&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们知道函数内积是这样算的了，自然也就容易证明，按照这个形式去写的傅立叶展开，这些级数确实都是两两正交的。证明过程这里就不展开了。好，下一个问题就是，为什么它们是正交basis如此重要呢？这就牵涉到系数的求解了。我们研究了函数f，研究了级数，一堆三角函数和常数1，那系数呢？a0, a1, a2这些系数该怎么确定呢？好，比如我这里准备求a1了。我现在知道什么？信号f(x)是已知的，傅立叶级数是已知的，我们怎么求a1呢？很简单，把方程两端的所有部分都求和cosx的内积，即：&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-2.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (2)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-2.gif&quot; alt=&quot;&quot; width=&quot;564&quot; height=&quot;18&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后我们发现，因为正交的性质，右边所有非a1项全部消失了，因为他们和cosx的内积都是0！所有就简化为&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-4.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (4)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-4.gif&quot; alt=&quot;&quot; width=&quot;309&quot; height=&quot;42&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这样，a1就求解出来了。到这里，你就看出正交的奇妙性了吧:)&lt;/p&gt;
&lt;p&gt;好，现在我们知道，傅立叶变换就是用一系列三角波来表示信号方程的展开，这个信号可以是连续的，可以是离散的。傅立叶所用的function basis是专门挑选的，是正交的，是利于计算coefficients的。但千万别误解为展开变换所用的basis都是正交的，这完全取决于具体的使用需求，比如泰勒展开的basis就只是简单的非正交多项式。&lt;/p&gt;
&lt;p&gt;有了傅立叶变换的基础，接下来，我们就看看什么是小波变换。首先来说说什么是小波。所谓波，就是在时间域或者空间域的震荡方程，比如正弦波，就是一种波。什么是波分析？针对波的分析拉（囧）。并不是说小波分析才属于波分析，傅立叶分析也是波分析，因为正弦波也是一种波嘛。那什么是小波呢？这个&amp;#8221;小“，是针对傅立叶波而言的。傅立叶所用的波是什么？正弦波，这玩意以有着无穷的能量，同样的幅度在整个无穷大区间里面振荡，像下面这样：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/sine-wave.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1460&quot; title=&quot;sine-wave&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/sine-wave.png&quot; alt=&quot;&quot; width=&quot;226&quot; height=&quot;78&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那小波是什么呢？是一种能量在时域非常集中的波。它的能量是有限的，而且集中在某一点附近。比如下面这样：&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/wavelet.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1461&quot; title=&quot;wavelet&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/wavelet.png&quot; alt=&quot;&quot; width=&quot;226&quot; height=&quot;78&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这种小波有什么好处呢？它对于分析瞬时时变信号非常有用。它有效的从信号中提取信息，通过伸缩和平移等运算功能对函数或信号进行多尺度细化分析，解决了傅立叶变换不能解决的许多困难问题。恩，以上就是通常情况下你能在国内网站上搜到的小波变换文章告诉你的。但为什么呢？这是我希望在这个系列文章中讲清楚的。不过在这篇文章里，我先点到为止，把小波变换的重要特性以及优点cover了，在下一篇文章中再具体推导这些特性。&lt;/p&gt;
&lt;p&gt;小波变换的本质和傅立叶变换类似，也是用精心挑选的basis来表示信号方程。每个小波变换都会有一个mother wavelet，我们称之为母小波，同时还有一个scaling function，中文是尺度函数，也被成为父小波。任何小波变换的basis函数，其实就是对这个母小波和父小波缩放和平移后的集合。下面这附图就是某种小波的示意图：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.25.38-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1483&quot; title=&quot;Screen shot 2011-01-25 at 10.25.38 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.25.38-PM.png&quot; alt=&quot;&quot; width=&quot;601&quot; height=&quot;486&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;从这里看出，这里的缩放倍数都是2的级数，平移的大小和当前其缩放的程度有关。这样的好处是，小波的basis函数既有高频又有低频，同时还覆盖了时域。对于这点，我们会在之后详细阐述。&lt;/p&gt;
&lt;p&gt;小波展开的形式通常都是这样（注意，这个只是近似表达，严谨的展开形式请参考&lt;a href=&quot;http://www.kunli.info/2011/01/27/fourier-wavele…otion-signal-2/&quot; &gt;第二篇&lt;/a&gt;）：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1469&quot; title=&quot;CodeCogsEqn (5)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot; alt=&quot;&quot; width=&quot;186&quot; height=&quot;43&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中的&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1470&quot; title=&quot;CodeCogsEqn (6)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; alt=&quot;&quot; width=&quot;46&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;就是小波级数，这些级数的组合就形成了小波变换中的基basis。和傅立叶级数有一点不同的是，小波级数通常是orthonormal basis，也就是说，它们不仅两两正交，还归一化了。小波级数通常有很多种，但是都符合下面这些特性：&lt;/p&gt;
&lt;p&gt;1. 小波变换对不管是一维还是高维的大部分信号都能cover很好。这个和傅立叶级数有很大区别。后者最擅长的是把一维的，类三角波连续变量函数信号映射到一维系数序列上，但对于突变信号或任何高维的非三角波信号则几乎无能为力。&lt;/p&gt;
&lt;p&gt;2. 围绕小波级数的展开能够在时域和频域上同时定位信号，也就是说，信号的大部分能量都能由非常少的展开系数，比如a_{j,k}，决定。这个特性是得益于小波变换是二维变换。我们从两者展开的表达式就可以看出来，傅立叶级数是&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-7.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (7)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-7.gif&quot; alt=&quot;&quot; width=&quot;35&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;，而小波级数是&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (6)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; alt=&quot;&quot; width=&quot;46&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;3. 从信号算出展开系数a需要很方便。普遍情况下，小波变换的复杂度是O(Nlog(N))，和FFT相当。有不少很快的变换甚至可以达到O(N)，也就是说，计算复杂度和信号长度是线性的关系。小波变换的等式定义，可以没有积分，没有微分，仅仅是乘法和加法即可以做到，和现代计算机的计算指令完全match。&lt;/p&gt;
&lt;p&gt;可能看到这里，你会有点晕了。这些特性是怎么来的？为什么需要有这些特性？具体到实践中，它们到底是怎么给小波变换带来比别人更强的好处的？计算简单这个可能好理解，因为前面我们已经讲过正交特性了。那么二维变换呢？频域和时域定位是如何进行的呢？恩，我完全理解你的感受，因为当初我看别的文章，也是有这些问题，就是看不到答案。要说想完全理解小波变换的这些本质，需要详细的讲解，所以我就把它放到下一篇了。&lt;/p&gt;
&lt;p&gt;接下来，上几张图，我们以一些基本的信号处理来呈现小波变换比傅立叶变换好的地方，我保证，你看了这个比较之后，大概能隐约感受到小波变换的强大，并对背后的原理充满期待:)&lt;/p&gt;
&lt;p&gt;假设我们现在有这么一个信号：&lt;br /&gt;
&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.29.15-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1484&quot; title=&quot;Screen shot 2011-01-25 at 10.29.15 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.29.15-PM.png&quot; alt=&quot;&quot; width=&quot;455&quot; height=&quot;218&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看到了吧，这个信号就是一个直流信号。我们用傅立叶将其展开，会发现形式非常简单：只有一个级数系数不是0，其他所有级数系数都是0。好，我们再看接下来这个信号：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.31.04-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1485&quot; title=&quot;Screen shot 2011-01-25 at 10.31.04 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.31.04-PM.png&quot; alt=&quot;&quot; width=&quot;500&quot; height=&quot;217&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;简单说，就是在前一个直流信号上，增加了一个突变。其实这个突变，在时域中看来很简单，前面还是很平滑的直流，后面也是很平滑的直流，就是中间有一个阶跃嘛。但是，如果我们再次让其傅立叶展开呢？所有的傅立叶级数都为非0了！为什么？因为傅立叶必须用三角波来展开信号，对于这种变换突然而剧烈的信号来讲，即使只有一小段变换，傅立叶也不得不用大量的三角波去拟合，就像这样：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.35.35-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1486&quot; title=&quot;Screen shot 2011-01-25 at 10.35.35 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.35.35-PM.png&quot; alt=&quot;&quot; width=&quot;631&quot; height=&quot;203&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看看上面这个图。学过基本的信号知识的朋友估计都能想到，这不就是Gibbs现象么？Exactly。用比较八股的说法来解释，Gibbs现象是由于展开式在间断点邻域不能均匀收敛所引起的，即使在N趋于无穷大时，这一现象也依然存在。其实通俗一点解释，就是当变化太sharp的时候，三角波fit不过来了，就凑合出Gibbs了:)&lt;/p&gt;
&lt;p&gt;接下来我们来看看，如果用刚才举例中的那种小波，展开之后是这样的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.42.59-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1488&quot; title=&quot;Screen shot 2011-01-25 at 10.42.59 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-25-at-10.42.59-PM.png&quot; alt=&quot;&quot; width=&quot;607&quot; height=&quot;567&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看见了么？只要小波basis不和这个信号变化重叠，它所对应的级数系数都为0！也就是说，假如我们就用这个三级小波对此信号展开，那么只有3个级数系数不为0 。你可以使用更复杂的小波，不管什么小波，大部分级数系数都会是0。原因？由于小波basis的特殊性，任何小波和常量函数的内积都趋近于0。换句话说，选小波的时候，就需要保证母小波在一个周期的积分趋近于0。正是这个有趣的性质，让小波变换的计算以及对信号的诠释比傅立叶变换更胜一筹！原因在于，小波变换允许更加精确的局部描述以及信号特征的分离。一个傅立叶系数通常表示某个贯穿整个时间域的信号分量，因此，即使是临时的信号，其特征也被强扯到了整个时间周期去描述。而小波展开的系数则代表了对应分量它当下的自己，因此非常容易诠释。&lt;/p&gt;
&lt;p&gt;小波变换的优势不仅仅在这里。事实上，对于傅立叶变换以及大部分的信号变换系统，他们的函数基都是固定的，那么变换后的结果只能按部就班被分析推导出来，没有任何灵活性，比如你如果决定使用傅立叶变换了，那basis function就是正弦波，你不管怎么scale，它都是正弦波，即使你举出余弦波，它还是移相后的正弦波。总之你就只能用正弦波，没有任何商量的余地。而对于小波变换来讲，基是变的，是可以根据信号来推导或者构建出来的，只要符合小波变换的性质和特点即可。也就是说，如果你有着比较特殊的信号需要处理，你甚至可以构建一个专门针对这种特殊信号的小波basis function集合对其进行分析。这种灵活性是任何别的变换都无法比拟的。总结来说，傅立叶变换适合周期性的，统计特性不随时间变化的信号; 而小波变换则适用于大部分信号，尤其是瞬时信号。它针对绝大部分信号的压缩，去噪，检测效果都特别好。&lt;/p&gt;
&lt;p&gt;看到这里，你应该大概了解了小波变换针对傅立叶变换的优点了。你也许对背后的原因还存在一些疑问，并希望深入了解一些小波的构建等知识，请移步本系列第二篇：&lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot; &gt;傅立叶变换，小波变换和motion信号处理（二）&lt;/a&gt;&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-02-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot;  title=&quot;小波变换和motion信号处理（二）&quot;&gt;小波变换和motion信号处理（二） (28)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2012-04-08 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot;  title=&quot;小波变换和motion信号处理（三）&quot;&gt;小波变换和motion信号处理（三） (2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207174/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">algorithm</category><category domain="http://www.kunli.info">傅立叶变换</category><category domain="http://www.kunli.info">小波变换</category><category domain="http://www.kunli.info">信号处理</category><pubDate>Sun, 08 Apr 2012 12:51:43 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1459</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207174/1226385</fs:itemid></item><item><title>小波变换和motion信号处理（二）</title><link atom:type="text/html">http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1478</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/">&lt;p&gt;这是《小波变换和motion信号处理》系列的第二篇，深入小波。&lt;a href=&quot;http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot; &gt;第一篇&lt;/a&gt;我进行了基础知识的铺垫，&lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot; &gt;第三篇&lt;/a&gt;主要讲解应用。&lt;/p&gt;
&lt;p&gt;在上一篇中讲到，每个小波变换都会有一个mother wavelet，我们称之为母小波，同时还有一个father wavelet，就是scaling function。而该小波的basis函数其实就是对这个母小波和父小波缩放和平移形成的。缩放倍数都是2的级数，平移的大小和当前其缩放的程度有关。&lt;/p&gt;
&lt;p&gt;还讲到，小波系统有很多种，不同的母小波，衍生的小波基就完全不同。小波展开的近似形式是这样：&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;lightbox&quot; href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot; &gt;&lt;img title=&quot;CodeCogsEqn (5)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot; alt=&quot;&quot; width=&quot;186&quot; height=&quot;43&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中的&lt;a rel=&quot;lightbox&quot; href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; &gt;&lt;img title=&quot;CodeCogsEqn (6)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; alt=&quot;&quot; width=&quot;46&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;就是小波级数，这些级数的组合就形成了小波变换中的基basis。和傅立叶级数有一点不同的是，小波级数通常是orthonormal basis，也就是说，它们不仅两两正交，还归一化了。&lt;/p&gt;
&lt;p&gt;我们还讲了一般小波变换的三个特点，就是小波级数是二维的，能定位时域和频域，计算很快。但我们并没有深入讲解，比如，如何理解这个二维？它是如何同时定位频域和时域的？&lt;/p&gt;
&lt;p&gt;在这一篇文章里，我们就来讨论一下这些特性背后的原理。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1478&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;首先，我们一直都在讲小波展开的近似形式。那什么是完整形式呢？之前讲到，小波basis的形成，是基于基本的小波函数，也就是母小波来做缩放和平移的。但是，母小波并非唯一的原始基。在构建小波基函数集合的时候，通常还要用到一个函数叫尺度函数，scaling function，人们通常都称其为父小波。它和母小波一样，也是归一化了，而且它还需要满足一个性质，就是它和对自己本身周期平移的函数两两正交：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.00.37-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1546&quot; title=&quot;Screen shot 2011-01-30 at 9.00.37 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.00.37-PM.png&quot; alt=&quot;&quot; width=&quot;120&quot; height=&quot;36&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.01.01-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1547&quot; title=&quot;Screen shot 2011-01-30 at 9.01.01 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.01.01-PM.png&quot; alt=&quot;&quot; width=&quot;268&quot; height=&quot;38&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;另外，为了方便处理，父小波和母小波也需要是正交的。可以说，完整的小波展开就是由母小波和父小波共同定义的。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-13.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1507&quot; title=&quot;CodeCogsEqn (13)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-13.gif&quot; alt=&quot;&quot; width=&quot;377&quot; height=&quot;53&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-14.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1508&quot; title=&quot;CodeCogsEqn (14)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-14.gif&quot; alt=&quot;&quot; width=&quot;30&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;是母小波，&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1509&quot; title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;是父小波。需要提醒一点的是，这个正交纯粹是为了小波分析的方便而引入的特性，并不是说小波变换的基就一定必须是正交的。但大部分小波变换的基确实是正交的，所以本文就直接默认正交为小波变换的主要性质之一了。引入这个父小波呢，主要是为了方便做多解析度分析（multiresolution analysis, MRA）。说到这里，你的问题可能会井喷了：好好的为什么出来一个父小波呢？这个scaling function是拿来干嘛的？它背后的物理意义是什么？wavelet function背后的物理意义又是什么？这个多解析度分析又是什么呢？不急，下面，我们围绕一个例子来巩固一下前面的知识，同时再引出新的特性。&lt;/p&gt;
&lt;p&gt;假设我们有这样一个信号：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.19.46-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.19.46 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.19.46-AM.png&quot; alt=&quot;&quot; width=&quot;479&quot; height=&quot;162&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;该信号长度为8，是离散的一维信号。我们要考虑的，就是如何用小波将其展开。为了方便讲解，我们考虑最简单的一种小波，哈尔小波。下面是它的一种母小波：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.22.57-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.22.57 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.22.57-AM-1024x496.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那如何构建基于这个母小波的基呢？刚才提到了，要缩放，要平移。我们先试试缩放，那就是ψ(2n)：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.29.58-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.29.58 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.29.58-AM.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;120&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;但这样的话，它与自己的内积就不是1了，不符合小波基orthonormal的要求，所以我们要在前面加一个系数根号二，这样我们就得到了另一个哈尔小波的basis function：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.34.40-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.34.40 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.34.40-AM-1024x401.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;155&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同理，我们可以一直这样推广下去做scale，得到4n，8n，&amp;#8230;&amp;#8230;.下的basis function。当然在这个例子里，我们信号长度就是8，所以做到4n就够了。但推广来说，就是这种scaling对母小波的作用为&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-11.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (11)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-11.gif&quot; alt=&quot;&quot; width=&quot;79&quot; height=&quot;22&quot; /&gt;&lt;/a&gt;，这是归一化后的表示形式。&lt;/p&gt;
&lt;p&gt;平移的话也很简单，我们可以对母小波进行平移，也可以对scale之后的basis function进行平移。比如对上一幅图中的basis function进行平移，就成了&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.43.35-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.43.35 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.43.35-AM-1024x390.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;155&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看得出来，平移后的basis function和母小波以及仅仅scale过的小波，都是正交的，附合小波basis的特点。如果我们用ψ(n)来表示这个mother wavelet，那么这些orthonormal basis函数可以写成：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-12.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (12)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-12.gif&quot; alt=&quot;&quot; width=&quot;205&quot; height=&quot;23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这里的k是可以看成时域的参数，因为它控制着小波基时域的转移，而j是频域的参数，因为它决定了小波基的频率特性。看到这里，你应该会感觉很熟悉，因为这里的平移和变换本质和刚才对scaling function的平移变换是一模一样的。&lt;/p&gt;
&lt;p&gt;这样，我们就有了针对此信号space的哈尔小波basis组合：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.53.03-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.53.03 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.53.03-AM-1024x524.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;262&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;图1&lt;/p&gt;
&lt;p&gt;可以看出，我们用到了三层频率尺度的小波函数，每往下一层，小波的数量都是上面一层的两倍。在图中，每一个小波基函数的表达形式都写在了波形的下面。&lt;/p&gt;
&lt;p&gt;等等，你可能已经发现了，有问题。这里为什么多了个没有函数表达式的波形呢？这货明显不是wavelet function阿。没错，它是之前提到的scaling function，也就是父小波。然后你可能就会问，为啥这个凭空插了一个scaling function出来呢？明明目标信号已经可以用纯的小波基组合表示了。是，确实是，就算不包括scaling function，这些小波函数本身也组成了正交归一基，但如果仅限于此的话，小波变换也就没那么神奇的功效了。引入这个scaling function，才能引入我们提到的多解析度分析的理论，而小波变换的强大，就体现在这个多解析度上。那在这里，我们怎么用这个多解析度呢？这个哈尔小波basis组合是怎么通过多解析度推导出来的呢？&lt;/p&gt;
&lt;p&gt;话说在数学定义中，有一种空间叫Lebesgue空间，对于信号处理非常重要，可以用L^p(R)表示，指的是由p次可积函数所组成的函数空间。我们在小波变换中要研究的信号都是属于L^2(R)空间的，这个空间是R上的所有处处平方可积的可测函数的集合，这样就等于对信号提出了一个限制，就是信号能量必须是有限的，否则它就不可积了。小波变换的定义都是基于但不限于L^2(R)中的信号的。这玩意的特性要具体解释起来太数学了，牵涉到太多泛函知识，我就不在这里详述了。而且老实说我也没能力完全讲清楚，毕竟不是学这个的，有兴趣可以参考&lt;a href=&quot;http://en.wikipedia.org/wiki/Lp_space&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/en.wikipedia.org');&quot;&gt;wiki&lt;/a&gt;。总之你记住，小波变换研究中所使用的信号基本都是平方可积的信号，但其应用不限于这种信号，就行了。&lt;/p&gt;
&lt;p&gt;对L^2(R)空间做MRA是在干嘛呢？就是说，在L^2(R)空间中，我们可以找出一个嵌套的空间序列&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image060.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;39&quot; height=&quot;19&quot; align=&quot;absMiddle&quot; /&gt;，并有下列性质：&lt;/p&gt;
&lt;p&gt;(i) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image062.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;170&quot; height=&quot;15&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(ii) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image063.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;144&quot; height=&quot;17&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(iii) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image064.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;135&quot; height=&quot;17&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(iv) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image065.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;135&quot; height=&quot;15&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(v) 有这样一个方程&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;,  &lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-16.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1511&quot; title=&quot;CodeCogsEqn (16)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-16.gif&quot; alt=&quot;&quot; width=&quot;62&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;是&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image049.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;14&quot; height=&quot;15&quot; align=&quot;absMiddle&quot; /&gt;的orthonormal basis。&lt;/p&gt;
&lt;p&gt;我来简单解释一下这些性质。这个V_j都是L^2(R)空间中的子空间，然后他们是由小到大的，交集是{0}，因为这是最小的子空间，并集就是L空间。是不是有点难以理解？没关系，看看下面这个图就清楚了：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.18.56-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1512&quot; title=&quot;Screen shot 2011-01-29 at 12.18.56 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.18.56-AM-300x173.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;173&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个图是圈圈套圈圈，最里面的圈是V0，之后分别是V1，V2，V3，V4 。那他们有趣的性质就是，假如有一个函数f(t)他属于一个某空间，那你将其在时域上平移，它还是属于这个空间。但如果你对它频域的放大或缩小，它就会相应移到下一个或者上一个空间了。&lt;/p&gt;
&lt;p&gt;同时我们还知道，你要形容每一个空间的话，都需要有对应的orthonormal basis，这是必然的，那对于V0来讲，它的orthonormal basis就是&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.32.59-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1514&quot; title=&quot;Screen shot 2011-01-29 at 12.32.59 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.32.59-AM-300x33.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;33&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这一系列函数是什么呢？是&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;的时域变换，而且我们刚才也说了，时域上平移，是不会跳出这个空间的。这样，我们就可以说，由这一系列basis所定义的L^2(R)子空间V0被这些basis所span，表示成：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.28.54-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1513&quot; title=&quot;Screen shot 2011-01-29 at 12.28.54 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.28.54-AM-300x91.png&quot; alt=&quot;&quot; width=&quot;150&quot; height=&quot;45&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;k从负无穷到正无穷。上面的bar表示这是一个闭包空间，也就是说&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.34.37-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1515&quot; title=&quot;Screen shot 2011-01-29 at 12.34.37 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.34.37-AM-300x51.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;51&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这样，我们就定义了基本的V0这个子空间。刚才说了，这个子空间的基都是对&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;的整数时域变换，这里我们称&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;为scaling function，所以换个说法，就是说这里整个子空间V0，由scaling function和其时域变换的兄弟们span。&lt;/p&gt;
&lt;p&gt;当然，如果这个scaling function只是用来代表一个子空间的，那它的地位也就不会这么重要了。刚才我们提到，这个嵌套空间序列有一个性质，&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image064.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;135&quot; height=&quot;17&quot; align=&quot;absMiddle&quot; /&gt;。这就是这个函数，如果你对它频域的放大或缩小，它就会相应移到下一个或者上一个空间了。这个性质就有意思了，它代表什么呢？对于任何一个包含V0的更上一层的空间来讲，他们的基都可以通过对scaling function做频域的scale后再做时域上的整数变换得到！推广开来就是说，当&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.42.43-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1516&quot; title=&quot;Screen shot 2011-01-29 at 12.42.43 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.42.43-AM-300x42.png&quot; alt=&quot;&quot; width=&quot;200&quot; height=&quot;28&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们有&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.44.04-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1517&quot; title=&quot;Screen shot 2011-01-29 at 12.44.04 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.44.04-AM-300x43.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;43&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这也就意味着，对于任何属于V_j空间的函数f(t)，都可以表示为：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.45.09-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1518&quot; title=&quot;Screen shot 2011-01-29 at 12.45.09 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.45.09-AM-300x68.png&quot; alt=&quot;&quot; width=&quot;200&quot; height=&quot;44&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;到这里，我们就明白这些个子空间和那个凭空冒出来的scaling function的作用了。scaling的构建这些不同的子空间的基础，当j越大的时候，每一次你对频率变换后的scaling function所做的时域上的整数平移幅度会越小，这样在这个j子空间里面得到的f(t)表示粒度会很细，细节展现很多。反之亦然。通俗点说，就是对scaling function的变换平移给你不同的子空间，而不同的子空间给你不同的分辨率，这样你就可以用不同的分辨率去看目标信号。&lt;/p&gt;
&lt;p&gt;下面就是时候看看什么是MRA equation了，这是更加有趣，也是更加核心的地方。通过刚才的讲解，V0属于V1，那scaling function&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;是在V0中的，自然也在V1中了。我们把他写成V1的基的线性组合，那就是&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-01-29-at-10.13.32-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1551&quot; title=&quot;Screen shot 2011-01-29 at 10.13.32 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-01-29-at-10.13.32-AM.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;44&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中的h(n)是scaling function的系数，也叫做scaling filter或者scaling vector，可以是实数，也可以是虚数。根号2是为了维持norm为1的。看，在这个公式里，我们就把属于V0的函数用V1的基表示出来了。同理，我们可以循环如此，把属于V0的&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;在V2, V3, &amp;#8230;, Vn中表示出来。这些方程就是MRA equation，也叫refinement equation，它是scaling function理论的基础，也是小波分析的基础之一。&lt;/p&gt;
&lt;p&gt;好，稍微总结一下。到现在，已经讲了关于scaling function的基本理论知识，知道了信号空间可以分为不同精细度的子空间，这些子空间的basis集合就是scaling function或者频率变换之后的scaling function，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-3.51.17-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1522&quot; title=&quot;Screen shot 2011-01-30 at 3.51.17 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-3.51.17-PM-300x207.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;207&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上图就是四个子空间的basis集合的展览。通过前面的讨论，我们还知道，一开始的scaling function可以通过更精细的子空间的scaling function（它们都是对应子空间的basis）来构建。比如&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.52.54-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1523&quot; title=&quot;Screen shot 2011-01-30 at 4.52.54 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.52.54-PM-1024x424.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;180&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于更加finer的scale：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.55.47-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1524&quot; title=&quot;Screen shot 2011-01-30 at 4.55.47 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.55.47-PM-1024x443.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;221&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.55.47-PM.png&quot; &gt;&lt;/a&gt; 图2&lt;br /&gt;
依此类推。实际上，对于任何scale和translate过的scaling function，都可以用更加精细的scale层面上的scaling function构建出来。&lt;/p&gt;
&lt;p&gt;然后，我们有各种scale下的scaling function了，该看看它们分别所对应的嵌套的空间序列&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image060.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;39&quot; height=&quot;19&quot; align=&quot;absMiddle&quot; /&gt;了。先看看V0，自然就是以基本的scaling function为基础去span出来的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.05.59-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1526&quot; title=&quot;Screen shot 2011-01-30 at 5.05.59 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.05.59-PM.png&quot; alt=&quot;&quot; width=&quot;140&quot; height=&quot;23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个不新鲜，刚才就讲过了。这个子空间代表什么样的信号？常量信号。道理很简单，这个scaling function在整个信号长度上，没有任何变化。继续往下看：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.08.27-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1527&quot; title=&quot;Screen shot 2011-01-30 at 5.08.27 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.08.27-PM-1024x90.png&quot; alt=&quot;&quot; width=&quot;280&quot; height=&quot;23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个相比V0更加finer的子空间，代表着这样一种信号，它从1-4是常量，从5-8是另一个常量。同理我们有：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.10.33-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1528&quot; title=&quot;Screen shot 2011-01-30 at 5.10.33 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.10.33-PM-1024x201.png&quot; alt=&quot;&quot; width=&quot;340&quot; height=&quot;66&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;V2代表的信号，是分别在1，2; 3，4; 5，6; 7，8上有相同值的信号。那么V3呢？则表示任何信号，因为对于V3来讲，任何一个时间刻度上的值都可以不一样。而且现在，我们也可以通过上面的一些scaling functions的波形验证了之前提到的多解析度分析中的一个核心性质，那就是：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.13.23-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1529&quot; title=&quot;Screen shot 2011-01-30 at 5.13.23 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.13.23-PM.png&quot; alt=&quot;&quot; width=&quot;154&quot; height=&quot;26&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们之前讲了一堆多解析度的理论，但直到现在，通过这些图形化的分析，我们可能才会真正理解它。那好，既然我们有一个现成的信号，那就来看看，对这个信号作多解析度分析是啥样子的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.24.35-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1530&quot; title=&quot;Screen shot 2011-01-30 at 5.24.35 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.24.35-PM-1024x520.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;260&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你看，在不同的子空间，对于同一个信号就有不同的诠释。诠释最好的当然是V3，完全不损失细节。这就是多解析度的意义。我们可以有嵌套的，由scaling function演变的basis function集合，每一个集合都提供对原始信号的某种近似，解析度越高，近似越精确。&lt;/p&gt;
&lt;p&gt;说到这里，可能你对scaling function以及多解析度分析已经比较理解了。但是，我们还没有涉及到它们在小波变换中的具体应用，也就是还没有回答刚才那个问题：凭空插了一个scaling function到小波basis组合中干嘛。也就是说，我们希望理解scaling function是怎么和小波函数结合的呢，多解析度能给小波变换带来什么样的好处呢。这其实就是是小波变换中的核心知识。理解了这个，后面的小波变换就是纯数学计算了。&lt;/p&gt;
&lt;p&gt;好，我们已经知道，对于子空间V0，basis是scaling function：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.46.32-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1531&quot; title=&quot;Screen shot 2011-01-30 at 5.46.32 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.46.32-PM.png&quot; alt=&quot;&quot; width=&quot;416&quot; height=&quot;59&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对应的小波函数是：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.08.35-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1533&quot; title=&quot;Screen shot 2011-01-30 at 6.08.35 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.08.35-PM.png&quot; alt=&quot;&quot; width=&quot;407&quot; height=&quot;75&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后子空间V1的basis集合是这俩哥们：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.07.04-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1532&quot; title=&quot;Screen shot 2011-01-30 at 6.07.04 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.07.04-PM.png&quot; alt=&quot;&quot; width=&quot;420&quot; height=&quot;156&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看出什么规律了么？多看几次这三个图，你会惊讶地发现，在V0中的scaling function和wavelet function的组合，其实就是V1中的basis！继续这样推导，V1本来的的basis是：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.12.49-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1534&quot; title=&quot;Screen shot 2011-01-30 at 6.12.49 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.12.49-PM.png&quot; alt=&quot;&quot; width=&quot;416&quot; height=&quot;153&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后V1中对应的wavelet function是&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.13.22-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1535&quot; title=&quot;Screen shot 2011-01-30 at 6.13.22 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.13.22-PM.png&quot; alt=&quot;&quot; width=&quot;420&quot; height=&quot;208&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;他们的组合，本质上也就是V2的basis（参考图2）。你继续推导下去，会得到同样的结论：在scale j的wavelet function，可以被用来将Vj的basis扩展到V(j+1)中去！这是一个非常非常关键的性质，因为这代表着，对任何一个子空间Vj，我们现在有两种方法去得到它的orthonormal basis：&lt;/p&gt;
&lt;p&gt;1. 一种就是它本来的basis &lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-17.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1536&quot; title=&quot;CodeCogsEqn (17)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-17.gif&quot; alt=&quot;&quot; width=&quot;27&quot; height=&quot;14&quot; /&gt;&lt;/a&gt;，对任意k。&lt;/p&gt;
&lt;p&gt;2. 第二种就是它上一个子空间的basis&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-18.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1537&quot; title=&quot;CodeCogsEqn (18)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-18.gif&quot; alt=&quot;&quot; width=&quot;44&quot; height=&quot;14&quot; /&gt;&lt;/a&gt;，对任意k，以及上一级子空间的wavelet function &lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-19.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1538&quot; title=&quot;CodeCogsEqn (19)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-19.gif&quot; alt=&quot;&quot; width=&quot;45&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;，对任意k。&lt;/p&gt;
&lt;p&gt;第二种选择能给我们带来额外的好处，那就是我们可以循环不断地用上一级子空间的scaling function以及wavelet function的组合来作为当前子空间的基。换句话说，如果针对V3这个子空间，它实际上就有四种不同的，但是等价的orthonormal basis：&lt;/p&gt;
&lt;p&gt;1. 本级(V3)的scaling function basis set&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.16.28-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1539&quot; title=&quot;Screen shot 2011-01-30 at 8.16.28 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.16.28-PM-1024x566.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;283&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2. 上一级(V2)的scaling function + wavelet function;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1540&quot; title=&quot;Screen shot 2011-01-30 at 8.18.10 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM-1024x519.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;259&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;3 . 上上一级(V1)的scaling function + 上上一级(V1)的wavelet function + 上一级(V2)的wavelet function;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.09-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1541&quot; title=&quot;Screen shot 2011-01-30 at 8.19.09 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.09-PM-1024x521.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;260&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;4. 上上上一级(V0)的scaling function + 上上上一级(V0)的wavelet function + 上上一级(V1)的wavelet function + 上一级(V2)的wavelet function&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.57-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1542&quot; title=&quot;Screen shot 2011-01-30 at 8.19.57 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.57-PM-1024x516.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;258&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;好，看看最后一种选取方式，有没有感到眼熟？对了，它就是我们之前提到的“针对此信号space的哈尔小波basis组合”，参见图1。现在我们知道了，这个scaling function不是凭空插进去的，而是通过不断的嵌套迭代出来的：）&lt;/p&gt;
&lt;p&gt;那为什么我们最后选定的是这种选取方式呢？实际上，刚才介绍的这个性质已经告诉我们，对于任何的scale j0，我们都可以给我们的signal space找到一组orthonormal basis，这个basis是通过组合scale j0上的scaling function以及所有在scale j，j&amp;gt;=j0上的wavelets得到的。这样，基于这个orthonormal basis，所有信号空间中的信号都可以写成组成这个basis的functions的线性组合：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.40.25-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1544&quot; title=&quot;Screen shot 2011-01-30 at 8.40.25 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.40.25-PM-1024x153.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;76&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对应的系数的计算和平常一样：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.41.37-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1545&quot; title=&quot;Screen shot 2011-01-30 at 8.41.37 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.41.37-PM.png&quot; alt=&quot;&quot; width=&quot;240&quot; height=&quot;102&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这，就是最终的，也是最核心的，小波变换形式。不管是信号压缩，滤波，还是别的方式处理，只要是用小波变换，都逃不出这个基础流程：&lt;/p&gt;
&lt;p&gt;1. 选取合适的wavelet function和scaling function，从已有的信号中，反算出系数c和d。&lt;/p&gt;
&lt;p&gt;2. 对系数做对应处理&lt;/p&gt;
&lt;p&gt;3. 从处理后的系数中重新构建信号。&lt;/p&gt;
&lt;p&gt;这里的系数处理是区别你的应用的重点。比如图像或者视频压缩，就希望选取能将能量聚集到很小一部分系数中的小波，然后抛弃那些能量很小的小波系数，只保留少数的这些大头系数，再反变换回去。这样的话，图像信号的能量并没有怎么丢失，图像体积却大大减小了。&lt;/p&gt;
&lt;p&gt;还有一个没有解释的问题是，为什么要强调尺度函数和小波函数组成一个orthonormal basis呢？计算方便是一方面，还有一个原因是，如果他们满足这个性质，就满足瑞利能量定理，也就是说，信号的能量，可以完全用每个频域里面的展开部分的能量，也就是他们的展开系数表示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-02-14-at-10.19.53-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1552&quot; title=&quot;Screen shot 2011-02-14 at 10.19.53 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-02-14-at-10.19.53-AM.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;60&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;到这里，我们对小波变换的形式就讲完了。虽然是用的最简单的哈尔小波为例子，但举一反三即可。我们着重介绍了多解析度分析以及它给小波变换带来的杀手锏：时域频域同时定位。结束之前，再多说几句小波变换的意义。我们拿刚才例子中V3子空间的第二种可选择的orthonormal basis作为例子：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-30 at 8.18.10 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM-1024x519.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;259&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;左边这四个basis组成元素，也就是scaling functions，的系数，表征的是信号的local平均（想想它们和信号的内积形式），而右边的这四个basis组成元素，也就是wavelet functions，的系数则表征了在local平均中丢失的信号细节。得益于此，多解析度分析能够对信号在越来越宽的区域上取平均，等同于做低通滤波，而且，它还能保留因为平均而损失的信号细节，等同于做高通滤波！这样，我们终于可以解释了wavelet function和scaling function背后的物理意义了：wavelet function等同于对信号做高通滤波保留变化细节，而scaling function等同于对信号做低通滤波保留平滑的shape！&lt;/p&gt;
&lt;p&gt;对小波变换的基础知识，我们就讲到这里。需要注意的是，这只是小波变换最基本最基本的知识，但也是最核心的知识。掌握了这些，代表你对小波变换的物理意义有了一定的了解。但对于小波变换本身的讲解，一本书都不一定能将讲透，还有很多的基础知识我都没有讲，比如如何构建自己的scaling function，选取合适的系数集h[k]，并由此构建自己的wavelet functions。所以，如果有深入下去研究的同学，好好买一本书来看吧。而只是希望用小波变换来服务自己的应用的同学，个人觉得这些知识已经足够让你用来起步了。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-02-15 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot;  title=&quot;小波变换和motion信号处理（一）&quot;&gt;小波变换和motion信号处理（一） (14)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2012-04-08 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot;  title=&quot;小波变换和motion信号处理（三）&quot;&gt;小波变换和motion信号处理（三） (2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>28</thr:total><description>这是《小波变换和motion信号处理》系列的第二篇，深入小波。第一篇我进行了基础知识的铺垫，第三篇主要讲解应用。 在上一篇中讲到，每个小波变换都会有一个mother wavelet，我们称之为母小波，同时还有一个father wavelet，就是scaling function。而该小波的basis函数其实就是对这个母小波和父小波缩放和平移形成的。缩放倍数都是2的级数，平移的大小和当前其缩放的程度有关。 还讲到，小波系统有很多种，不同的母小波，衍生的小波基就完全不同。小波展开的近似形式是这样： 其中的就是小波级数，这些级数的组合就形成了小波变换中的基basis。和傅立叶级数有一点不同的是，小波级数通常是orthonormal basis，也就是说，它们不仅两两正交，还归一化了。 我们还讲了一般小波变换的三个特点，就是小波级数是二维的，能定位时域和频域，计算很快。但我们并没有深入讲解，比如，如何理解这个二维？它是如何同时定位频域和时域的？ 在这一篇文章里，我们就来讨论一下这些特性背后的原理。 首先，我们一直都在讲小波展开的近似形式。那什么是完整形式呢？之前讲到，小波basis的形成，是基于基本的小波函数，也就是母小波来做缩放和平移的。但是，母小波并非唯一的原始基。在构建小波基函数集合的时候，通常还要用到一个函数叫尺度函数，scaling function，人们通常都称其为父小波。它和母小波一样，也是归一化了，而且它还需要满足一个性质，就是它和对自己本身周期平移的函数两两正交： 另外，为了方便处理，父小波和母小波也需要是正交的。可以说，完整的小波展开就是由母小波和父小波共同定义的。 其中是母小波，是父小波。需要提醒一点的是，这个正交纯粹是为了小波分析的方便而引入的特性，并不是说小波变换的基就一定必须是正交的。但大部分小波变换的基确实是正交的，所以本文就直接默认正交为小波变换的主要性质之一了。引入这个父小波呢，主要是为了方便做多解析度分析（multiresolution analysis, MRA）。说到这里，你的问题可能会井喷了：好好的为什么出来一个父小波呢？这个scaling function是拿来干嘛的？它背后的物理意义是什么？wavelet function背后的物理意义又是什么？这个多解析度分析又是什么呢？不急，下面，我们围绕一个例子来巩固一下前面的知识，同时再引出新的特性。 假设我们有这样一个信号： 该信号长度为8，是离散的一维信号。我们要考虑的，就是如何用小波将其展开。为了方便讲解，我们考虑最简单的一种小波，哈尔小波。下面是它的一种母小波： 那如何构建基于这个母小波的基呢？刚才提到了，要缩放，要平移。我们先试试缩放，那就是ψ(2n)： 但这样的话，它与自己的内积就不是1了，不符合小波基orthonormal的要求，所以我们要在前面加一个系数根号二，这样我们就得到了另一个哈尔小波的basis function： 同理，我们可以一直这样推广下去做scale，得到4n，8n，&amp;#8230;&amp;#8230;.下的basis function。当然在这个例子里，我们信号长度就是8，所以做到4n就够了。但推广来说，就是这种scaling对母小波的作用为，这是归一化后的表示形式。 平移的话也很简单，我们可以对母小波进行平移，也可以对scale之后的basis function进行平移。比如对上一幅图中的basis function进行平移，就成了 看得出来，平移后的basis function和母小波以及仅仅scale过的小波，都是正交的，附合小波basis的特点。如果我们用ψ(n)来表示这个mother wavelet，那么这些orthonormal basis函数可以写成： 这里的k是可以看成时域的参数，因为它控制着小波基时域的转移，而j是频域的参数，因为它决定了小波基的频率特性。看到这里，你应该会感觉很熟悉，因为这里的平移和变换本质和刚才对scaling function的平移变换是一模一样的。 这样，我们就有了针对此信号space的哈尔小波basis组合： 图1 可以看出，我们用到了三层频率尺度的小波函数，每往下一层，小波的数量都是上面一层的两倍。在图中，每一个小波基函数的表达形式都写在了波形的下面。 等等，你可能已经发现了，有问题。这里为什么多了个没有函数表达式的波形呢？这货明显不是wavelet function阿。没错，它是之前提到的scaling function，也就是父小波。然后你可能就会问，为啥这个凭空插了一个scaling function出来呢？明明目标信号已经可以用纯的小波基组合表示了。是，确实是，就算不包括scaling function，这些小波函数本身也组成了正交归一基，但如果仅限于此的话，小波变换也就没那么神奇的功效了。引入这个scaling function，才能引入我们提到的多解析度分析的理论，而小波变换的强大，就体现在这个多解析度上。那在这里，我们怎么用这个多解析度呢？这个哈尔小波basis组合是怎么通过多解析度推导出来的呢？ 话说在数学定义中，有一种空间叫Lebesgue空间，对于信号处理非常重要，可以用L^p(R)表示，指的是由p次可积函数所组成的函数空间。我们在小波变换中要研究的信号都是属于L^2(R)空间的，这个空间是R上的所有处处平方可积的可测函数的集合，这样就等于对信号提出了一个限制，就是信号能量必须是有限的，否则它就不可积了。小波变换的定义都是基于但不限于L^2(R)中的信号的。这玩意的特性要具体解释起来太数学了，牵涉到太多泛函知识，我就不在这里详述了。而且老实说我也没能力完全讲清楚，毕竟不是学这个的，有兴趣可以参考wiki。总之你记住，小波变换研究中所使用的信号基本都是平方可积的信号，但其应用不限于这种信号，就行了。 对L^2(R)空间做MRA是在干嘛呢？就是说，在L^2(R)空间中，我们可以找出一个嵌套的空间序列，并有下列性质： (i)  (ii)  (iii)  (iv)  (v) 有这样一个方程,  是的orthonormal basis。 我来简单解释一下这些性质。这个V_j都是L^2(R)空间中的子空间，然后他们是由小到大的，交集是{0}，因为这是最小的子空间，并集就是L空间。是不是有点难以理解？没关系，看看下面这个图就清楚了： 这个图是圈圈套圈圈，最里面的圈是V0，之后分别是V1，V2，V3，V4 。那他们有趣的性质就是，假如有一个函数f(t)他属于一个某空间，那你将其在时域上平移，它还是属于这个空间。但如果你对它频域的放大或缩小，它就会相应移到下一个或者上一个空间了。 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207173/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;这是《小波变换和motion信号处理》系列的第二篇，深入小波。&lt;a href=&quot;http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot; &gt;第一篇&lt;/a&gt;我进行了基础知识的铺垫，&lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot; &gt;第三篇&lt;/a&gt;主要讲解应用。&lt;/p&gt;
&lt;p&gt;在上一篇中讲到，每个小波变换都会有一个mother wavelet，我们称之为母小波，同时还有一个father wavelet，就是scaling function。而该小波的basis函数其实就是对这个母小波和父小波缩放和平移形成的。缩放倍数都是2的级数，平移的大小和当前其缩放的程度有关。&lt;/p&gt;
&lt;p&gt;还讲到，小波系统有很多种，不同的母小波，衍生的小波基就完全不同。小波展开的近似形式是这样：&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;lightbox&quot; href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot; &gt;&lt;img title=&quot;CodeCogsEqn (5)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-5.gif&quot; alt=&quot;&quot; width=&quot;186&quot; height=&quot;43&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中的&lt;a rel=&quot;lightbox&quot; href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; &gt;&lt;img title=&quot;CodeCogsEqn (6)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-6.gif&quot; alt=&quot;&quot; width=&quot;46&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;就是小波级数，这些级数的组合就形成了小波变换中的基basis。和傅立叶级数有一点不同的是，小波级数通常是orthonormal basis，也就是说，它们不仅两两正交，还归一化了。&lt;/p&gt;
&lt;p&gt;我们还讲了一般小波变换的三个特点，就是小波级数是二维的，能定位时域和频域，计算很快。但我们并没有深入讲解，比如，如何理解这个二维？它是如何同时定位频域和时域的？&lt;/p&gt;
&lt;p&gt;在这一篇文章里，我们就来讨论一下这些特性背后的原理。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1478&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;首先，我们一直都在讲小波展开的近似形式。那什么是完整形式呢？之前讲到，小波basis的形成，是基于基本的小波函数，也就是母小波来做缩放和平移的。但是，母小波并非唯一的原始基。在构建小波基函数集合的时候，通常还要用到一个函数叫尺度函数，scaling function，人们通常都称其为父小波。它和母小波一样，也是归一化了，而且它还需要满足一个性质，就是它和对自己本身周期平移的函数两两正交：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.00.37-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1546&quot; title=&quot;Screen shot 2011-01-30 at 9.00.37 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.00.37-PM.png&quot; alt=&quot;&quot; width=&quot;120&quot; height=&quot;36&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.01.01-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1547&quot; title=&quot;Screen shot 2011-01-30 at 9.01.01 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-9.01.01-PM.png&quot; alt=&quot;&quot; width=&quot;268&quot; height=&quot;38&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;另外，为了方便处理，父小波和母小波也需要是正交的。可以说，完整的小波展开就是由母小波和父小波共同定义的。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-13.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1507&quot; title=&quot;CodeCogsEqn (13)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-13.gif&quot; alt=&quot;&quot; width=&quot;377&quot; height=&quot;53&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-14.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1508&quot; title=&quot;CodeCogsEqn (14)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-14.gif&quot; alt=&quot;&quot; width=&quot;30&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;是母小波，&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1509&quot; title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;是父小波。需要提醒一点的是，这个正交纯粹是为了小波分析的方便而引入的特性，并不是说小波变换的基就一定必须是正交的。但大部分小波变换的基确实是正交的，所以本文就直接默认正交为小波变换的主要性质之一了。引入这个父小波呢，主要是为了方便做多解析度分析（multiresolution analysis, MRA）。说到这里，你的问题可能会井喷了：好好的为什么出来一个父小波呢？这个scaling function是拿来干嘛的？它背后的物理意义是什么？wavelet function背后的物理意义又是什么？这个多解析度分析又是什么呢？不急，下面，我们围绕一个例子来巩固一下前面的知识，同时再引出新的特性。&lt;/p&gt;
&lt;p&gt;假设我们有这样一个信号：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.19.46-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.19.46 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.19.46-AM.png&quot; alt=&quot;&quot; width=&quot;479&quot; height=&quot;162&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;该信号长度为8，是离散的一维信号。我们要考虑的，就是如何用小波将其展开。为了方便讲解，我们考虑最简单的一种小波，哈尔小波。下面是它的一种母小波：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.22.57-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.22.57 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.22.57-AM-1024x496.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那如何构建基于这个母小波的基呢？刚才提到了，要缩放，要平移。我们先试试缩放，那就是ψ(2n)：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.29.58-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.29.58 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.29.58-AM.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;120&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;但这样的话，它与自己的内积就不是1了，不符合小波基orthonormal的要求，所以我们要在前面加一个系数根号二，这样我们就得到了另一个哈尔小波的basis function：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.34.40-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.34.40 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.34.40-AM-1024x401.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;155&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同理，我们可以一直这样推广下去做scale，得到4n，8n，&amp;#8230;&amp;#8230;.下的basis function。当然在这个例子里，我们信号长度就是8，所以做到4n就够了。但推广来说，就是这种scaling对母小波的作用为&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-11.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (11)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-11.gif&quot; alt=&quot;&quot; width=&quot;79&quot; height=&quot;22&quot; /&gt;&lt;/a&gt;，这是归一化后的表示形式。&lt;/p&gt;
&lt;p&gt;平移的话也很简单，我们可以对母小波进行平移，也可以对scale之后的basis function进行平移。比如对上一幅图中的basis function进行平移，就成了&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.43.35-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.43.35 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.43.35-AM-1024x390.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;155&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看得出来，平移后的basis function和母小波以及仅仅scale过的小波，都是正交的，附合小波basis的特点。如果我们用ψ(n)来表示这个mother wavelet，那么这些orthonormal basis函数可以写成：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-12.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (12)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-12.gif&quot; alt=&quot;&quot; width=&quot;205&quot; height=&quot;23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这里的k是可以看成时域的参数，因为它控制着小波基时域的转移，而j是频域的参数，因为它决定了小波基的频率特性。看到这里，你应该会感觉很熟悉，因为这里的平移和变换本质和刚才对scaling function的平移变换是一模一样的。&lt;/p&gt;
&lt;p&gt;这样，我们就有了针对此信号space的哈尔小波basis组合：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.53.03-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-26 at 11.53.03 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-26-at-11.53.03-AM-1024x524.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;262&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;图1&lt;/p&gt;
&lt;p&gt;可以看出，我们用到了三层频率尺度的小波函数，每往下一层，小波的数量都是上面一层的两倍。在图中，每一个小波基函数的表达形式都写在了波形的下面。&lt;/p&gt;
&lt;p&gt;等等，你可能已经发现了，有问题。这里为什么多了个没有函数表达式的波形呢？这货明显不是wavelet function阿。没错，它是之前提到的scaling function，也就是父小波。然后你可能就会问，为啥这个凭空插了一个scaling function出来呢？明明目标信号已经可以用纯的小波基组合表示了。是，确实是，就算不包括scaling function，这些小波函数本身也组成了正交归一基，但如果仅限于此的话，小波变换也就没那么神奇的功效了。引入这个scaling function，才能引入我们提到的多解析度分析的理论，而小波变换的强大，就体现在这个多解析度上。那在这里，我们怎么用这个多解析度呢？这个哈尔小波basis组合是怎么通过多解析度推导出来的呢？&lt;/p&gt;
&lt;p&gt;话说在数学定义中，有一种空间叫Lebesgue空间，对于信号处理非常重要，可以用L^p(R)表示，指的是由p次可积函数所组成的函数空间。我们在小波变换中要研究的信号都是属于L^2(R)空间的，这个空间是R上的所有处处平方可积的可测函数的集合，这样就等于对信号提出了一个限制，就是信号能量必须是有限的，否则它就不可积了。小波变换的定义都是基于但不限于L^2(R)中的信号的。这玩意的特性要具体解释起来太数学了，牵涉到太多泛函知识，我就不在这里详述了。而且老实说我也没能力完全讲清楚，毕竟不是学这个的，有兴趣可以参考&lt;a href=&quot;http://en.wikipedia.org/wiki/Lp_space&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/en.wikipedia.org');&quot;&gt;wiki&lt;/a&gt;。总之你记住，小波变换研究中所使用的信号基本都是平方可积的信号，但其应用不限于这种信号，就行了。&lt;/p&gt;
&lt;p&gt;对L^2(R)空间做MRA是在干嘛呢？就是说，在L^2(R)空间中，我们可以找出一个嵌套的空间序列&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image060.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;39&quot; height=&quot;19&quot; align=&quot;absMiddle&quot; /&gt;，并有下列性质：&lt;/p&gt;
&lt;p&gt;(i) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image062.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;170&quot; height=&quot;15&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(ii) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image063.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;144&quot; height=&quot;17&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(iii) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image064.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;135&quot; height=&quot;17&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(iv) &lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image065.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;135&quot; height=&quot;15&quot; align=&quot;absMiddle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;(v) 有这样一个方程&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;,  &lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-16.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1511&quot; title=&quot;CodeCogsEqn (16)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-16.gif&quot; alt=&quot;&quot; width=&quot;62&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;是&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image049.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;14&quot; height=&quot;15&quot; align=&quot;absMiddle&quot; /&gt;的orthonormal basis。&lt;/p&gt;
&lt;p&gt;我来简单解释一下这些性质。这个V_j都是L^2(R)空间中的子空间，然后他们是由小到大的，交集是{0}，因为这是最小的子空间，并集就是L空间。是不是有点难以理解？没关系，看看下面这个图就清楚了：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.18.56-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1512&quot; title=&quot;Screen shot 2011-01-29 at 12.18.56 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.18.56-AM-300x173.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;173&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个图是圈圈套圈圈，最里面的圈是V0，之后分别是V1，V2，V3，V4 。那他们有趣的性质就是，假如有一个函数f(t)他属于一个某空间，那你将其在时域上平移，它还是属于这个空间。但如果你对它频域的放大或缩小，它就会相应移到下一个或者上一个空间了。&lt;/p&gt;
&lt;p&gt;同时我们还知道，你要形容每一个空间的话，都需要有对应的orthonormal basis，这是必然的，那对于V0来讲，它的orthonormal basis就是&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.32.59-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1514&quot; title=&quot;Screen shot 2011-01-29 at 12.32.59 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.32.59-AM-300x33.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;33&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这一系列函数是什么呢？是&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;的时域变换，而且我们刚才也说了，时域上平移，是不会跳出这个空间的。这样，我们就可以说，由这一系列basis所定义的L^2(R)子空间V0被这些basis所span，表示成：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.28.54-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1513&quot; title=&quot;Screen shot 2011-01-29 at 12.28.54 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.28.54-AM-300x91.png&quot; alt=&quot;&quot; width=&quot;150&quot; height=&quot;45&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;k从负无穷到正无穷。上面的bar表示这是一个闭包空间，也就是说&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.34.37-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1515&quot; title=&quot;Screen shot 2011-01-29 at 12.34.37 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.34.37-AM-300x51.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;51&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这样，我们就定义了基本的V0这个子空间。刚才说了，这个子空间的基都是对&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;的整数时域变换，这里我们称&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;为scaling function，所以换个说法，就是说这里整个子空间V0，由scaling function和其时域变换的兄弟们span。&lt;/p&gt;
&lt;p&gt;当然，如果这个scaling function只是用来代表一个子空间的，那它的地位也就不会这么重要了。刚才我们提到，这个嵌套空间序列有一个性质，&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image064.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;135&quot; height=&quot;17&quot; align=&quot;absMiddle&quot; /&gt;。这就是这个函数，如果你对它频域的放大或缩小，它就会相应移到下一个或者上一个空间了。这个性质就有意思了，它代表什么呢？对于任何一个包含V0的更上一层的空间来讲，他们的基都可以通过对scaling function做频域的scale后再做时域上的整数变换得到！推广开来就是说，当&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.42.43-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1516&quot; title=&quot;Screen shot 2011-01-29 at 12.42.43 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.42.43-AM-300x42.png&quot; alt=&quot;&quot; width=&quot;200&quot; height=&quot;28&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们有&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.44.04-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1517&quot; title=&quot;Screen shot 2011-01-29 at 12.44.04 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.44.04-AM-300x43.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;43&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这也就意味着，对于任何属于V_j空间的函数f(t)，都可以表示为：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.45.09-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1518&quot; title=&quot;Screen shot 2011-01-29 at 12.45.09 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-29-at-12.45.09-AM-300x68.png&quot; alt=&quot;&quot; width=&quot;200&quot; height=&quot;44&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;到这里，我们就明白这些个子空间和那个凭空冒出来的scaling function的作用了。scaling的构建这些不同的子空间的基础，当j越大的时候，每一次你对频率变换后的scaling function所做的时域上的整数平移幅度会越小，这样在这个j子空间里面得到的f(t)表示粒度会很细，细节展现很多。反之亦然。通俗点说，就是对scaling function的变换平移给你不同的子空间，而不同的子空间给你不同的分辨率，这样你就可以用不同的分辨率去看目标信号。&lt;/p&gt;
&lt;p&gt;下面就是时候看看什么是MRA equation了，这是更加有趣，也是更加核心的地方。通过刚才的讲解，V0属于V1，那scaling function&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;是在V0中的，自然也在V1中了。我们把他写成V1的基的线性组合，那就是&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-01-29-at-10.13.32-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1551&quot; title=&quot;Screen shot 2011-01-29 at 10.13.32 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-01-29-at-10.13.32-AM.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;44&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;其中的h(n)是scaling function的系数，也叫做scaling filter或者scaling vector，可以是实数，也可以是虚数。根号2是为了维持norm为1的。看，在这个公式里，我们就把属于V0的函数用V1的基表示出来了。同理，我们可以循环如此，把属于V0的&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;CodeCogsEqn (15)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-15.gif&quot; alt=&quot;&quot; width=&quot;32&quot; height=&quot;20&quot; /&gt;&lt;/a&gt;在V2, V3, &amp;#8230;, Vn中表示出来。这些方程就是MRA equation，也叫refinement equation，它是scaling function理论的基础，也是小波分析的基础之一。&lt;/p&gt;
&lt;p&gt;好，稍微总结一下。到现在，已经讲了关于scaling function的基本理论知识，知道了信号空间可以分为不同精细度的子空间，这些子空间的basis集合就是scaling function或者频率变换之后的scaling function，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-3.51.17-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1522&quot; title=&quot;Screen shot 2011-01-30 at 3.51.17 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-3.51.17-PM-300x207.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;207&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;上图就是四个子空间的basis集合的展览。通过前面的讨论，我们还知道，一开始的scaling function可以通过更精细的子空间的scaling function（它们都是对应子空间的basis）来构建。比如&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.52.54-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1523&quot; title=&quot;Screen shot 2011-01-30 at 4.52.54 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.52.54-PM-1024x424.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;180&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于更加finer的scale：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.55.47-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1524&quot; title=&quot;Screen shot 2011-01-30 at 4.55.47 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.55.47-PM-1024x443.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;221&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-4.55.47-PM.png&quot; &gt;&lt;/a&gt; 图2&lt;br /&gt;
依此类推。实际上，对于任何scale和translate过的scaling function，都可以用更加精细的scale层面上的scaling function构建出来。&lt;/p&gt;
&lt;p&gt;然后，我们有各种scale下的scaling function了，该看看它们分别所对应的嵌套的空间序列&lt;img src=&quot;http://merganser.math.gvsu.edu/david/reed03/projects/song/wavelets_files/image060.gif&quot; border=&quot;0&quot; alt=&quot;&quot; width=&quot;39&quot; height=&quot;19&quot; align=&quot;absMiddle&quot; /&gt;了。先看看V0，自然就是以基本的scaling function为基础去span出来的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.05.59-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1526&quot; title=&quot;Screen shot 2011-01-30 at 5.05.59 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.05.59-PM.png&quot; alt=&quot;&quot; width=&quot;140&quot; height=&quot;23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个不新鲜，刚才就讲过了。这个子空间代表什么样的信号？常量信号。道理很简单，这个scaling function在整个信号长度上，没有任何变化。继续往下看：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.08.27-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1527&quot; title=&quot;Screen shot 2011-01-30 at 5.08.27 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.08.27-PM-1024x90.png&quot; alt=&quot;&quot; width=&quot;280&quot; height=&quot;23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个相比V0更加finer的子空间，代表着这样一种信号，它从1-4是常量，从5-8是另一个常量。同理我们有：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.10.33-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1528&quot; title=&quot;Screen shot 2011-01-30 at 5.10.33 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.10.33-PM-1024x201.png&quot; alt=&quot;&quot; width=&quot;340&quot; height=&quot;66&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;V2代表的信号，是分别在1，2; 3，4; 5，6; 7，8上有相同值的信号。那么V3呢？则表示任何信号，因为对于V3来讲，任何一个时间刻度上的值都可以不一样。而且现在，我们也可以通过上面的一些scaling functions的波形验证了之前提到的多解析度分析中的一个核心性质，那就是：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.13.23-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1529&quot; title=&quot;Screen shot 2011-01-30 at 5.13.23 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.13.23-PM.png&quot; alt=&quot;&quot; width=&quot;154&quot; height=&quot;26&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们之前讲了一堆多解析度的理论，但直到现在，通过这些图形化的分析，我们可能才会真正理解它。那好，既然我们有一个现成的信号，那就来看看，对这个信号作多解析度分析是啥样子的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.24.35-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1530&quot; title=&quot;Screen shot 2011-01-30 at 5.24.35 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.24.35-PM-1024x520.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;260&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你看，在不同的子空间，对于同一个信号就有不同的诠释。诠释最好的当然是V3，完全不损失细节。这就是多解析度的意义。我们可以有嵌套的，由scaling function演变的basis function集合，每一个集合都提供对原始信号的某种近似，解析度越高，近似越精确。&lt;/p&gt;
&lt;p&gt;说到这里，可能你对scaling function以及多解析度分析已经比较理解了。但是，我们还没有涉及到它们在小波变换中的具体应用，也就是还没有回答刚才那个问题：凭空插了一个scaling function到小波basis组合中干嘛。也就是说，我们希望理解scaling function是怎么和小波函数结合的呢，多解析度能给小波变换带来什么样的好处呢。这其实就是是小波变换中的核心知识。理解了这个，后面的小波变换就是纯数学计算了。&lt;/p&gt;
&lt;p&gt;好，我们已经知道，对于子空间V0，basis是scaling function：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.46.32-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1531&quot; title=&quot;Screen shot 2011-01-30 at 5.46.32 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-5.46.32-PM.png&quot; alt=&quot;&quot; width=&quot;416&quot; height=&quot;59&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对应的小波函数是：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.08.35-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1533&quot; title=&quot;Screen shot 2011-01-30 at 6.08.35 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.08.35-PM.png&quot; alt=&quot;&quot; width=&quot;407&quot; height=&quot;75&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后子空间V1的basis集合是这俩哥们：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.07.04-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1532&quot; title=&quot;Screen shot 2011-01-30 at 6.07.04 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.07.04-PM.png&quot; alt=&quot;&quot; width=&quot;420&quot; height=&quot;156&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;看出什么规律了么？多看几次这三个图，你会惊讶地发现，在V0中的scaling function和wavelet function的组合，其实就是V1中的basis！继续这样推导，V1本来的的basis是：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.12.49-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1534&quot; title=&quot;Screen shot 2011-01-30 at 6.12.49 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.12.49-PM.png&quot; alt=&quot;&quot; width=&quot;416&quot; height=&quot;153&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后V1中对应的wavelet function是&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.13.22-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1535&quot; title=&quot;Screen shot 2011-01-30 at 6.13.22 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-6.13.22-PM.png&quot; alt=&quot;&quot; width=&quot;420&quot; height=&quot;208&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;他们的组合，本质上也就是V2的basis（参考图2）。你继续推导下去，会得到同样的结论：在scale j的wavelet function，可以被用来将Vj的basis扩展到V(j+1)中去！这是一个非常非常关键的性质，因为这代表着，对任何一个子空间Vj，我们现在有两种方法去得到它的orthonormal basis：&lt;/p&gt;
&lt;p&gt;1. 一种就是它本来的basis &lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-17.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1536&quot; title=&quot;CodeCogsEqn (17)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-17.gif&quot; alt=&quot;&quot; width=&quot;27&quot; height=&quot;14&quot; /&gt;&lt;/a&gt;，对任意k。&lt;/p&gt;
&lt;p&gt;2. 第二种就是它上一个子空间的basis&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-18.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1537&quot; title=&quot;CodeCogsEqn (18)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-18.gif&quot; alt=&quot;&quot; width=&quot;44&quot; height=&quot;14&quot; /&gt;&lt;/a&gt;，对任意k，以及上一级子空间的wavelet function &lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-19.gif&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1538&quot; title=&quot;CodeCogsEqn (19)&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/CodeCogsEqn-19.gif&quot; alt=&quot;&quot; width=&quot;45&quot; height=&quot;19&quot; /&gt;&lt;/a&gt;，对任意k。&lt;/p&gt;
&lt;p&gt;第二种选择能给我们带来额外的好处，那就是我们可以循环不断地用上一级子空间的scaling function以及wavelet function的组合来作为当前子空间的基。换句话说，如果针对V3这个子空间，它实际上就有四种不同的，但是等价的orthonormal basis：&lt;/p&gt;
&lt;p&gt;1. 本级(V3)的scaling function basis set&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.16.28-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1539&quot; title=&quot;Screen shot 2011-01-30 at 8.16.28 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.16.28-PM-1024x566.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;283&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2. 上一级(V2)的scaling function + wavelet function;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1540&quot; title=&quot;Screen shot 2011-01-30 at 8.18.10 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM-1024x519.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;259&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;3 . 上上一级(V1)的scaling function + 上上一级(V1)的wavelet function + 上一级(V2)的wavelet function;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.09-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1541&quot; title=&quot;Screen shot 2011-01-30 at 8.19.09 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.09-PM-1024x521.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;260&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;4. 上上上一级(V0)的scaling function + 上上上一级(V0)的wavelet function + 上上一级(V1)的wavelet function + 上一级(V2)的wavelet function&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.57-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1542&quot; title=&quot;Screen shot 2011-01-30 at 8.19.57 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.19.57-PM-1024x516.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;258&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;好，看看最后一种选取方式，有没有感到眼熟？对了，它就是我们之前提到的“针对此信号space的哈尔小波basis组合”，参见图1。现在我们知道了，这个scaling function不是凭空插进去的，而是通过不断的嵌套迭代出来的：）&lt;/p&gt;
&lt;p&gt;那为什么我们最后选定的是这种选取方式呢？实际上，刚才介绍的这个性质已经告诉我们，对于任何的scale j0，我们都可以给我们的signal space找到一组orthonormal basis，这个basis是通过组合scale j0上的scaling function以及所有在scale j，j&amp;gt;=j0上的wavelets得到的。这样，基于这个orthonormal basis，所有信号空间中的信号都可以写成组成这个basis的functions的线性组合：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.40.25-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1544&quot; title=&quot;Screen shot 2011-01-30 at 8.40.25 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.40.25-PM-1024x153.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;76&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对应的系数的计算和平常一样：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.41.37-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1545&quot; title=&quot;Screen shot 2011-01-30 at 8.41.37 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.41.37-PM.png&quot; alt=&quot;&quot; width=&quot;240&quot; height=&quot;102&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这，就是最终的，也是最核心的，小波变换形式。不管是信号压缩，滤波，还是别的方式处理，只要是用小波变换，都逃不出这个基础流程：&lt;/p&gt;
&lt;p&gt;1. 选取合适的wavelet function和scaling function，从已有的信号中，反算出系数c和d。&lt;/p&gt;
&lt;p&gt;2. 对系数做对应处理&lt;/p&gt;
&lt;p&gt;3. 从处理后的系数中重新构建信号。&lt;/p&gt;
&lt;p&gt;这里的系数处理是区别你的应用的重点。比如图像或者视频压缩，就希望选取能将能量聚集到很小一部分系数中的小波，然后抛弃那些能量很小的小波系数，只保留少数的这些大头系数，再反变换回去。这样的话，图像信号的能量并没有怎么丢失，图像体积却大大减小了。&lt;/p&gt;
&lt;p&gt;还有一个没有解释的问题是，为什么要强调尺度函数和小波函数组成一个orthonormal basis呢？计算方便是一方面，还有一个原因是，如果他们满足这个性质，就满足瑞利能量定理，也就是说，信号的能量，可以完全用每个频域里面的展开部分的能量，也就是他们的展开系数表示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-02-14-at-10.19.53-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1552&quot; title=&quot;Screen shot 2011-02-14 at 10.19.53 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/02/Screen-shot-2011-02-14-at-10.19.53-AM.png&quot; alt=&quot;&quot; width=&quot;400&quot; height=&quot;60&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;到这里，我们对小波变换的形式就讲完了。虽然是用的最简单的哈尔小波为例子，但举一反三即可。我们着重介绍了多解析度分析以及它给小波变换带来的杀手锏：时域频域同时定位。结束之前，再多说几句小波变换的意义。我们拿刚才例子中V3子空间的第二种可选择的orthonormal basis作为例子：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img title=&quot;Screen shot 2011-01-30 at 8.18.10 PM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/01/Screen-shot-2011-01-30-at-8.18.10-PM-1024x519.png&quot; alt=&quot;&quot; width=&quot;512&quot; height=&quot;259&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;左边这四个basis组成元素，也就是scaling functions，的系数，表征的是信号的local平均（想想它们和信号的内积形式），而右边的这四个basis组成元素，也就是wavelet functions，的系数则表征了在local平均中丢失的信号细节。得益于此，多解析度分析能够对信号在越来越宽的区域上取平均，等同于做低通滤波，而且，它还能保留因为平均而损失的信号细节，等同于做高通滤波！这样，我们终于可以解释了wavelet function和scaling function背后的物理意义了：wavelet function等同于对信号做高通滤波保留变化细节，而scaling function等同于对信号做低通滤波保留平滑的shape！&lt;/p&gt;
&lt;p&gt;对小波变换的基础知识，我们就讲到这里。需要注意的是，这只是小波变换最基本最基本的知识，但也是最核心的知识。掌握了这些，代表你对小波变换的物理意义有了一定的了解。但对于小波变换本身的讲解，一本书都不一定能将讲透，还有很多的基础知识我都没有讲，比如如何构建自己的scaling function，选取合适的系数集h[k]，并由此构建自己的wavelet functions。所以，如果有深入下去研究的同学，好好买一本书来看吧。而只是希望用小波变换来服务自己的应用的同学，个人觉得这些知识已经足够让你用来起步了。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-02-15 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot;  title=&quot;小波变换和motion信号处理（一）&quot;&gt;小波变换和motion信号处理（一） (14)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2012-04-08 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot;  title=&quot;小波变换和motion信号处理（三）&quot;&gt;小波变换和motion信号处理（三） (2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207173/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">algorithm</category><category domain="http://www.kunli.info">傅立叶变换</category><category domain="http://www.kunli.info">小波变换</category><category domain="http://www.kunli.info">信号处理</category><pubDate>Sun, 08 Apr 2012 12:51:33 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1478</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207173/1226385</fs:itemid></item><item><title>小波变换和motion信号处理（三）</title><link atom:type="text/html">http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1660</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/">&lt;p&gt;从前两篇发布到现在，过去一年多了。当初承诺的主要讲解应用的第三篇迟迟没能出炉的原因主要是这个方法用到了我们组的一篇论文中，所以在论文发表之前，不大方便发出来。倒不是说这个方法有多原创创新，只是这是团队工作，我单独提前发出来不大好。&lt;/p&gt;
&lt;p&gt;现在这篇论文已经录取发表，所以可以不用顾虑放上来了。我本来想讲的东西都在论文中，我也比较懒，就不再翻译一遍了。各位感兴趣的可以从这里&lt;a href=&quot;http://eces.colorado.edu/~kkli/pervasive12.pdf&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/eces.colorado.edu');&quot;&gt;下载&lt;/a&gt;。因为篇幅原因，和小波相关的文字已经被删除来只剩下不到两页了，不过基本思想还在。总的来说，就是我们希望用一个简单有效的方法，能达到这样一个效果：在你乘车的时候，当你的手机随便放在身上哪里，或者是座位上哪里，我们都能把手机感知到的汽车移动信息，和手机载体（比如包，口袋，或者车座位）移动导致的移动信息分开。这是小波变换一个非常合适的应用，因为由汽车突然移动或者人突然移动导致的速度变化，加速度变化等，在小波上的特征和汽车本身移动的特征是完全不同的。&lt;/p&gt;
&lt;p&gt;这样结束这个系列多多少少有点太监贴的感觉^_^。如果有朋友有和应用相关的问题，可以留言提问，我尽可能回答我能回答的&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-02-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot;  title=&quot;小波变换和motion信号处理（二）&quot;&gt;小波变换和motion信号处理（二） (28)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-02-15 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot;  title=&quot;小波变换和motion信号处理（一）&quot;&gt;小波变换和motion信号处理（一） (14)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>2</thr:total><description>从前两篇发布到现在，过去一年多了。当初承诺的主要讲解应用的第三篇迟迟没能出炉的原因主要是这个方法用到了我们组的一篇论文中，所以在论文发表之前，不大方便发出来。倒不是说这个方法有多原创创新，只是这是团队工作，我单独提前发出来不大好。 现在这篇论文已经录取发表，所以可以不用顾虑放上来了。我本来想讲的东西都在论文中，我也比较懒，就不再翻译一遍了。各位感兴趣的可以从这里下载。因为篇幅原因，和小波相关的文字已经被删除来只剩下不到两页了，不过基本思想还在。总的来说，就是我们希望用一个简单有效的方法，能达到这样一个效果：在你乘车的时候，当你的手机随便放在身上哪里，或者是座位上哪里，我们都能把手机感知到的汽车移动信息，和手机载体（比如包，口袋，或者车座位）移动导致的移动信息分开。这是小波变换一个非常合适的应用，因为由汽车突然移动或者人突然移动导致的速度变化，加速度变化等，在小波上的特征和汽车本身移动的特征是完全不同的。 这样结束这个系列多多少少有点太监贴的感觉^_^。如果有朋友有和应用相关的问题，可以留言提问，我尽可能回答我能回答的 也许你还会对这些文章感兴趣 2011-02-18 &amp;#8212; 小波变换和motion信号处理（二） (28) 2011-02-15 &amp;#8212; 小波变换和motion信号处理（一） (14) visit the website for more great content.&lt;img src=&quot;http://www1.feedsky.com/t1/631207161/windstorm/feedsky/s.gif?r=http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;从前两篇发布到现在，过去一年多了。当初承诺的主要讲解应用的第三篇迟迟没能出炉的原因主要是这个方法用到了我们组的一篇论文中，所以在论文发表之前，不大方便发出来。倒不是说这个方法有多原创创新，只是这是团队工作，我单独提前发出来不大好。&lt;/p&gt;
&lt;p&gt;现在这篇论文已经录取发表，所以可以不用顾虑放上来了。我本来想讲的东西都在论文中，我也比较懒，就不再翻译一遍了。各位感兴趣的可以从这里&lt;a href=&quot;http://eces.colorado.edu/~kkli/pervasive12.pdf&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/eces.colorado.edu');&quot;&gt;下载&lt;/a&gt;。因为篇幅原因，和小波相关的文字已经被删除来只剩下不到两页了，不过基本思想还在。总的来说，就是我们希望用一个简单有效的方法，能达到这样一个效果：在你乘车的时候，当你的手机随便放在身上哪里，或者是座位上哪里，我们都能把手机感知到的汽车移动信息，和手机载体（比如包，口袋，或者车座位）移动导致的移动信息分开。这是小波变换一个非常合适的应用，因为由汽车突然移动或者人突然移动导致的速度变化，加速度变化等，在小波上的特征和汽车本身移动的特征是完全不同的。&lt;/p&gt;
&lt;p&gt;这样结束这个系列多多少少有点太监贴的感觉^_^。如果有朋友有和应用相关的问题，可以留言提问，我尽可能回答我能回答的&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-02-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/18/fourier-wavelet-motion-signal-2/&quot;  title=&quot;小波变换和motion信号处理（二）&quot;&gt;小波变换和motion信号处理（二） (28)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-02-15 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/&quot;  title=&quot;小波变换和motion信号处理（一）&quot;&gt;小波变换和motion信号处理（一） (14)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207161/windstorm/feedsky/s.gif?r=http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">algorithm</category><category domain="http://www.kunli.info">小波变换</category><category domain="http://www.kunli.info">应用</category><pubDate>Sun, 08 Apr 2012 12:51:20 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1660</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207161/1226385</fs:itemid></item><item><title>使用Go语言一段时间的感受</title><link atom:type="text/html">http://www.kunli.info/2012/03/03/golang-feeling/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1652</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2012/03/03/golang-feeling/">&lt;p&gt;有一段时间没更新了。最近在忙一个Server+Client的项目，Client是Android手机，大概也就是几十的规模。Server是纯Golang实现，没有apache或者ngix这种web server，也没有数据库，自己写了个文件管理module，handle这种小规模的服务没问题。算下来接触Golang也有四个多月了，断断续续写了一些东西，这里纪录一下心得吧&lt;/p&gt;
&lt;p&gt;先大概说下为什么用Golang。我是一个对语言有洁癖的人，曾经是一个c+Python的坚定呐喊者，最常说的一句话就是，只要熟练这两种，什么情况都能应付，根本不用Java和C++(纯指我所在的领域）。核心代码用c，速度快，需要记的语言细节少；外围用Python glue，灵活，简洁，任何模块都容易上手，绝配。Java的繁琐，C++的无数无用的特性，都让我只在不得不用的时候才去用。Objective-C是另一个我欣赏的语言，问题是不跨平台，过于封闭。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1652&quot;&gt;&lt;/span&gt;&lt;br /&gt;
可惜的是，在这个节奏极快的时代，不是所有情况下都适合上c。之前有一个项目也是类似的架构和规模，为了节省时间，当初几乎没有服务器平台编程经验的我，在服务器端选择用Django+Apache+MySQL做，成熟，社区活跃，又是python作为主要开发语言，这些都是这个选择的原因。说实话，几个月过去后，回首看，这不是一个愉快的经历。Django是一个好架构，大而全，而大而全有时也就意味着臃肿，五花八门的配置，过紧的模块耦合对引入第三方工具限制颇多，自带的ORM又不好用。之前从来没有搞过服务器配置的我，对Apache的配置和效率所带来的琐碎的东西也头疼。总的来说这个部分花了我很多时间，有新手学习服务器编程的必经过程，也有折腾Django和Apache没必要的时间浪费，很大部分上抵消了Python带来的快速开发的灵活性。而一旦服务器上线，动态语言带来的一些bug又会让人头疼。对于普通高校实验室这种没有完善的服务器调试的条件，基本就是改了就上线用，有些隐蔽bug到某些条件分支才会触发，一旦在运行中途出问题，改起来也麻烦。&lt;/p&gt;
&lt;p&gt;从那时起，我就特别想，要是有一种语言能把c和Python的优点结合起来，也就是说&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;速度快，高性能&lt;/li&gt;
&lt;li&gt;简洁明了，需要记的语言细节少，开发迅速(c)&lt;/li&gt;
&lt;li&gt;灵活，开发快速，类Python的list，map等常用数据结构支持(Python)&lt;/li&gt;
&lt;li&gt;完善的模块支持，模块也容易上手(Python)&lt;/li&gt;
&lt;li&gt;对程序员友好的并行架构(Erlang)&lt;/li&gt;
&lt;li&gt;安全，绝大部分问题能消灭在compile time中(C minus pointer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那基本就是系统级和网络级编程最对我胃口的语言了。然后我就找到了&lt;a href=&quot;http://golang.org&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;Go&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Golang是一个新语言，截至目前为止，第一版正式版还没有发布。Golang的设计者是Robert Griesemer, Rob Pike和Ken Thompson，当年设计C和Unix，后来的Plan9团队中的人 。Golang的设计理念很明确，就是将动态类型语言的编程容易度和静态类型语言的安全效率结合起来。如果你想更深入了解Golang的发展历史以及完整的目标，请参考&lt;a href=&quot;http://golang.org/doc/go_faq.html#What_is_the_purpose_of_the_project&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;Golang FAQ&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;当然，Golang吸引我的地方，不是因为其是Google出品，也不是因为其设计者皆为大牛，而是因为，Golang真的做到了它所宣称的目标。Golang就如同C和Python中间的完美结合，如果你是Python爱好者，又追求代码的速度和并行化，那么简单说，Golang就是为你设计的。Golang有很浓厚的C的遗风，尽量屏蔽C++和Java的影响，比如没有独立的OO体系（并不是说不能OO），一切以struct为中心，没有exceptions(Oh yes!)，仍然有指针，等等。但是，Golang又吸取了很多新语言的精华，并带有自己独特的设计。比如&lt;/p&gt;
&lt;p&gt;1. 保留但大幅度简化指针&lt;/p&gt;
&lt;p&gt;Golang保留着C中值和指针的区别，但是对于指针繁琐用法进行了大量的简化，引入引用的概念。所以在Golang中，你几乎不用担心会因为直接操作内寸而引起各式各样的错误。&lt;/p&gt;
&lt;p&gt;2. 多参数返回&lt;/p&gt;
&lt;p&gt;还记得在C里面为了回馈多个参数，不得不开辟几段指针传到目标函数中让其操作么？在Go里面这是完全不必要的。而且多参数的支持让Go无需使用繁琐的exceptions体系，一个函数可以返回期待的返回值加上error，调用函数后立刻处理错误信息，清晰明了。&lt;/p&gt;
&lt;p&gt;3. Array，slice，map等内置基本数据结构&lt;/p&gt;
&lt;p&gt;如果你习惯了Python中简洁的list和dict操作，在Golang中，你不会感到孤单。一切都是那么熟悉，而且更加高效。如果你是C++程序员，你会发现你又找到了STL的vector 和 map这对朋友。&lt;/p&gt;
&lt;p&gt;4. Interface&lt;/p&gt;
&lt;p&gt;Golang最让人赞叹不易的特性，就是&lt;a href=&quot;http://research.swtch.com/interfaces&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/research.swtch.com');&quot;&gt;interface的设计&lt;/a&gt;。任何数据结构，只要实现了interface所定义的函数，自动就implement了这个interface，没有像Java那样冗长的class申明，提供了&lt;a href=&quot;http://golangtutorials.blogspot.com/2011/06/interfaces-in-go.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golangtutorials.blogspot.com');&quot;&gt;灵活太多的设计度和OO抽象度&lt;/a&gt;，让你的代码也非常干净。千万不要以为你习惯了Java那种一条一条加implements的方式，感觉还行，等接口的设计越来越复杂的时候，无数Bug正在后面等着你。&lt;/p&gt;
&lt;p&gt;同时，正因为如此，Golang的interface可以用来表示任何generic的东西，比如一个空的interface，可以是string可以是int，可以是任何数据类型，因为这些数据类型都不需要实现任何函数，自然就满足空interface的定义了。加上Golang的type assertion，可以提供一般动态语言才有的duck typing特性， 而仍然能在compile中捕捉明显的错误。&lt;/p&gt;
&lt;p&gt;5. OO&lt;/p&gt;
&lt;p&gt;Golang本质上不是面向对象语言，它还是过程化的。但是，在Golang中， 你可以很轻易的做大部分你在别的OO语言中能做的事，用更简单清晰的逻辑。是的，在这里，不需要class，仍然可以继承，仍然可以多态，但是速度却快得多。因为本质上，OO在Golang中，就是&lt;a href=&quot;http://golangtutorials.blogspot.com/2011/06/structs-in-go-instead-of-classes-in.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golangtutorials.blogspot.com');&quot;&gt;普通的struct操作&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;6. Goroutine&lt;/p&gt;
&lt;p&gt;这个几乎算是Golang的招牌特性之一了，我也不想多提。如果你完全不了解Goroutine，那么你只需要知道，这玩意是超级轻量级的类似线程的东西，但通过它，你不需要复杂的线程操作锁操作，不需要care调度，就能玩转基本的并行程序。在Golang里，触发一个routine和erlang spawn一样简单。基本上要掌握Golang，以Goroutine和channel为核心的&lt;a href=&quot;http://golang.org/doc/go_mem.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;内存模型&lt;/a&gt;是必须要懂的。不过请放心，真的非常简单。&lt;/p&gt;
&lt;p&gt;7. 更多现代的特性&lt;/p&gt;
&lt;p&gt;和C比较，Golang完全就是一门现代化语言，原生支持的Unicode, garbage collection, Closures(是的，和functional programming language类似), function是first class object，等等等等。&lt;/p&gt;
&lt;p&gt;看到这里，你可能会发现，我用了很多轻易，简单，快速之类的形容词来形容Golang的特点。我想说的是，一点都不夸张，连Golang的入门学习到提高，都比别的语言门槛低太多太多。在大部分人都有C的背景的时代，对于Golang，从入门到能够上手做项目，最多不过半个月。Golang给人的感觉就是太直接了，什么都直接，读源代码直接，写自己的代码也直接。&lt;/p&gt;
&lt;p&gt;有朋友要抗议了，你把Golang吹的这么好，难道它就没有缺点？有，当然有，不过和它的优点比，我觉得很多缺点都是因为整个语言太新，不成熟，随着时间的推移都能得到解决，相比之下都能忍了。如果你希望进一步了解Golang的优缺点，可以参考以下yufeng写的这篇文章，系统编程语言明日之星—Go（http://blog.yufeng.info/Go.pdf。&lt;/p&gt;
&lt;p&gt;还有朋友要说，Golang这么好，为什么没人用？我想说，眼界放开点，这个世界精彩的东西比你想象的多。Golang被Google用于&lt;a href=&quot;http://code.google.com/p/vitess/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/code.google.com');&quot;&gt;Youtube的数据库&lt;/a&gt;，被&lt;a href=&quot;http://go-lang.cat-v.org/organizations-using-go&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/go-lang.cat-v.org');&quot;&gt;越来越多的国外公司&lt;/a&gt;(大部分创业公司)用于后端开发，甚至在天朝，也有完全用Golang做服务开发的&lt;a href=&quot;https://qbox.me/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/qbox.me');&quot;&gt;云应用公司&lt;/a&gt;了。可以说，随着Go 1即将到来的正式推出，Golang的使用范围，应该会越来越广。&lt;/p&gt;
&lt;p&gt;好，总结时间&lt;/p&gt;
&lt;p&gt;如果你是Python和动态语言狂热爱好者，Go不一定能给你带来很大的惊喜，这纯粹取决于你得项目性质，考虑到Python目前在很多地方都用C做核心运算，速度在大部分情况下都不是大问题。scalability是一个问题，但并不是人人都会遇到的。&lt;/p&gt;
&lt;p&gt;如果你是C爱好者，强烈建议你学习和使用Go。Go可以调用C/C++程序，又提供了太多的便利，速度上稍有牺牲，但并不大。在绝大部分场景下Go能给你带来媲美C的性能，而对于某些确实性能过于关键的场合，也可以通过cgo让Go和C搭配。&lt;/p&gt;
&lt;p&gt;如果你是Java爱好者，除非你是做Android这种不得不用Java的平台，否则也建议你尝试学习Go，这个开发上感觉的差异如同比较开载着1吨石头的拖拉机和开保时捷911那么明显，而Java能给你的，Go能给得更好。&lt;/p&gt;
&lt;p&gt;如果你是C++爱好者，!@#$%^&amp;amp;*，恭喜你，至少你的智商应该是没问题的。人生苦短，赶紧脱离C++这个苦海吧。你用来学89个C++高级特性的时间，估计已经用Go写了64个开源项目了。&lt;/p&gt;
&lt;p&gt;如果你是像我一样的C和Python的爱好者，对动态语言又没有特殊的热爱&amp;#8230;&amp;#8230;我还需要说什么呢？&lt;/p&gt;
&lt;p&gt;让我们荡起双桨，去遨游&lt;a href=&quot;http://golang.org/doc/install.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;Golang的海洋&lt;/a&gt;吧。&lt;br /&gt;
&lt;h3&gt;Random Posts&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>10</thr:total><description>有一段时间没更新了。最近在忙一个Server+Client的项目，Client是Android手机，大概也就是几十的规模。Server是纯Golang实现，没有apache或者ngix这种web server，也没有数据库，自己写了个文件管理module，handle这种小规模的服务没问题。算下来接触Golang也有四个多月了，断断续续写了一些东西，这里纪录一下心得吧 先大概说下为什么用Golang。我是一个对语言有洁癖的人，曾经是一个c+Python的坚定呐喊者，最常说的一句话就是，只要熟练这两种，什么情况都能应付，根本不用Java和C++(纯指我所在的领域）。核心代码用c，速度快，需要记的语言细节少；外围用Python glue，灵活，简洁，任何模块都容易上手，绝配。Java的繁琐，C++的无数无用的特性，都让我只在不得不用的时候才去用。Objective-C是另一个我欣赏的语言，问题是不跨平台，过于封闭。 可惜的是，在这个节奏极快的时代，不是所有情况下都适合上c。之前有一个项目也是类似的架构和规模，为了节省时间，当初几乎没有服务器平台编程经验的我，在服务器端选择用Django+Apache+MySQL做，成熟，社区活跃，又是python作为主要开发语言，这些都是这个选择的原因。说实话，几个月过去后，回首看，这不是一个愉快的经历。Django是一个好架构，大而全，而大而全有时也就意味着臃肿，五花八门的配置，过紧的模块耦合对引入第三方工具限制颇多，自带的ORM又不好用。之前从来没有搞过服务器配置的我，对Apache的配置和效率所带来的琐碎的东西也头疼。总的来说这个部分花了我很多时间，有新手学习服务器编程的必经过程，也有折腾Django和Apache没必要的时间浪费，很大部分上抵消了Python带来的快速开发的灵活性。而一旦服务器上线，动态语言带来的一些bug又会让人头疼。对于普通高校实验室这种没有完善的服务器调试的条件，基本就是改了就上线用，有些隐蔽bug到某些条件分支才会触发，一旦在运行中途出问题，改起来也麻烦。 从那时起，我就特别想，要是有一种语言能把c和Python的优点结合起来，也就是说 速度快，高性能 简洁明了，需要记的语言细节少，开发迅速(c) 灵活，开发快速，类Python的list，map等常用数据结构支持(Python) 完善的模块支持，模块也容易上手(Python) 对程序员友好的并行架构(Erlang) 安全，绝大部分问题能消灭在compile time中(C minus pointer) 那基本就是系统级和网络级编程最对我胃口的语言了。然后我就找到了Go。 Golang是一个新语言，截至目前为止，第一版正式版还没有发布。Golang的设计者是Robert Griesemer, Rob Pike和Ken Thompson，当年设计C和Unix，后来的Plan9团队中的人 。Golang的设计理念很明确，就是将动态类型语言的编程容易度和静态类型语言的安全效率结合起来。如果你想更深入了解Golang的发展历史以及完整的目标，请参考Golang FAQ。 当然，Golang吸引我的地方，不是因为其是Google出品，也不是因为其设计者皆为大牛，而是因为，Golang真的做到了它所宣称的目标。Golang就如同C和Python中间的完美结合，如果你是Python爱好者，又追求代码的速度和并行化，那么简单说，Golang就是为你设计的。Golang有很浓厚的C的遗风，尽量屏蔽C++和Java的影响，比如没有独立的OO体系（并不是说不能OO），一切以struct为中心，没有exceptions(Oh yes!)，仍然有指针，等等。但是，Golang又吸取了很多新语言的精华，并带有自己独特的设计。比如 1. 保留但大幅度简化指针 Golang保留着C中值和指针的区别，但是对于指针繁琐用法进行了大量的简化，引入引用的概念。所以在Golang中，你几乎不用担心会因为直接操作内寸而引起各式各样的错误。 2. 多参数返回 还记得在C里面为了回馈多个参数，不得不开辟几段指针传到目标函数中让其操作么？在Go里面这是完全不必要的。而且多参数的支持让Go无需使用繁琐的exceptions体系，一个函数可以返回期待的返回值加上error，调用函数后立刻处理错误信息，清晰明了。 3. Array，slice，map等内置基本数据结构 如果你习惯了Python中简洁的list和dict操作，在Golang中，你不会感到孤单。一切都是那么熟悉，而且更加高效。如果你是C++程序员，你会发现你又找到了STL的vector 和 map这对朋友。 4. Interface Golang最让人赞叹不易的特性，就是interface的设计。任何数据结构，只要实现了interface所定义的函数，自动就implement了这个interface，没有像Java那样冗长的class申明，提供了灵活太多的设计度和OO抽象度，让你的代码也非常干净。千万不要以为你习惯了Java那种一条一条加implements的方式，感觉还行，等接口的设计越来越复杂的时候，无数Bug正在后面等着你。 同时，正因为如此，Golang的interface可以用来表示任何generic的东西，比如一个空的interface，可以是string可以是int，可以是任何数据类型，因为这些数据类型都不需要实现任何函数，自然就满足空interface的定义了。加上Golang的type assertion，可以提供一般动态语言才有的duck typing特性， 而仍然能在compile中捕捉明显的错误。 5. OO Golang本质上不是面向对象语言，它还是过程化的。但是，在Golang中， 你可以很轻易的做大部分你在别的OO语言中能做的事，用更简单清晰的逻辑。是的，在这里，不需要class，仍然可以继承，仍然可以多态，但是速度却快得多。因为本质上，OO在Golang中，就是普通的struct操作。 6. Goroutine 这个几乎算是Golang的招牌特性之一了，我也不想多提。如果你完全不了解Goroutine，那么你只需要知道，这玩意是超级轻量级的类似线程的东西，但通过它，你不需要复杂的线程操作锁操作，不需要care调度，就能玩转基本的并行程序。在Golang里，触发一个routine和erlang spawn一样简单。基本上要掌握Golang，以Goroutine和channel为核心的内存模型是必须要懂的。不过请放心，真的非常简单。 7. 更多现代的特性 和C比较，Golang完全就是一门现代化语言，原生支持的Unicode, garbage [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207162/windstorm/feedsky/s.gif?r=http://www.kunli.info/2012/03/03/golang-feeling/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;有一段时间没更新了。最近在忙一个Server+Client的项目，Client是Android手机，大概也就是几十的规模。Server是纯Golang实现，没有apache或者ngix这种web server，也没有数据库，自己写了个文件管理module，handle这种小规模的服务没问题。算下来接触Golang也有四个多月了，断断续续写了一些东西，这里纪录一下心得吧&lt;/p&gt;
&lt;p&gt;先大概说下为什么用Golang。我是一个对语言有洁癖的人，曾经是一个c+Python的坚定呐喊者，最常说的一句话就是，只要熟练这两种，什么情况都能应付，根本不用Java和C++(纯指我所在的领域）。核心代码用c，速度快，需要记的语言细节少；外围用Python glue，灵活，简洁，任何模块都容易上手，绝配。Java的繁琐，C++的无数无用的特性，都让我只在不得不用的时候才去用。Objective-C是另一个我欣赏的语言，问题是不跨平台，过于封闭。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1652&quot;&gt;&lt;/span&gt;&lt;br /&gt;
可惜的是，在这个节奏极快的时代，不是所有情况下都适合上c。之前有一个项目也是类似的架构和规模，为了节省时间，当初几乎没有服务器平台编程经验的我，在服务器端选择用Django+Apache+MySQL做，成熟，社区活跃，又是python作为主要开发语言，这些都是这个选择的原因。说实话，几个月过去后，回首看，这不是一个愉快的经历。Django是一个好架构，大而全，而大而全有时也就意味着臃肿，五花八门的配置，过紧的模块耦合对引入第三方工具限制颇多，自带的ORM又不好用。之前从来没有搞过服务器配置的我，对Apache的配置和效率所带来的琐碎的东西也头疼。总的来说这个部分花了我很多时间，有新手学习服务器编程的必经过程，也有折腾Django和Apache没必要的时间浪费，很大部分上抵消了Python带来的快速开发的灵活性。而一旦服务器上线，动态语言带来的一些bug又会让人头疼。对于普通高校实验室这种没有完善的服务器调试的条件，基本就是改了就上线用，有些隐蔽bug到某些条件分支才会触发，一旦在运行中途出问题，改起来也麻烦。&lt;/p&gt;
&lt;p&gt;从那时起，我就特别想，要是有一种语言能把c和Python的优点结合起来，也就是说&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;速度快，高性能&lt;/li&gt;
&lt;li&gt;简洁明了，需要记的语言细节少，开发迅速(c)&lt;/li&gt;
&lt;li&gt;灵活，开发快速，类Python的list，map等常用数据结构支持(Python)&lt;/li&gt;
&lt;li&gt;完善的模块支持，模块也容易上手(Python)&lt;/li&gt;
&lt;li&gt;对程序员友好的并行架构(Erlang)&lt;/li&gt;
&lt;li&gt;安全，绝大部分问题能消灭在compile time中(C minus pointer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那基本就是系统级和网络级编程最对我胃口的语言了。然后我就找到了&lt;a href=&quot;http://golang.org&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;Go&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Golang是一个新语言，截至目前为止，第一版正式版还没有发布。Golang的设计者是Robert Griesemer, Rob Pike和Ken Thompson，当年设计C和Unix，后来的Plan9团队中的人 。Golang的设计理念很明确，就是将动态类型语言的编程容易度和静态类型语言的安全效率结合起来。如果你想更深入了解Golang的发展历史以及完整的目标，请参考&lt;a href=&quot;http://golang.org/doc/go_faq.html#What_is_the_purpose_of_the_project&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;Golang FAQ&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;当然，Golang吸引我的地方，不是因为其是Google出品，也不是因为其设计者皆为大牛，而是因为，Golang真的做到了它所宣称的目标。Golang就如同C和Python中间的完美结合，如果你是Python爱好者，又追求代码的速度和并行化，那么简单说，Golang就是为你设计的。Golang有很浓厚的C的遗风，尽量屏蔽C++和Java的影响，比如没有独立的OO体系（并不是说不能OO），一切以struct为中心，没有exceptions(Oh yes!)，仍然有指针，等等。但是，Golang又吸取了很多新语言的精华，并带有自己独特的设计。比如&lt;/p&gt;
&lt;p&gt;1. 保留但大幅度简化指针&lt;/p&gt;
&lt;p&gt;Golang保留着C中值和指针的区别，但是对于指针繁琐用法进行了大量的简化，引入引用的概念。所以在Golang中，你几乎不用担心会因为直接操作内寸而引起各式各样的错误。&lt;/p&gt;
&lt;p&gt;2. 多参数返回&lt;/p&gt;
&lt;p&gt;还记得在C里面为了回馈多个参数，不得不开辟几段指针传到目标函数中让其操作么？在Go里面这是完全不必要的。而且多参数的支持让Go无需使用繁琐的exceptions体系，一个函数可以返回期待的返回值加上error，调用函数后立刻处理错误信息，清晰明了。&lt;/p&gt;
&lt;p&gt;3. Array，slice，map等内置基本数据结构&lt;/p&gt;
&lt;p&gt;如果你习惯了Python中简洁的list和dict操作，在Golang中，你不会感到孤单。一切都是那么熟悉，而且更加高效。如果你是C++程序员，你会发现你又找到了STL的vector 和 map这对朋友。&lt;/p&gt;
&lt;p&gt;4. Interface&lt;/p&gt;
&lt;p&gt;Golang最让人赞叹不易的特性，就是&lt;a href=&quot;http://research.swtch.com/interfaces&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/research.swtch.com');&quot;&gt;interface的设计&lt;/a&gt;。任何数据结构，只要实现了interface所定义的函数，自动就implement了这个interface，没有像Java那样冗长的class申明，提供了&lt;a href=&quot;http://golangtutorials.blogspot.com/2011/06/interfaces-in-go.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golangtutorials.blogspot.com');&quot;&gt;灵活太多的设计度和OO抽象度&lt;/a&gt;，让你的代码也非常干净。千万不要以为你习惯了Java那种一条一条加implements的方式，感觉还行，等接口的设计越来越复杂的时候，无数Bug正在后面等着你。&lt;/p&gt;
&lt;p&gt;同时，正因为如此，Golang的interface可以用来表示任何generic的东西，比如一个空的interface，可以是string可以是int，可以是任何数据类型，因为这些数据类型都不需要实现任何函数，自然就满足空interface的定义了。加上Golang的type assertion，可以提供一般动态语言才有的duck typing特性， 而仍然能在compile中捕捉明显的错误。&lt;/p&gt;
&lt;p&gt;5. OO&lt;/p&gt;
&lt;p&gt;Golang本质上不是面向对象语言，它还是过程化的。但是，在Golang中， 你可以很轻易的做大部分你在别的OO语言中能做的事，用更简单清晰的逻辑。是的，在这里，不需要class，仍然可以继承，仍然可以多态，但是速度却快得多。因为本质上，OO在Golang中，就是&lt;a href=&quot;http://golangtutorials.blogspot.com/2011/06/structs-in-go-instead-of-classes-in.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golangtutorials.blogspot.com');&quot;&gt;普通的struct操作&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;6. Goroutine&lt;/p&gt;
&lt;p&gt;这个几乎算是Golang的招牌特性之一了，我也不想多提。如果你完全不了解Goroutine，那么你只需要知道，这玩意是超级轻量级的类似线程的东西，但通过它，你不需要复杂的线程操作锁操作，不需要care调度，就能玩转基本的并行程序。在Golang里，触发一个routine和erlang spawn一样简单。基本上要掌握Golang，以Goroutine和channel为核心的&lt;a href=&quot;http://golang.org/doc/go_mem.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;内存模型&lt;/a&gt;是必须要懂的。不过请放心，真的非常简单。&lt;/p&gt;
&lt;p&gt;7. 更多现代的特性&lt;/p&gt;
&lt;p&gt;和C比较，Golang完全就是一门现代化语言，原生支持的Unicode, garbage collection, Closures(是的，和functional programming language类似), function是first class object，等等等等。&lt;/p&gt;
&lt;p&gt;看到这里，你可能会发现，我用了很多轻易，简单，快速之类的形容词来形容Golang的特点。我想说的是，一点都不夸张，连Golang的入门学习到提高，都比别的语言门槛低太多太多。在大部分人都有C的背景的时代，对于Golang，从入门到能够上手做项目，最多不过半个月。Golang给人的感觉就是太直接了，什么都直接，读源代码直接，写自己的代码也直接。&lt;/p&gt;
&lt;p&gt;有朋友要抗议了，你把Golang吹的这么好，难道它就没有缺点？有，当然有，不过和它的优点比，我觉得很多缺点都是因为整个语言太新，不成熟，随着时间的推移都能得到解决，相比之下都能忍了。如果你希望进一步了解Golang的优缺点，可以参考以下yufeng写的这篇文章，系统编程语言明日之星—Go（http://blog.yufeng.info/Go.pdf。&lt;/p&gt;
&lt;p&gt;还有朋友要说，Golang这么好，为什么没人用？我想说，眼界放开点，这个世界精彩的东西比你想象的多。Golang被Google用于&lt;a href=&quot;http://code.google.com/p/vitess/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/code.google.com');&quot;&gt;Youtube的数据库&lt;/a&gt;，被&lt;a href=&quot;http://go-lang.cat-v.org/organizations-using-go&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/go-lang.cat-v.org');&quot;&gt;越来越多的国外公司&lt;/a&gt;(大部分创业公司)用于后端开发，甚至在天朝，也有完全用Golang做服务开发的&lt;a href=&quot;https://qbox.me/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/qbox.me');&quot;&gt;云应用公司&lt;/a&gt;了。可以说，随着Go 1即将到来的正式推出，Golang的使用范围，应该会越来越广。&lt;/p&gt;
&lt;p&gt;好，总结时间&lt;/p&gt;
&lt;p&gt;如果你是Python和动态语言狂热爱好者，Go不一定能给你带来很大的惊喜，这纯粹取决于你得项目性质，考虑到Python目前在很多地方都用C做核心运算，速度在大部分情况下都不是大问题。scalability是一个问题，但并不是人人都会遇到的。&lt;/p&gt;
&lt;p&gt;如果你是C爱好者，强烈建议你学习和使用Go。Go可以调用C/C++程序，又提供了太多的便利，速度上稍有牺牲，但并不大。在绝大部分场景下Go能给你带来媲美C的性能，而对于某些确实性能过于关键的场合，也可以通过cgo让Go和C搭配。&lt;/p&gt;
&lt;p&gt;如果你是Java爱好者，除非你是做Android这种不得不用Java的平台，否则也建议你尝试学习Go，这个开发上感觉的差异如同比较开载着1吨石头的拖拉机和开保时捷911那么明显，而Java能给你的，Go能给得更好。&lt;/p&gt;
&lt;p&gt;如果你是C++爱好者，!@#$%^&amp;amp;*，恭喜你，至少你的智商应该是没问题的。人生苦短，赶紧脱离C++这个苦海吧。你用来学89个C++高级特性的时间，估计已经用Go写了64个开源项目了。&lt;/p&gt;
&lt;p&gt;如果你是像我一样的C和Python的爱好者，对动态语言又没有特殊的热爱&amp;#8230;&amp;#8230;我还需要说什么呢？&lt;/p&gt;
&lt;p&gt;让我们荡起双桨，去遨游&lt;a href=&quot;http://golang.org/doc/install.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/golang.org');&quot;&gt;Golang的海洋&lt;/a&gt;吧。&lt;br /&gt;
&lt;h3&gt;Random Posts&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207162/windstorm/feedsky/s.gif?r=http://www.kunli.info/2012/03/03/golang-feeling/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">code</category><category domain="http://www.kunli.info">golang</category><category domain="http://www.kunli.info">感受</category><pubDate>Sun, 04 Mar 2012 01:33:07 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1652</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2012/03/03/golang-feeling/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207162/1226385</fs:itemid></item><item><title>Android Native 代码NDK开发学习笔记</title><link atom:type="text/html">http://www.kunli.info/2011/08/21/android-native-code-study-note/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1597</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/08/21/android-native-code-study-note/">&lt;p&gt;本文提供排版更佳的&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/08/JNIDocumentChinese.pdf&quot; &gt;PDF&lt;/a&gt;版本下载。&lt;/p&gt;
&lt;p&gt;JNI，全称Java Native Interface，是用于让运行在JVM中的Java代码和运行在JVM外的Native代码（主要是C或者C++）沟通的桥梁。代码编写者即可以使用JNI从Java的程序中调用Native代码，又可以从Native程序中调用Java代码。这样，编程人员可以将低阶的代码逻辑包装到高阶的程序框架中，获得高性能高效率的同时保证了代码框架的高抽象性。&lt;/p&gt;
&lt;p&gt;在Android中，仅有以下类库是允许在JNI中使用的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;libc (C library) headers&lt;/li&gt;
&lt;li&gt;libm (math library) headers&lt;/li&gt;
&lt;li&gt;JNI interface headers&lt;/li&gt;
&lt;li&gt;libz (Zlib compression) headers&lt;/li&gt;
&lt;li&gt;liblog (Android logging) header&lt;/li&gt;
&lt;li&gt;OpenGL ES 1.1 (3D graphics library) headers (since 1.6)&lt;/li&gt;
&lt;li&gt;A Minimal set of headers for C++ support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JNI本身仅仅是一个把两者融合的工具，作为编程者需要做的，就是在Java代码和Native代码中按照固定的格式告诉JNI如何调用对方。在Android中，有两种方式可以调用JNI，一种是Google release的专门针对Android Native开发的工具包，叫做NDK。去Android网站上下载该工具包后，就可以通过阅读里面的文档来setup一个新的包含Native代码的工程，创建自己的Android.mk文件，编译等等；另一种是完整的源码编译环境 ，也就是通过git从官方网站获取完全的Android源代码平台。这个平台中提供有基于make的编译系统。更多细节请参考&lt;a href=&quot;http://source.android.com/index.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/source.android.com');&quot;&gt;这里&lt;/a&gt;。不管选择以上两种方法的哪一个，都必须编写自己的Android.mk文件，有关该文件的编写请参考相关文档。&lt;/p&gt;
&lt;p&gt;下面通过一个简单的使用例子来讲解JNI。Android给C和C++提供的是两套不同的Native API，本文仅以C++举例说明。假设这么一个需求，Java代码需要打印一个字符串，而该字符串需要Native代码计算生成。对应的JNI流程是这样的：&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1597&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;1. 在准备打印字符串的Android类中，添加两段代码。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;第一段是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;private native String getPrintStr();&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;这一行代码的目的是告诉JNI，这个Java文件中有这么一个函数，该函数是在Native代码中执行的，Native代码会返回一个字符串供Java代码来输出。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;第二段是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;try {System.loadLibrary(&amp;#8220;LIBNAME&amp;#8221; }&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;catch (UnsatisfiedLinkError ule) {Log.e(TAG, &amp;#8220;Could not load native library&amp;#8221;);}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;这两行代码是告诉JNI，你需要找的所有Native函数都在libLIBNAME.so这个动态库中。注意JNI会自动补全lib和so给LIBNAME，你只需要提供LIBNAME给loadLibrary就行了。在最后执行的时候，JNI会先找到这个动态库，然后找里面的OnLoad函数，具体注册流程由OnLoad函数接管。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;关于如何确定这个LIBNAME，和如何定义OnLoad函数，下面就会讲。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;2. 上面的第一步是告诉JNI，java代码需要和Native代码交互，同时把在哪里找，找什么都通知了。接下来的事情就由Native端接管。如果把上面的getPrintString函数申明比作原型，那么本地代码中的具体函数定义就应该和该原型匹配，JNI才能知道具体在哪里执行代码。具体来说，应该有一个对应的Native函数，有和Java中定义的函数同样的参数列表以及返回值。另外，还需要有某种机制让JNI将两者相互映射，方便参数和返回值的传递。在老版的JNI中，这是通过丑陋的命名匹配实现的，比如说在Java中定义的函数名是getPrintStr, 该函数属于package java.come.android.xxx，那么中对应Native代码中的函数名就应该是Java_com_android_xxx_getPrintStr。这样给开发人员带来了很多不便。可以用javah命令来生成对应Java code中定义函数的Native code版本header文件，从中得知传统的匹配方法是如何做的。具体过程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过SDK的方式编译Java代码。&lt;/li&gt;
&lt;li&gt;找到Eclipse的工程目录，进入bin目录下。这里是编译出的java文件所对应的class文件所在。&lt;/li&gt;
&lt;li&gt;假设包括Native函数调用的java文件属于com.android.xxx package，名字叫test.java，那么在bin下执行javah -jni com.android.xxx.test&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;ltr&quot;&gt;执行完后，可以看到一个新生成的header文件，名字为com_android_xxx_test.h。打开后会发现已经有一个函数申明，函数名为java_com_android_xxx_test_getPrintStr。这个名字就包括了该函数所对应Java版本所在的包，文件以及名称。这就是JNI传统的确定名字的方法。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;值得注意的是，header文件中不仅包含了基于函数名的映射信息，还包含了另一个重要信息，就是signature。一个函数的signature是一个字符串，描述了这个函数的参数和返回值。其中&amp;#8221;()&amp;#8221; 中的字符表示参数，后面的则代表返回值。例如&amp;#8221;()V&amp;#8221; 就表示void Func(); &amp;#8220;(II)V&amp;#8221; 表示 void Func(int, int); 数组则以&amp;#8221;[&quot;开始，用两个字符表示。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;具体的每一个字符的对应关系如下：&lt;/p&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col width=&quot;96&quot;&gt;&lt;/col&gt;
&lt;col width=&quot;103&quot;&gt;&lt;/col&gt;
&lt;col width=&quot;110&quot;&gt;&lt;/col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;字符&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;Java类型&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;C类型&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;V&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;void&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;void&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;I&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jint&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;int&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;Z&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jboolean&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;boolean&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;J&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jlong&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;long&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;D&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jdouble&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;double&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;F&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jfloat&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;float&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;B&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jbyte&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;byte&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;C&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jchar&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;char&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;S&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jshort&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;short&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p dir=&quot;ltr&quot;&gt;上面的都是基本类型。如果Java函数的参数是class，则以&quot;L&quot;开头，以&quot;;&quot;结尾，中间是用&quot;/&quot; 隔开的包及类名。而其对应的C函数名的参数则为jobject。 一个例外是String类，其对应的类为jstring。举例：&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;Ljava/lang/String; String jstring&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;Ljava/net/Socket; Socket jobject&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;如果JAVA函数位于一个嵌入类，则用$作为类名间的分隔符。例如 &quot;(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z&quot;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;这个signature非常重要，是下面要介绍的新版命名匹配方法的关键点之一。所以，即使传统的命名匹配已经不再使用，javah这一步操作还是必须的，因为可以从中得到Java代码中需要Native执行的函数的签名，以供后面使用。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;3. 在新版（版本号大于1.4）的JNI中，Android提供了另一个机制来解决命名匹配问题，那就是JNI_OnLoad。正如前面所述，每一次JNI执行Native代码，都是通过调用JNI_OnLoad实现的。下面的代码是针对本例的OnLoad代码：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;/* Returns the JNI version on success, -1 on failure.&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;jint JNI_OnLoad(JavaVM* vm, void* reserved) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;JNIEnv* env = NULL;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;jint result = -1;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (vm-&amp;gt;GetEnv((void**) &amp;amp;env, JNI_VERSION_1_4) != JNI_OK) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&quot;ERROR: GetEnv failed&quot;);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;goto bail;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;assert(env != NULL);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (!register_Test(env)) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&quot;ERROR: Test native registration failed&quot;);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;goto bail;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;/* success -- return valid version number */&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;result = JNI_VERSION_1_4;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;bail:  return result;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;分析这个函数。首先，OnLoad通过GetEnv函数获取JNI的环境对象，然后通过register_Test来注册Native函数。register_Test的实现如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;int register_Test(JNIEnv *env) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const char* const ClassPathName  ＝ &quot;com/android/xxx/test&quot;;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return registerNativeMethods(env, ClassPathName, TestMethods,&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;sizeof(TestMethods) / sizeof(TestMethods[0]));&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这里，ClassPathName是Java类的全名，包括package的全名。只是用 “/” 代替 ”.” 。然后我们把类名以及TestMethods这个参数一同送到registerNativeMethods这个函数中注册。这个函数是基于JNI_OnLoad的命名匹配方式的重点。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;在JNI中，代码编写者通过函数signature名和映射表的配合，来告诉JNI_OnLoad，你要找的函数在Native代码中是如何定义的（signature），以及在哪定义的（映射表）。关于signature的生成和含义，在上面已经介绍。而映射表，是Android使用的一种用于映射Java和C/C++函数的数组，这个数组的类型是JNINativeMethod，定义为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;typedef struct {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const char* name;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const char* signature;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;void* fnPtr;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;} JNINativeMethod;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中，第一个变量是Java代码中的函数名称。第二个变量是该函数对应的Native signature。第三个变量是该函数对应的Native函数的函数指针。例如，在上面register_Test的函数实现中，传给registerNativeMethods的参数TestMethods就是映射表，定义如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;static JNINativeMethod TestMethods[] = {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;{&amp;#8220;getPrintStr&amp;#8221;, &amp;#8220;()Ljava/lang/String&amp;#8221;, (void*)test_getPrintStr}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;};&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;其中getPrintStr是在Java代码中定义的函数的名称，()Ljava/lang/String是签名，因为该函数无参数传入，并返回一个String。test_getPrintStr则是我们即将在Native code中定义的函数名称。该映射表和前面定义的类名ClassPathName一起传入registerNativeMethods：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod*     Methods, int numMethods) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;jclass clazz;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;clazz = env-&amp;gt;FindClass(className);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (clazz == NULL) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&amp;#8220;Native registration unable to find class &amp;#8216;%s&amp;#8217;&amp;#8221;, className);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return JNI_FALSE；&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (env-&amp;gt;RegisterNatives(clazz, gMethods, numMethods) &amp;lt; 0) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&amp;#8220;RegisterNatives failed for &amp;#8216;%s&amp;#8217;&amp;#8221;, className);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return JNI_FALSE;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return JNI_TRUE;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这里，先load目标类，然后注册Native函数，然后返回状态。&lt;/p&gt;
&lt;p&gt;可以看出，通过映射表方式，Java code中的函数名不须再和Native code中的函数名呆板对应。只需要将函数注册进映射表中，Native code的函数编写就有了很大的灵活性。虽说和前一种传统的匹配方法比，这种方式并没有效率上的改进，因为两者本质上都是从JNI load开始做函数映射。但是这一种register的方法极大降低了两边的耦合性，所以实际使用中会受欢迎得多。比如说，由于映射表是一个&amp;lt;名称，函数指针&amp;gt;对照表，在程序执行时，可多次调用registerNativeMethods()函数来更换本地函数指针，而达到弹性抽换本地函数的目的。&lt;/p&gt;
&lt;p&gt;4. 接下来本应介绍test_getPrintStr。但在此之前，简单介绍Android.mk，也就是编译NDK所需要的Makefile，从而完成JNI信息链的讲解。Android.mk可以基于模版修改，里面重要的变量包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LOCAL_C_INCLUDES：包含的头文件。这里需要包含JNI的头文件。&lt;/li&gt;
&lt;li&gt;LOCAL_SRC_FILES: 包含的源文件。&lt;/li&gt;
&lt;li&gt;LOCAL_MODULE：当前模块的名称，也就是第一步中我们提到的LIBNAME。注意这个需要加上lib前缀，但不需要加.so后缀，也就是说应该是libLIBNAME。&lt;/li&gt;
&lt;li&gt;LOCAL_SHARED_LIBRARIES：当前模块需要依赖的共享库。&lt;/li&gt;
&lt;li&gt;LOCAL_PRELINK_MODULE：该模块是否被启动就加载。该项设置依具体程序的特性而定。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;5. 至此，JNI作为桥梁所需要的所有信息均已就绪。JNI知道在调用Java代码中的getPrintStr函数时，需要执行Native代码。于是通过System.loadLibrary所加载的libLIBNAME.so找到OnLoad入口。在OnLoad中，JNI发现了函数映射表，发现getPrintStr对应的Native函数是test_getPrintStr。于是JNI将参数（如果有的话）传递给test_getPrintStr并执行，再将返回值（如果有的话）传回Java中的getPrintStr。&lt;/p&gt;
&lt;p&gt;6. 用于最后测试的test_getPrintStr函数实现如下：&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const jstring testStr = env-&amp;gt;NewStringUTF(&amp;#8220;hello, world&amp;#8221;);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return testStr;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;然后在Java代码中打印出返回的字符串即可。&lt;a href=&quot;http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/download.oracle.com');&quot;&gt;这个网页&lt;/a&gt;详细介绍了env可以调用的所有方法。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;7. 关于测试时使用Log。调用JNI进行Native Code的开发有两种环境，完整源码环境以及NDK。两种环境对应的Log输出方式也并不相同，差异则主要体现在需要包含的头文件中。如果是在完整源码编译环境下，只要include &amp;lt;utils/Log.h&amp;gt;头文件（位于Android-src/system/core/include/cutils），就可以使用对应的LOGI、LOGD等方法了，当然LOG_TAG，LOG_NDEBUG等宏值需要自定义。如果是在NDK环境下编译，则需要include &amp;lt;android/log.h&amp;gt;头文件（位于ndk/android-ndk-r4/platforms/android-8/arch-arm/usr/include/android/），另外自己定义宏映射，例如：&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#include &amp;lt;android/log.h&amp;gt;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#ifndef LOG_TAG&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOG_TAG &amp;#8220;MY_LOG_TAG&amp;#8221;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#endif&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGD(&amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGI(&amp;#8230;) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGW(&amp;#8230;) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGE(&amp;#8230;) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGF(&amp;#8230;) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;另外，在Android.mk文件中对类库的应用在两种环境下也不相同。如果是NDK环境下，需要包括&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOCAL_LDLIBS := -llog&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;而在完整源码环境下，则需要包括&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOCAL_SHARED_LIBRARIES := libutils libcutils&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;8. 如果希望知道如何在Native中访问Java类的私有域和方法，请参考&lt;a href=&quot;http://hi.baidu.com/yeshaoting/blog/item/5b6eacee548fdcfbce1b3eba.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/hi.baidu.com');&quot; target=&quot;_blank&quot;&gt;这篇文章&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-12-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot;  title=&quot;一个新的开源项目Libsvm-androidjni&quot;&gt;一个新的开源项目Libsvm-androidjni (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-06 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/06/android-graphics/&quot;  title=&quot;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像&quot;&gt;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-04 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  title=&quot;谈谈Android 4.0&quot;&gt;谈谈Android 4.0 (11)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>2</thr:total><description>本文提供排版更佳的PDF版本下载。 JNI，全称Java Native Interface，是用于让运行在JVM中的Java代码和运行在JVM外的Native代码（主要是C或者C++）沟通的桥梁。代码编写者即可以使用JNI从Java的程序中调用Native代码，又可以从Native程序中调用Java代码。这样，编程人员可以将低阶的代码逻辑包装到高阶的程序框架中，获得高性能高效率的同时保证了代码框架的高抽象性。 在Android中，仅有以下类库是允许在JNI中使用的： libc (C library) headers libm (math library) headers JNI interface headers libz (Zlib compression) headers liblog (Android logging) header OpenGL ES 1.1 (3D graphics library) headers (since 1.6) A Minimal set of headers for C++ support JNI本身仅仅是一个把两者融合的工具，作为编程者需要做的，就是在Java代码和Native代码中按照固定的格式告诉JNI如何调用对方。在Android中，有两种方式可以调用JNI，一种是Google release的专门针对Android Native开发的工具包，叫做NDK。去Android网站上下载该工具包后，就可以通过阅读里面的文档来setup一个新的包含Native代码的工程，创建自己的Android.mk文件，编译等等；另一种是完整的源码编译环境 ，也就是通过git从官方网站获取完全的Android源代码平台。这个平台中提供有基于make的编译系统。更多细节请参考这里。不管选择以上两种方法的哪一个，都必须编写自己的Android.mk文件，有关该文件的编写请参考相关文档。 下面通过一个简单的使用例子来讲解JNI。Android给C和C++提供的是两套不同的Native API，本文仅以C++举例说明。假设这么一个需求，Java代码需要打印一个字符串，而该字符串需要Native代码计算生成。对应的JNI流程是这样的： 1. 在准备打印字符串的Android类中，添加两段代码。 第一段是： private native String getPrintStr(); 这一行代码的目的是告诉JNI，这个Java文件中有这么一个函数，该函数是在Native代码中执行的，Native代码会返回一个字符串供Java代码来输出。 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207169/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;本文提供排版更佳的&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/08/JNIDocumentChinese.pdf&quot; &gt;PDF&lt;/a&gt;版本下载。&lt;/p&gt;
&lt;p&gt;JNI，全称Java Native Interface，是用于让运行在JVM中的Java代码和运行在JVM外的Native代码（主要是C或者C++）沟通的桥梁。代码编写者即可以使用JNI从Java的程序中调用Native代码，又可以从Native程序中调用Java代码。这样，编程人员可以将低阶的代码逻辑包装到高阶的程序框架中，获得高性能高效率的同时保证了代码框架的高抽象性。&lt;/p&gt;
&lt;p&gt;在Android中，仅有以下类库是允许在JNI中使用的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;libc (C library) headers&lt;/li&gt;
&lt;li&gt;libm (math library) headers&lt;/li&gt;
&lt;li&gt;JNI interface headers&lt;/li&gt;
&lt;li&gt;libz (Zlib compression) headers&lt;/li&gt;
&lt;li&gt;liblog (Android logging) header&lt;/li&gt;
&lt;li&gt;OpenGL ES 1.1 (3D graphics library) headers (since 1.6)&lt;/li&gt;
&lt;li&gt;A Minimal set of headers for C++ support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JNI本身仅仅是一个把两者融合的工具，作为编程者需要做的，就是在Java代码和Native代码中按照固定的格式告诉JNI如何调用对方。在Android中，有两种方式可以调用JNI，一种是Google release的专门针对Android Native开发的工具包，叫做NDK。去Android网站上下载该工具包后，就可以通过阅读里面的文档来setup一个新的包含Native代码的工程，创建自己的Android.mk文件，编译等等；另一种是完整的源码编译环境 ，也就是通过git从官方网站获取完全的Android源代码平台。这个平台中提供有基于make的编译系统。更多细节请参考&lt;a href=&quot;http://source.android.com/index.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/source.android.com');&quot;&gt;这里&lt;/a&gt;。不管选择以上两种方法的哪一个，都必须编写自己的Android.mk文件，有关该文件的编写请参考相关文档。&lt;/p&gt;
&lt;p&gt;下面通过一个简单的使用例子来讲解JNI。Android给C和C++提供的是两套不同的Native API，本文仅以C++举例说明。假设这么一个需求，Java代码需要打印一个字符串，而该字符串需要Native代码计算生成。对应的JNI流程是这样的：&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1597&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;1. 在准备打印字符串的Android类中，添加两段代码。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;第一段是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;private native String getPrintStr();&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;这一行代码的目的是告诉JNI，这个Java文件中有这么一个函数，该函数是在Native代码中执行的，Native代码会返回一个字符串供Java代码来输出。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;第二段是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;try {System.loadLibrary(&amp;#8220;LIBNAME&amp;#8221; }&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;catch (UnsatisfiedLinkError ule) {Log.e(TAG, &amp;#8220;Could not load native library&amp;#8221;);}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;这两行代码是告诉JNI，你需要找的所有Native函数都在libLIBNAME.so这个动态库中。注意JNI会自动补全lib和so给LIBNAME，你只需要提供LIBNAME给loadLibrary就行了。在最后执行的时候，JNI会先找到这个动态库，然后找里面的OnLoad函数，具体注册流程由OnLoad函数接管。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;关于如何确定这个LIBNAME，和如何定义OnLoad函数，下面就会讲。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;2. 上面的第一步是告诉JNI，java代码需要和Native代码交互，同时把在哪里找，找什么都通知了。接下来的事情就由Native端接管。如果把上面的getPrintString函数申明比作原型，那么本地代码中的具体函数定义就应该和该原型匹配，JNI才能知道具体在哪里执行代码。具体来说，应该有一个对应的Native函数，有和Java中定义的函数同样的参数列表以及返回值。另外，还需要有某种机制让JNI将两者相互映射，方便参数和返回值的传递。在老版的JNI中，这是通过丑陋的命名匹配实现的，比如说在Java中定义的函数名是getPrintStr, 该函数属于package java.come.android.xxx，那么中对应Native代码中的函数名就应该是Java_com_android_xxx_getPrintStr。这样给开发人员带来了很多不便。可以用javah命令来生成对应Java code中定义函数的Native code版本header文件，从中得知传统的匹配方法是如何做的。具体过程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过SDK的方式编译Java代码。&lt;/li&gt;
&lt;li&gt;找到Eclipse的工程目录，进入bin目录下。这里是编译出的java文件所对应的class文件所在。&lt;/li&gt;
&lt;li&gt;假设包括Native函数调用的java文件属于com.android.xxx package，名字叫test.java，那么在bin下执行javah -jni com.android.xxx.test&lt;/li&gt;
&lt;/ol&gt;
&lt;p dir=&quot;ltr&quot;&gt;执行完后，可以看到一个新生成的header文件，名字为com_android_xxx_test.h。打开后会发现已经有一个函数申明，函数名为java_com_android_xxx_test_getPrintStr。这个名字就包括了该函数所对应Java版本所在的包，文件以及名称。这就是JNI传统的确定名字的方法。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;值得注意的是，header文件中不仅包含了基于函数名的映射信息，还包含了另一个重要信息，就是signature。一个函数的signature是一个字符串，描述了这个函数的参数和返回值。其中&amp;#8221;()&amp;#8221; 中的字符表示参数，后面的则代表返回值。例如&amp;#8221;()V&amp;#8221; 就表示void Func(); &amp;#8220;(II)V&amp;#8221; 表示 void Func(int, int); 数组则以&amp;#8221;[&quot;开始，用两个字符表示。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;具体的每一个字符的对应关系如下：&lt;/p&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col width=&quot;96&quot;&gt;&lt;/col&gt;
&lt;col width=&quot;103&quot;&gt;&lt;/col&gt;
&lt;col width=&quot;110&quot;&gt;&lt;/col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;字符&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;Java类型&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;C类型&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;V&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;void&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;void&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;I&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jint&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;int&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;Z&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jboolean&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;boolean&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;J&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jlong&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;long&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;D&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jdouble&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;double&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;F&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jfloat&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;float&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;B&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jbyte&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;byte&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;C&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jchar&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;char&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;S&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;jshort&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p dir=&quot;ltr&quot;&gt;short&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p dir=&quot;ltr&quot;&gt;上面的都是基本类型。如果Java函数的参数是class，则以&quot;L&quot;开头，以&quot;;&quot;结尾，中间是用&quot;/&quot; 隔开的包及类名。而其对应的C函数名的参数则为jobject。 一个例外是String类，其对应的类为jstring。举例：&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;Ljava/lang/String; String jstring&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;Ljava/net/Socket; Socket jobject&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;如果JAVA函数位于一个嵌入类，则用$作为类名间的分隔符。例如 &quot;(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z&quot;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;这个signature非常重要，是下面要介绍的新版命名匹配方法的关键点之一。所以，即使传统的命名匹配已经不再使用，javah这一步操作还是必须的，因为可以从中得到Java代码中需要Native执行的函数的签名，以供后面使用。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;3. 在新版（版本号大于1.4）的JNI中，Android提供了另一个机制来解决命名匹配问题，那就是JNI_OnLoad。正如前面所述，每一次JNI执行Native代码，都是通过调用JNI_OnLoad实现的。下面的代码是针对本例的OnLoad代码：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;/* Returns the JNI version on success, -1 on failure.&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;jint JNI_OnLoad(JavaVM* vm, void* reserved) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;JNIEnv* env = NULL;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;jint result = -1;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (vm-&amp;gt;GetEnv((void**) &amp;amp;env, JNI_VERSION_1_4) != JNI_OK) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&quot;ERROR: GetEnv failed&quot;);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;goto bail;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;assert(env != NULL);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (!register_Test(env)) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&quot;ERROR: Test native registration failed&quot;);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;goto bail;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;/* success -- return valid version number */&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;result = JNI_VERSION_1_4;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;bail:  return result;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;分析这个函数。首先，OnLoad通过GetEnv函数获取JNI的环境对象，然后通过register_Test来注册Native函数。register_Test的实现如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;int register_Test(JNIEnv *env) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const char* const ClassPathName  ＝ &quot;com/android/xxx/test&quot;;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return registerNativeMethods(env, ClassPathName, TestMethods,&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;sizeof(TestMethods) / sizeof(TestMethods[0]));&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这里，ClassPathName是Java类的全名，包括package的全名。只是用 “/” 代替 ”.” 。然后我们把类名以及TestMethods这个参数一同送到registerNativeMethods这个函数中注册。这个函数是基于JNI_OnLoad的命名匹配方式的重点。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;在JNI中，代码编写者通过函数signature名和映射表的配合，来告诉JNI_OnLoad，你要找的函数在Native代码中是如何定义的（signature），以及在哪定义的（映射表）。关于signature的生成和含义，在上面已经介绍。而映射表，是Android使用的一种用于映射Java和C/C++函数的数组，这个数组的类型是JNINativeMethod，定义为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;typedef struct {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const char* name;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const char* signature;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;void* fnPtr;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;} JNINativeMethod;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中，第一个变量是Java代码中的函数名称。第二个变量是该函数对应的Native signature。第三个变量是该函数对应的Native函数的函数指针。例如，在上面register_Test的函数实现中，传给registerNativeMethods的参数TestMethods就是映射表，定义如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;static JNINativeMethod TestMethods[] = {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;{&amp;#8220;getPrintStr&amp;#8221;, &amp;#8220;()Ljava/lang/String&amp;#8221;, (void*)test_getPrintStr}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;};&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;其中getPrintStr是在Java代码中定义的函数的名称，()Ljava/lang/String是签名，因为该函数无参数传入，并返回一个String。test_getPrintStr则是我们即将在Native code中定义的函数名称。该映射表和前面定义的类名ClassPathName一起传入registerNativeMethods：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p dir=&quot;ltr&quot;&gt;static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod*     Methods, int numMethods) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;jclass clazz;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;clazz = env-&amp;gt;FindClass(className);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (clazz == NULL) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&amp;#8220;Native registration unable to find class &amp;#8216;%s&amp;#8217;&amp;#8221;, className);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return JNI_FALSE；&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;if (env-&amp;gt;RegisterNatives(clazz, gMethods, numMethods) &amp;lt; 0) {&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOGE(&amp;#8220;RegisterNatives failed for &amp;#8216;%s&amp;#8217;&amp;#8221;, className);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return JNI_FALSE;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return JNI_TRUE;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这里，先load目标类，然后注册Native函数，然后返回状态。&lt;/p&gt;
&lt;p&gt;可以看出，通过映射表方式，Java code中的函数名不须再和Native code中的函数名呆板对应。只需要将函数注册进映射表中，Native code的函数编写就有了很大的灵活性。虽说和前一种传统的匹配方法比，这种方式并没有效率上的改进，因为两者本质上都是从JNI load开始做函数映射。但是这一种register的方法极大降低了两边的耦合性，所以实际使用中会受欢迎得多。比如说，由于映射表是一个&amp;lt;名称，函数指针&amp;gt;对照表，在程序执行时，可多次调用registerNativeMethods()函数来更换本地函数指针，而达到弹性抽换本地函数的目的。&lt;/p&gt;
&lt;p&gt;4. 接下来本应介绍test_getPrintStr。但在此之前，简单介绍Android.mk，也就是编译NDK所需要的Makefile，从而完成JNI信息链的讲解。Android.mk可以基于模版修改，里面重要的变量包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LOCAL_C_INCLUDES：包含的头文件。这里需要包含JNI的头文件。&lt;/li&gt;
&lt;li&gt;LOCAL_SRC_FILES: 包含的源文件。&lt;/li&gt;
&lt;li&gt;LOCAL_MODULE：当前模块的名称，也就是第一步中我们提到的LIBNAME。注意这个需要加上lib前缀，但不需要加.so后缀，也就是说应该是libLIBNAME。&lt;/li&gt;
&lt;li&gt;LOCAL_SHARED_LIBRARIES：当前模块需要依赖的共享库。&lt;/li&gt;
&lt;li&gt;LOCAL_PRELINK_MODULE：该模块是否被启动就加载。该项设置依具体程序的特性而定。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;5. 至此，JNI作为桥梁所需要的所有信息均已就绪。JNI知道在调用Java代码中的getPrintStr函数时，需要执行Native代码。于是通过System.loadLibrary所加载的libLIBNAME.so找到OnLoad入口。在OnLoad中，JNI发现了函数映射表，发现getPrintStr对应的Native函数是test_getPrintStr。于是JNI将参数（如果有的话）传递给test_getPrintStr并执行，再将返回值（如果有的话）传回Java中的getPrintStr。&lt;/p&gt;
&lt;p&gt;6. 用于最后测试的test_getPrintStr函数实现如下：&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;const jstring testStr = env-&amp;gt;NewStringUTF(&amp;#8220;hello, world&amp;#8221;);&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;return testStr;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;然后在Java代码中打印出返回的字符串即可。&lt;a href=&quot;http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/download.oracle.com');&quot;&gt;这个网页&lt;/a&gt;详细介绍了env可以调用的所有方法。&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;7. 关于测试时使用Log。调用JNI进行Native Code的开发有两种环境，完整源码环境以及NDK。两种环境对应的Log输出方式也并不相同，差异则主要体现在需要包含的头文件中。如果是在完整源码编译环境下，只要include &amp;lt;utils/Log.h&amp;gt;头文件（位于Android-src/system/core/include/cutils），就可以使用对应的LOGI、LOGD等方法了，当然LOG_TAG，LOG_NDEBUG等宏值需要自定义。如果是在NDK环境下编译，则需要include &amp;lt;android/log.h&amp;gt;头文件（位于ndk/android-ndk-r4/platforms/android-8/arch-arm/usr/include/android/），另外自己定义宏映射，例如：&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#include &amp;lt;android/log.h&amp;gt;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#ifndef LOG_TAG&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOG_TAG &amp;#8220;MY_LOG_TAG&amp;#8221;&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#endif&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGD(&amp;#8230;) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGI(&amp;#8230;) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGW(&amp;#8230;) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGE(&amp;#8230;) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;#define LOGF(&amp;#8230;) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__)&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;另外，在Android.mk文件中对类库的应用在两种环境下也不相同。如果是NDK环境下，需要包括&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOCAL_LDLIBS := -llog&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;而在完整源码环境下，则需要包括&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;LOCAL_SHARED_LIBRARIES := libutils libcutils&lt;/p&gt;
&lt;p dir=&quot;ltr&quot;&gt;8. 如果希望知道如何在Native中访问Java类的私有域和方法，请参考&lt;a href=&quot;http://hi.baidu.com/yeshaoting/blog/item/5b6eacee548fdcfbce1b3eba.html&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/hi.baidu.com');&quot; target=&quot;_blank&quot;&gt;这篇文章&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-12-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot;  title=&quot;一个新的开源项目Libsvm-androidjni&quot;&gt;一个新的开源项目Libsvm-androidjni (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-06 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/06/android-graphics/&quot;  title=&quot;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像&quot;&gt;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-04 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  title=&quot;谈谈Android 4.0&quot;&gt;谈谈Android 4.0 (11)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207169/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">杂项</category><category domain="http://www.kunli.info">android</category><category domain="http://www.kunli.info">jni</category><category domain="http://www.kunli.info">NDK</category><pubDate>Sun, 22 Jan 2012 01:49:32 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1597</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/08/21/android-native-code-study-note/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207169/1226385</fs:itemid></item><item><title>一个新的开源项目Libsvm-androidjni</title><link atom:type="text/html">http://www.kunli.info/2011/12/21/libsvm-androidjni-project/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1644</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/12/21/libsvm-androidjni-project/">&lt;p&gt;我创建了一个关于libsvm库+Android的开源项目 &lt;a href=&quot;https://github.com/cnbuff410/Libsvm-androidjni&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/github.com');&quot;&gt;Libsvm-androidjni&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;这个项目的目的是让当今最流行的SVM支持向量机机器学习库Libsvm被移植到Android平台中。当然官方提供了Java库，但用Java来进行大规模的SVM计算还是太低效了，所以这个项目是要把c/c++版本的库移植到JNI环境下。&lt;/p&gt;
&lt;p&gt;目前的code状态是svm的training和prediction功能皆可正常运行。具体的使用方式请参考README。虽然是c++环境，但主体code还是c的风格，这和我个人喜好有关，不影响使用。&lt;/p&gt;
&lt;p&gt;目前还有一些高级功能不完善，比如完整的参数传递和误差计算。&lt;/p&gt;
&lt;p&gt;项目代码请到&lt;a href=&quot;https://github.com/cnbuff410/Libsvm-androidjni&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/github.com');&quot;&gt;https://github.com/cnbuff410/Libsvm-androidjni&lt;/a&gt;下载。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-08-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot;  title=&quot;Android Native 代码NDK开发学习笔记&quot;&gt;Android Native 代码NDK开发学习笔记 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-06 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/06/android-graphics/&quot;  title=&quot;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像&quot;&gt;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-04 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  title=&quot;谈谈Android 4.0&quot;&gt;谈谈Android 4.0 (11)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>5</thr:total><description>我创建了一个关于libsvm库+Android的开源项目 Libsvm-androidjni. 这个项目的目的是让当今最流行的SVM支持向量机机器学习库Libsvm被移植到Android平台中。当然官方提供了Java库，但用Java来进行大规模的SVM计算还是太低效了，所以这个项目是要把c/c++版本的库移植到JNI环境下。 目前的code状态是svm的training和prediction功能皆可正常运行。具体的使用方式请参考README。虽然是c++环境，但主体code还是c的风格，这和我个人喜好有关，不影响使用。 目前还有一些高级功能不完善，比如完整的参数传递和误差计算。 项目代码请到https://github.com/cnbuff410/Libsvm-androidjni下载。 也许你还会对这些文章感兴趣 2011-11-17 &amp;#8212; 如何对Android的本地代码进行profiling (0) 2011-08-21 &amp;#8212; Android Native 代码NDK开发学习笔记 (2) 2011-12-06 &amp;#8212; Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9) 2011-12-04 &amp;#8212; 谈谈Android 4.0 (11) 2011-01-20 &amp;#8212; 聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1) 2010-09-29 &amp;#8212; Android上Tcpdump的使用 (0) 2010-07-18 &amp;#8212; Samsung Galaxy S上手感受 (6) 2010-06-18 &amp;#8212; Gingerbread，向左走还是向右走？ (5) 2010-06-09 &amp;#8212; Android机器人T-shirt情侣衫照 (6) 2010-05-31 &amp;#8212; Android并不伟大，但丝毫不令人沮丧 (6) 2010-02-11 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207163/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;我创建了一个关于libsvm库+Android的开源项目 &lt;a href=&quot;https://github.com/cnbuff410/Libsvm-androidjni&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/github.com');&quot;&gt;Libsvm-androidjni&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;这个项目的目的是让当今最流行的SVM支持向量机机器学习库Libsvm被移植到Android平台中。当然官方提供了Java库，但用Java来进行大规模的SVM计算还是太低效了，所以这个项目是要把c/c++版本的库移植到JNI环境下。&lt;/p&gt;
&lt;p&gt;目前的code状态是svm的training和prediction功能皆可正常运行。具体的使用方式请参考README。虽然是c++环境，但主体code还是c的风格，这和我个人喜好有关，不影响使用。&lt;/p&gt;
&lt;p&gt;目前还有一些高级功能不完善，比如完整的参数传递和误差计算。&lt;/p&gt;
&lt;p&gt;项目代码请到&lt;a href=&quot;https://github.com/cnbuff410/Libsvm-androidjni&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/github.com');&quot;&gt;https://github.com/cnbuff410/Libsvm-androidjni&lt;/a&gt;下载。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-08-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot;  title=&quot;Android Native 代码NDK开发学习笔记&quot;&gt;Android Native 代码NDK开发学习笔记 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-06 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/06/android-graphics/&quot;  title=&quot;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像&quot;&gt;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-04 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  title=&quot;谈谈Android 4.0&quot;&gt;谈谈Android 4.0 (11)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207163/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">android</category><category domain="http://www.kunli.info">c</category><category domain="http://www.kunli.info">code</category><category domain="http://www.kunli.info">jni</category><category domain="http://www.kunli.info">libsvm</category><category domain="http://www.kunli.info">native</category><category domain="http://www.kunli.info">port</category><pubDate>Wed, 21 Dec 2011 15:29:03 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1644</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/12/21/libsvm-androidjni-project/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207163/1226385</fs:itemid></item><item><title>输入数学公式的Chrome应用推荐</title><link atom:type="text/html">http://www.kunli.info/2011/12/15/math-equation-in-chrome/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1641</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/12/15/math-equation-in-chrome/">&lt;p&gt;我曾经写过的一篇博客是&lt;a href=&quot;http://www.kunli.info/2008/06/17/howto-use-latex-in-blog/&quot; &gt;在blog中用LaTex输入数学公式&lt;/a&gt;。里面提到过“在线生成的方法”，并推荐了几个网站。今天在Chrome应用商店里发现了一个应用叫&lt;a href=&quot;https://chrome.google.com/webstore/search/Daum%20Equation%20Editor&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/chrome.google.com');&quot;&gt;Daum Equation Editor&lt;/a&gt;，非常非常好用，界面漂亮，选项众多，支持字体特效和大小的调整，输出图片或者latex文字。基本上秒杀我那篇文章里推荐的那些软件。所以在这里再推荐一下:)&lt;br /&gt;
&lt;h3&gt;Random Posts&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>4</thr:total><description>我曾经写过的一篇博客是在blog中用LaTex输入数学公式。里面提到过“在线生成的方法”，并推荐了几个网站。今天在Chrome应用商店里发现了一个应用叫Daum Equation Editor，非常非常好用，界面漂亮，选项众多，支持字体特效和大小的调整，输出图片或者latex文字。基本上秒杀我那篇文章里推荐的那些软件。所以在这里再推荐一下:) Random Posts visit the website for more great content.&lt;img src=&quot;http://www1.feedsky.com/t1/631207164/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/15/math-equation-in-chrome/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;我曾经写过的一篇博客是&lt;a href=&quot;http://www.kunli.info/2008/06/17/howto-use-latex-in-blog/&quot; &gt;在blog中用LaTex输入数学公式&lt;/a&gt;。里面提到过“在线生成的方法”，并推荐了几个网站。今天在Chrome应用商店里发现了一个应用叫&lt;a href=&quot;https://chrome.google.com/webstore/search/Daum%20Equation%20Editor&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/chrome.google.com');&quot;&gt;Daum Equation Editor&lt;/a&gt;，非常非常好用，界面漂亮，选项众多，支持字体特效和大小的调整，输出图片或者latex文字。基本上秒杀我那篇文章里推荐的那些软件。所以在这里再推荐一下:)&lt;br /&gt;
&lt;h3&gt;Random Posts&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207164/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/15/math-equation-in-chrome/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">杂项</category><pubDate>Thu, 15 Dec 2011 13:53:51 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1641</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/12/15/math-equation-in-chrome/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207164/1226385</fs:itemid></item><item><title>Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像</title><link atom:type="text/html">http://www.kunli.info/2011/12/06/android-graphics/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1633</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/12/06/android-graphics/">&lt;p&gt;Google+上有意思的讨论从未间断，几乎已是Google+的标志性特色了。最近两天，移动领域的爱好者都被Dianne Hackborn的&lt;a href=&quot;https://plus.google.com/u/0/105051985738280261832/posts/2FXDCz8x93s&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/plus.google.com');&quot; target=&quot;_blank&quot;&gt;一则吐槽&lt;/a&gt;所吸引。吐槽要火，两大因素不可缺少，一是该话题乃众人关注，却无统一意见。二是吐槽中有大料或者干货爆出，引人入胜。此番吐槽吸引人的地方，正是因为此吐槽是关于饱受争议的Android graphics性能的，自从Android推出的第一天起，graphics的渲染，动画切换等就为人诟病，到后来几乎成了果粉安粉大战的必备话题。而吐槽之人呢？是Android团队中比较senior的架构工程师Dianne Hackborn，相信关注Android开发的朋友，都不会对此女陌生。&lt;/p&gt;
&lt;p&gt;为什么Dianne Hackborn身为Android内部人士，会突然公开讨论如此敏感的一个话题呢？用她自己的话说，就是“受够了外界谣传的关于Android图形渲染的不实信息”。我把她吐槽的大概重点归纳如下：&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1633&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;1. 外界盛传，Android图形渲染一直不支持硬件加速，直到3.0才开启此特性。我也一直深信此观点。其实，从最初起，Android就一直支持硬件加速图形窗口，比如你看到的所有比如菜单的出没，activity之间的切换，对话框的弹出等。&lt;/p&gt;
&lt;p&gt;2. 但Android却是用软件来渲染窗口里面的内容的。如果屏幕上有多个窗口呈现，其中一个窗口的内容需要重新绘制，那么其他窗口不会变化，而改变化的窗口的重新构成还是通过硬件加速，只不过其中变化的内容，却是软件绘制了(不好意思插一句。Redraw!!!!!Android开发者现在应该知道这多么坑爹了吧）。虽然说是软件绘制，却不一定就表示会卡。卡不卡，是由绘制频率和刷新率是否匹配所决定的，比如手机频的刷新率是60fps，但你的渲染率是50fps，双方不同步，自然就会有停顿的感觉产生。如果用软件做这个任务，做得好不好，这个取决于显示屏上的像素数量以及你CPU的能力。比如同样的渲染，Nexus S即使在800&amp;#215;480也不会有问题，而最老的Moto Droid如果也是这样的屏幕，就会力不从心。&lt;/p&gt;
&lt;p&gt;3. “完全”的硬件加速，已经在Android 3.0中就支持了，也就是说，即使是窗口内容的渲染也是硬件做的。Android 4.0并没有比3.0有更多的加速能力。4.0的改进，仅仅是默认所有app都使用硬件加速了，而不是像3.0那样开发者还需要指定android:handwareAccelerated=&amp;#8221;true&amp;#8221;这个选项。然而，完全启用硬件加速的代价是，程序内存占用会严重增多，反而会导致别的方面，比如程序切换，变慢。正因为这样，在将ICS移植到Nexus S时，Google强制关闭了硬件加速选项，保证整个系统的流畅运行。&lt;/p&gt;
&lt;p&gt;4. 人们经常比较的网页浏览的性能，iOS总是比Android好很多，但这个和硬件加速渲染是无关的。在Android中，网页是被当作list而不断在屏幕上渲染的，而iOS用的则是tile贴图。list的好处是你不会在放大缩小或者上下滑动时看到还没来得及绘制的tile，但这却大大增加了渲染frame rate的难度。所幸的是，从3.0开始，Android也使用了tile的渲染，所以之后的设备不会再有这种性能缺陷（在我的GN上是明显感觉出来了进步）。&lt;/p&gt;
&lt;p&gt;她的吐槽还有很多内容，但大意就是这些。有兴趣的朋友可以直接点击那个链接过去看。总的来说，问题就是Android是一直都有硬件加速的，可惜这个加速仅仅是用于服务那些微不足道或者不重要的东西的&amp;#8212;窗口的切换这些。真正和application相关的内容渲染却都是软件在做。这就是为什么iPhone永远感觉都比Android快的原因。iPhone一切的UIView都是Core Animation支持的，而Core Animation又是GPU支持的。更关键的是，iPhone的Core Animation是在不同的线程上run的，和用户正在做的操作是隔离的，所以动画效果会严格按照schedule的去产生，完全没有迟钝感。&lt;/p&gt;
&lt;p&gt;Dianne Hackborn的这个吐槽引起了很大的影响，其中一位前Google的实习生，即将去Windows Phone开发组的Andrew Munn，也因此发表了其&lt;a href=&quot;https://plus.google.com/u/0/100838276097451809262/posts/VDkV9XaJRGS&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/plus.google.com');&quot; target=&quot;_blank&quot;&gt;对此的看法&lt;/a&gt;。Munn强调，这些技术细节都不重要，用户关注的就是你卡不卡。作为一个长期服侍果粉LD的人，我对此深表同意。Munn也针对这个性能问题提出了不少技术看法，可惜其中有不少低级错误。我总结一些我觉得是对的吧：&lt;/p&gt;
&lt;p&gt;1. 所有app硬件加速，如Dianna所说，不是万能良药。但是，至少如ICS所表现，确实解决了很多问题。Munn的Nexus S在运行ICS后流畅度大为增加，而从我使用Galaxy Nexus的情况看，完全不是和以前的Android一个等级的。特别是桌面环境（很多widget的情况下）和Android market。Munn还指出，硬件加速能帮助电池的使用长度。&lt;/p&gt;
&lt;p&gt;2. 垃圾回收机制虽然已经并行化了，但还是需要改进。最明显的就是Android上的gallery app。如果你在使用gallery时，会发现frame rate很低的情况，这是因为Android将其限制到了30fps。为什么？因为如果你浏览60fps的照片，偶尔会出现垃圾回收引起的停顿，严重影响使用体验。&lt;/p&gt;
&lt;p&gt;3. Java, Dalvik。这个问题相信所有开发者都有体会。作为Java痛恨者之一，我很早就做过论断，只要Android坚持java一天，系统效率就会落后iOS一天。如果你尝试过Android NDK的开发，你会发现，区别是多么惊人。&lt;/p&gt;
&lt;p&gt;4. Android的UI问题是一个历史遗留问题。在目前市场上所有的移动系统里，Android是唯一一个早于iPhone推出之前就开始开发的，而且当时针对的是黑莓，非触摸屏机。所以，UI框架也有着不可原谅的遗留问题：UI的渲染是在主线程进行的，animation是由UI管的。而且UI没有任何优先级。之后，全新的WebOS, Win 7等都针对触摸操作而学习iOS的UI处理，只有Android没有，也无法推到重来。&lt;/p&gt;
&lt;p&gt;如果你好奇为什么Google很难推到现在UI的框架重来，原因不外乎就是这几个：所有的app都需要重写。老旧而没升级的app无法兼容。在UI新框架ready之前，所有Android的特性都无法继续进行改进。&lt;/p&gt;
&lt;p&gt;是的，Android有很多很强大的特性，比如widget，比如动态桌面，比如完全多进程。这些特性带给我们强大的体验，同时也增加了UI的负担，反过来成了Android一道长久的伤疤，而这个伤疤，即使是硬件再强大，也很难磨灭。作为一个长期使用iPhone的Android爱好者，UI是我之前一直无法忍受Android日常使用的第一原因。当然，正如我前一篇&lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  target=&quot;_blank&quot;&gt;介绍Android4.0的文章&lt;/a&gt;提到，ICS是在这个方面的一个巨大进步。它能和iOS比肩了么？还不能。但它让Android从在万米长跑中落后100米，变为了落后20米。Munn和我对Google都有同样的印象，那就是：速度，在Google里永远是第一目标。Google有很多人，他们都对&amp;#8221;lag&amp;#8221;这个东西极度痛恨，对“速度”的追求永无停止。看看search，看看Gmail，看看Chrome，你就明白了。我不知道Android team能否最后找到不需要重写就能解决UI问题的方法，但以我对Android team的工作精神，能力以及管理（这个话题要展开可以另写一篇文章，但总的来说我觉得Android是Google内部管理最好的团队之一）的了解，我相信Android迟早会达到这个目标的。也许就在今年6月。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-12-04 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  title=&quot;谈谈Android 4.0&quot;&gt;谈谈Android 4.0 (11)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot;  title=&quot;一个新的开源项目Libsvm-androidjni&quot;&gt;一个新的开源项目Libsvm-androidjni (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-08-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot;  title=&quot;Android Native 代码NDK开发学习笔记&quot;&gt;Android Native 代码NDK开发学习笔记 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>9</thr:total><description>Google+上有意思的讨论从未间断，几乎已是Google+的标志性特色了。最近两天，移动领域的爱好者都被Dianne Hackborn的一则吐槽所吸引。吐槽要火，两大因素不可缺少，一是该话题乃众人关注，却无统一意见。二是吐槽中有大料或者干货爆出，引人入胜。此番吐槽吸引人的地方，正是因为此吐槽是关于饱受争议的Android graphics性能的，自从Android推出的第一天起，graphics的渲染，动画切换等就为人诟病，到后来几乎成了果粉安粉大战的必备话题。而吐槽之人呢？是Android团队中比较senior的架构工程师Dianne Hackborn，相信关注Android开发的朋友，都不会对此女陌生。 为什么Dianne Hackborn身为Android内部人士，会突然公开讨论如此敏感的一个话题呢？用她自己的话说，就是“受够了外界谣传的关于Android图形渲染的不实信息”。我把她吐槽的大概重点归纳如下： 1. 外界盛传，Android图形渲染一直不支持硬件加速，直到3.0才开启此特性。我也一直深信此观点。其实，从最初起，Android就一直支持硬件加速图形窗口，比如你看到的所有比如菜单的出没，activity之间的切换，对话框的弹出等。 2. 但Android却是用软件来渲染窗口里面的内容的。如果屏幕上有多个窗口呈现，其中一个窗口的内容需要重新绘制，那么其他窗口不会变化，而改变化的窗口的重新构成还是通过硬件加速，只不过其中变化的内容，却是软件绘制了(不好意思插一句。Redraw!!!!!Android开发者现在应该知道这多么坑爹了吧）。虽然说是软件绘制，却不一定就表示会卡。卡不卡，是由绘制频率和刷新率是否匹配所决定的，比如手机频的刷新率是60fps，但你的渲染率是50fps，双方不同步，自然就会有停顿的感觉产生。如果用软件做这个任务，做得好不好，这个取决于显示屏上的像素数量以及你CPU的能力。比如同样的渲染，Nexus S即使在800&amp;#215;480也不会有问题，而最老的Moto Droid如果也是这样的屏幕，就会力不从心。 3. “完全”的硬件加速，已经在Android 3.0中就支持了，也就是说，即使是窗口内容的渲染也是硬件做的。Android 4.0并没有比3.0有更多的加速能力。4.0的改进，仅仅是默认所有app都使用硬件加速了，而不是像3.0那样开发者还需要指定android:handwareAccelerated=&amp;#8221;true&amp;#8221;这个选项。然而，完全启用硬件加速的代价是，程序内存占用会严重增多，反而会导致别的方面，比如程序切换，变慢。正因为这样，在将ICS移植到Nexus S时，Google强制关闭了硬件加速选项，保证整个系统的流畅运行。 4. 人们经常比较的网页浏览的性能，iOS总是比Android好很多，但这个和硬件加速渲染是无关的。在Android中，网页是被当作list而不断在屏幕上渲染的，而iOS用的则是tile贴图。list的好处是你不会在放大缩小或者上下滑动时看到还没来得及绘制的tile，但这却大大增加了渲染frame rate的难度。所幸的是，从3.0开始，Android也使用了tile的渲染，所以之后的设备不会再有这种性能缺陷（在我的GN上是明显感觉出来了进步）。 她的吐槽还有很多内容，但大意就是这些。有兴趣的朋友可以直接点击那个链接过去看。总的来说，问题就是Android是一直都有硬件加速的，可惜这个加速仅仅是用于服务那些微不足道或者不重要的东西的&amp;#8212;窗口的切换这些。真正和application相关的内容渲染却都是软件在做。这就是为什么iPhone永远感觉都比Android快的原因。iPhone一切的UIView都是Core Animation支持的，而Core Animation又是GPU支持的。更关键的是，iPhone的Core Animation是在不同的线程上run的，和用户正在做的操作是隔离的，所以动画效果会严格按照schedule的去产生，完全没有迟钝感。 Dianne Hackborn的这个吐槽引起了很大的影响，其中一位前Google的实习生，即将去Windows Phone开发组的Andrew Munn，也因此发表了其对此的看法。Munn强调，这些技术细节都不重要，用户关注的就是你卡不卡。作为一个长期服侍果粉LD的人，我对此深表同意。Munn也针对这个性能问题提出了不少技术看法，可惜其中有不少低级错误。我总结一些我觉得是对的吧： 1. 所有app硬件加速，如Dianna所说，不是万能良药。但是，至少如ICS所表现，确实解决了很多问题。Munn的Nexus S在运行ICS后流畅度大为增加，而从我使用Galaxy Nexus的情况看，完全不是和以前的Android一个等级的。特别是桌面环境（很多widget的情况下）和Android market。Munn还指出，硬件加速能帮助电池的使用长度。 2. 垃圾回收机制虽然已经并行化了，但还是需要改进。最明显的就是Android上的gallery app。如果你在使用gallery时，会发现frame rate很低的情况，这是因为Android将其限制到了30fps。为什么？因为如果你浏览60fps的照片，偶尔会出现垃圾回收引起的停顿，严重影响使用体验。 3. Java, Dalvik。这个问题相信所有开发者都有体会。作为Java痛恨者之一，我很早就做过论断，只要Android坚持java一天，系统效率就会落后iOS一天。如果你尝试过Android NDK的开发，你会发现，区别是多么惊人。 4. Android的UI问题是一个历史遗留问题。在目前市场上所有的移动系统里，Android是唯一一个早于iPhone推出之前就开始开发的，而且当时针对的是黑莓，非触摸屏机。所以，UI框架也有着不可原谅的遗留问题：UI的渲染是在主线程进行的，animation是由UI管的。而且UI没有任何优先级。之后，全新的WebOS, Win 7等都针对触摸操作而学习iOS的UI处理，只有Android没有，也无法推到重来。 如果你好奇为什么Google很难推到现在UI的框架重来，原因不外乎就是这几个：所有的app都需要重写。老旧而没升级的app无法兼容。在UI新框架ready之前，所有Android的特性都无法继续进行改进。 是的，Android有很多很强大的特性，比如widget，比如动态桌面，比如完全多进程。这些特性带给我们强大的体验，同时也增加了UI的负担，反过来成了Android一道长久的伤疤，而这个伤疤，即使是硬件再强大，也很难磨灭。作为一个长期使用iPhone的Android爱好者，UI是我之前一直无法忍受Android日常使用的第一原因。当然，正如我前一篇介绍Android4.0的文章提到，ICS是在这个方面的一个巨大进步。它能和iOS比肩了么？还不能。但它让Android从在万米长跑中落后100米，变为了落后20米。Munn和我对Google都有同样的印象，那就是：速度，在Google里永远是第一目标。Google有很多人，他们都对&amp;#8221;lag&amp;#8221;这个东西极度痛恨，对“速度”的追求永无停止。看看search，看看Gmail，看看Chrome，你就明白了。我不知道Android team能否最后找到不需要重写就能解决UI问题的方法，但以我对Android team的工作精神，能力以及管理（这个话题要展开可以另写一篇文章，但总的来说我觉得Android是Google内部管理最好的团队之一）的了解，我相信Android迟早会达到这个目标的。也许就在今年6月。 也许你还会对这些文章感兴趣 2011-12-04 &amp;#8212; 谈谈Android 4.0 (11) [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207165/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/06/android-graphics/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;Google+上有意思的讨论从未间断，几乎已是Google+的标志性特色了。最近两天，移动领域的爱好者都被Dianne Hackborn的&lt;a href=&quot;https://plus.google.com/u/0/105051985738280261832/posts/2FXDCz8x93s&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/plus.google.com');&quot; target=&quot;_blank&quot;&gt;一则吐槽&lt;/a&gt;所吸引。吐槽要火，两大因素不可缺少，一是该话题乃众人关注，却无统一意见。二是吐槽中有大料或者干货爆出，引人入胜。此番吐槽吸引人的地方，正是因为此吐槽是关于饱受争议的Android graphics性能的，自从Android推出的第一天起，graphics的渲染，动画切换等就为人诟病，到后来几乎成了果粉安粉大战的必备话题。而吐槽之人呢？是Android团队中比较senior的架构工程师Dianne Hackborn，相信关注Android开发的朋友，都不会对此女陌生。&lt;/p&gt;
&lt;p&gt;为什么Dianne Hackborn身为Android内部人士，会突然公开讨论如此敏感的一个话题呢？用她自己的话说，就是“受够了外界谣传的关于Android图形渲染的不实信息”。我把她吐槽的大概重点归纳如下：&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1633&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;1. 外界盛传，Android图形渲染一直不支持硬件加速，直到3.0才开启此特性。我也一直深信此观点。其实，从最初起，Android就一直支持硬件加速图形窗口，比如你看到的所有比如菜单的出没，activity之间的切换，对话框的弹出等。&lt;/p&gt;
&lt;p&gt;2. 但Android却是用软件来渲染窗口里面的内容的。如果屏幕上有多个窗口呈现，其中一个窗口的内容需要重新绘制，那么其他窗口不会变化，而改变化的窗口的重新构成还是通过硬件加速，只不过其中变化的内容，却是软件绘制了(不好意思插一句。Redraw!!!!!Android开发者现在应该知道这多么坑爹了吧）。虽然说是软件绘制，却不一定就表示会卡。卡不卡，是由绘制频率和刷新率是否匹配所决定的，比如手机频的刷新率是60fps，但你的渲染率是50fps，双方不同步，自然就会有停顿的感觉产生。如果用软件做这个任务，做得好不好，这个取决于显示屏上的像素数量以及你CPU的能力。比如同样的渲染，Nexus S即使在800&amp;#215;480也不会有问题，而最老的Moto Droid如果也是这样的屏幕，就会力不从心。&lt;/p&gt;
&lt;p&gt;3. “完全”的硬件加速，已经在Android 3.0中就支持了，也就是说，即使是窗口内容的渲染也是硬件做的。Android 4.0并没有比3.0有更多的加速能力。4.0的改进，仅仅是默认所有app都使用硬件加速了，而不是像3.0那样开发者还需要指定android:handwareAccelerated=&amp;#8221;true&amp;#8221;这个选项。然而，完全启用硬件加速的代价是，程序内存占用会严重增多，反而会导致别的方面，比如程序切换，变慢。正因为这样，在将ICS移植到Nexus S时，Google强制关闭了硬件加速选项，保证整个系统的流畅运行。&lt;/p&gt;
&lt;p&gt;4. 人们经常比较的网页浏览的性能，iOS总是比Android好很多，但这个和硬件加速渲染是无关的。在Android中，网页是被当作list而不断在屏幕上渲染的，而iOS用的则是tile贴图。list的好处是你不会在放大缩小或者上下滑动时看到还没来得及绘制的tile，但这却大大增加了渲染frame rate的难度。所幸的是，从3.0开始，Android也使用了tile的渲染，所以之后的设备不会再有这种性能缺陷（在我的GN上是明显感觉出来了进步）。&lt;/p&gt;
&lt;p&gt;她的吐槽还有很多内容，但大意就是这些。有兴趣的朋友可以直接点击那个链接过去看。总的来说，问题就是Android是一直都有硬件加速的，可惜这个加速仅仅是用于服务那些微不足道或者不重要的东西的&amp;#8212;窗口的切换这些。真正和application相关的内容渲染却都是软件在做。这就是为什么iPhone永远感觉都比Android快的原因。iPhone一切的UIView都是Core Animation支持的，而Core Animation又是GPU支持的。更关键的是，iPhone的Core Animation是在不同的线程上run的，和用户正在做的操作是隔离的，所以动画效果会严格按照schedule的去产生，完全没有迟钝感。&lt;/p&gt;
&lt;p&gt;Dianne Hackborn的这个吐槽引起了很大的影响，其中一位前Google的实习生，即将去Windows Phone开发组的Andrew Munn，也因此发表了其&lt;a href=&quot;https://plus.google.com/u/0/100838276097451809262/posts/VDkV9XaJRGS&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/plus.google.com');&quot; target=&quot;_blank&quot;&gt;对此的看法&lt;/a&gt;。Munn强调，这些技术细节都不重要，用户关注的就是你卡不卡。作为一个长期服侍果粉LD的人，我对此深表同意。Munn也针对这个性能问题提出了不少技术看法，可惜其中有不少低级错误。我总结一些我觉得是对的吧：&lt;/p&gt;
&lt;p&gt;1. 所有app硬件加速，如Dianna所说，不是万能良药。但是，至少如ICS所表现，确实解决了很多问题。Munn的Nexus S在运行ICS后流畅度大为增加，而从我使用Galaxy Nexus的情况看，完全不是和以前的Android一个等级的。特别是桌面环境（很多widget的情况下）和Android market。Munn还指出，硬件加速能帮助电池的使用长度。&lt;/p&gt;
&lt;p&gt;2. 垃圾回收机制虽然已经并行化了，但还是需要改进。最明显的就是Android上的gallery app。如果你在使用gallery时，会发现frame rate很低的情况，这是因为Android将其限制到了30fps。为什么？因为如果你浏览60fps的照片，偶尔会出现垃圾回收引起的停顿，严重影响使用体验。&lt;/p&gt;
&lt;p&gt;3. Java, Dalvik。这个问题相信所有开发者都有体会。作为Java痛恨者之一，我很早就做过论断，只要Android坚持java一天，系统效率就会落后iOS一天。如果你尝试过Android NDK的开发，你会发现，区别是多么惊人。&lt;/p&gt;
&lt;p&gt;4. Android的UI问题是一个历史遗留问题。在目前市场上所有的移动系统里，Android是唯一一个早于iPhone推出之前就开始开发的，而且当时针对的是黑莓，非触摸屏机。所以，UI框架也有着不可原谅的遗留问题：UI的渲染是在主线程进行的，animation是由UI管的。而且UI没有任何优先级。之后，全新的WebOS, Win 7等都针对触摸操作而学习iOS的UI处理，只有Android没有，也无法推到重来。&lt;/p&gt;
&lt;p&gt;如果你好奇为什么Google很难推到现在UI的框架重来，原因不外乎就是这几个：所有的app都需要重写。老旧而没升级的app无法兼容。在UI新框架ready之前，所有Android的特性都无法继续进行改进。&lt;/p&gt;
&lt;p&gt;是的，Android有很多很强大的特性，比如widget，比如动态桌面，比如完全多进程。这些特性带给我们强大的体验，同时也增加了UI的负担，反过来成了Android一道长久的伤疤，而这个伤疤，即使是硬件再强大，也很难磨灭。作为一个长期使用iPhone的Android爱好者，UI是我之前一直无法忍受Android日常使用的第一原因。当然，正如我前一篇&lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  target=&quot;_blank&quot;&gt;介绍Android4.0的文章&lt;/a&gt;提到，ICS是在这个方面的一个巨大进步。它能和iOS比肩了么？还不能。但它让Android从在万米长跑中落后100米，变为了落后20米。Munn和我对Google都有同样的印象，那就是：速度，在Google里永远是第一目标。Google有很多人，他们都对&amp;#8221;lag&amp;#8221;这个东西极度痛恨，对“速度”的追求永无停止。看看search，看看Gmail，看看Chrome，你就明白了。我不知道Android team能否最后找到不需要重写就能解决UI问题的方法，但以我对Android team的工作精神，能力以及管理（这个话题要展开可以另写一篇文章，但总的来说我觉得Android是Google内部管理最好的团队之一）的了解，我相信Android迟早会达到这个目标的。也许就在今年6月。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-12-04 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot;  title=&quot;谈谈Android 4.0&quot;&gt;谈谈Android 4.0 (11)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot;  title=&quot;一个新的开源项目Libsvm-androidjni&quot;&gt;一个新的开源项目Libsvm-androidjni (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-08-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot;  title=&quot;Android Native 代码NDK开发学习笔记&quot;&gt;Android Native 代码NDK开发学习笔记 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207165/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/06/android-graphics/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">android</category><category domain="http://www.kunli.info">mobile</category><category domain="http://www.kunli.info">graphics</category><category domain="http://www.kunli.info">ICS</category><pubDate>Tue, 06 Dec 2011 16:26:33 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1633</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/12/06/android-graphics/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207165/1226385</fs:itemid></item><item><title>谈谈Android 4.0</title><link atom:type="text/html">http://www.kunli.info/2011/12/04/ice-cream-sandwich/</link><author xmlns="http://www.w3.org/2005/Atom"><name>windstorm</name><uri>http://www.kunli.info</uri></author><id xmlns="http://www.w3.org/2005/Atom">http://www.kunli.info/?p=1621</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.kunli.info/2011/12/04/ice-cream-sandwich/">&lt;p&gt;昨天刚拿到Galaxy Nexus，把玩了差不多一天了。这篇文章并不想花大篇幅介绍这款机器的硬件和软件，如果你好奇，可以看一下下面这些知名网站的评测，再详细不过了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.engadget.com/2011/11/24/galaxy-nexus-hspa-review/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.engadget.com');&quot;&gt;Engadget&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.theverge.com/2011/11/17/2568348/galaxy-nexus-review&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.theverge.com');&quot;&gt;The Verge&lt;/a&gt;: 8.6/10（和iPhone4s同分）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.slashgear.com/galaxy-nexus-review-21196912/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.slashgear.com');&quot;&gt;SlashGear&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bgr.com/2011/11/22/samsung-galaxy-nexus-review/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.bgr.com');&quot;&gt;Boy Genius Report&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.techradar.com/reviews/phones/mobile-phones/samsung-galaxy-nexus-1039209/review&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.techradar.com');&quot;&gt;TechRadar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.phonearena.com/reviews/Samsung-Galaxy-Nexus-Review_id2915&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.phonearena.com');&quot;&gt;PhoneArena&lt;/a&gt;: 9.5/10&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gigaom.com/apple/review-the-galaxy-nexus-from-an-iphone-owners-perspective/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/gigaom.com');&quot;&gt;GigaOM&lt;/a&gt;:一个iPhone用户的评测&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gizmodo.com/5864584/galaxy-nexus-review-two-steps-forward-one-step-back?autoplay&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/gizmodo.com');&quot;&gt;Gizmodo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gigaom.com/mobile/galaxy-nexus-first-look-video-and-impressions/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/gigaom.com');&quot;&gt;GigaOM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果真要总结，那只有一句话，这是Android有史以来第一款能和苹果手机并肩的机器。这篇文章里，我就谈谈，在我眼里，Android的后续发展，和ICS的意义，当然都是结合了我在Google４个月的所见所闻以及感想。很多朋友希望看到我有一篇专门的实习总结，我想了想还是算了，首先我实习做的东西比较保密，没法说，其次也没什么写的，Google工作环境好，条件好，牛人多，大家都知道，没必要再吹一次。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1621&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;很多人都觉得我是Google粉，因为我一直在鼓吹Android，而且还机缘巧合算是在Android团队里做过实习。但我想辩解的是，我是Google服务爱好者，但我确实不是fanboy。那为什么我要“鼓吹”Android？因为它geek，和我一样。它开源，给你随便折腾，随便改。难道你就未曾想尝试过在自己的手机上跑自己编译甚至修改的操作系统？Hell，那你根本就算不上一个geek。实际生活中，如果要说我是什么fans，我是“好东西”fans。我用Google的服务，Gmail, Gmap, Chrome，是因为它们确实好用。我也用iMac和MBA，是因为它们确实好用。朋友找我推荐手机，我都是仔细询问需求，然后大部分情况下都是推荐了iPhone。迄今为止，我用了一年半的iPhone4。如果你到我家来一趟，你肯定会给我贴上&amp;#8221;Apple fanboy&amp;#8221;的标签。因为我家苹果的东西太多了。&lt;/p&gt;
&lt;p&gt;我只是喜欢用最好的东西而已。&lt;/p&gt;
&lt;p&gt;那也许有人问，你既然用苹果，为啥还分析Android？有没有credit？我觉得我有。你要问我用过多少Android做开发，我估算一下不下十种。从最早的G1 Dream，到最新的Galaxy S2。每一款机器，我都会插进我的sim卡用一段时间，亲身感受。即使有时不是随身携带，因开发关系，也会深入了解系统。&lt;/p&gt;
&lt;p&gt;我曾经写过两篇关于Android发展的文章。在&amp;#8221;&lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  target=&quot;_blank&quot;&gt;Android并不伟大，但丝毫不令人沮丧&lt;/a&gt;&amp;#8220;一文中，我提到五点：&lt;/p&gt;
&lt;p&gt;1. Android会越来越多地和云服务结合，并逐步融合Chrome OS的思想。&lt;br /&gt;
2. Android必须免费。一旦有强大定制化的开源系统，高度统一的收费系统就没法统治整个消费电子领域。&lt;br /&gt;
3. Android绝对不能被单方控制。&lt;br /&gt;
4. SNS和移动网络融合是一个趋势，也是目前没有明显强势选手的领域，Android能不能把握这个趋势，加入一些创新的元素，决定了Android是不是能继续保持和iPhone争锋的势头。&lt;br /&gt;
5. Google不能完全进入手机硬件市场。为什么说Android令人沮丧一文提出的Google收购Moto的建议，不客气地说，从目前Android发展阶段看，实在是馊主意。&lt;/p&gt;
&lt;p&gt;1这一点Android是越做越好，以Google Music为代表。2,3也是没问题的，4则是以Google+为代表。有意思的是5。应该说，我至少错了一半。是的，Google收购Moto了，而且就是为了Android。但是为什么我说我可能只错了一半呢？我在那篇文章里面还提到：&lt;/p&gt;
&lt;p&gt;“Android的定位已经悄然起了变化，这个变化，以家居电子厂商和汽车电子厂商纷纷表示对Android的兴趣或者直接推出对应产品为起点，以Google TV的推出为标志，彻底公开在了人们面前：Android已经从一个移动设备操作系统，变成了一个消费电子设备操作系统。”&lt;/p&gt;
&lt;p&gt;很明显，这也是苹果下一个扩展领域。对于Android来讲，Android@Home和Google TV的更新是一个明显的信号。当然，对于消费电子，特别是家庭电子，该领域太大太广，厂商众多，Google想分一杯羹谈何容易。如果所有的领域都需要别的硬件厂商的鼎力支持，有些领域可能完全就没机会打进去。何况有时候，别的硬件厂商完全就不靠谱，比如Sony做的Google TV。你会用么？反正我不会。所以，从这个层面上讲，Google收购的不是Moto的手机能力，而是硬件能力。有了Moto，Google可以做各种各样的硬件创新，并以此打入完全陌生的领域。&lt;/p&gt;
&lt;p&gt;那么这个收购在手机领域有什么影响呢？我不知道。而且当时大部分Googler也不知道，这也是Google内部问得最多的问题。我感觉肯定有影响，只是该影响可能在2-3年后太能体现。短时间内，Google肯定还是会一碗水端平，甚至会稍微照顾别的厂商一些。&lt;/p&gt;
&lt;p&gt;我在那篇文章里面有没有完全错误的论断呢？有。我说“Android只是Google的一个棋子。Android对于Google来说，是冗长战线上的一个坦克而已”。这个论断是完全错误的。Android对于Google来说，不是一个冗长战线上的坦克，而是一个王牌军。Google很清楚移动领域的未来，也很清楚它应该有多少资源投进Android。任何担心Android的地位会受哪怕一点点Chrome OS威胁的人，都是杞人忧天。Android会借鉴别的东西，但Android一直会是Android，Google在移动时代的王牌之一。&lt;/p&gt;
&lt;p&gt;在写完此文不久，我就写了另一篇文章，&amp;#8221;&lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  target=&quot;_blank&quot;&gt;Gingerbread，向左走还是向右走？&lt;/a&gt;&amp;#8220;。我在其中提到了一个观点：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;今天网上广为流传的消息，是来自TechCrunch的，Android团队正在努力解决用户体验的问题。伴随而来的，是Google正在考虑停止厂商自定义UI的权利，包括Sense UI、Moto Blur、Ninja Blur等等。一旦消息属实，我们假设Android真的限制了UI的定制权利，其他厂商如果生产Android手机，必须使用原生UI，那么造成的结果是什么样的？我会说，Android很可能会大败给苹果，而且连智能手机市场老二位置都占不了。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;直到今天，我认为这在当时发展情况下，也是无比正确的论断(汗)。为什么？当时的Android太丑了。我想象不出任何一个非Geek，在看到原生Android UI和iOS的UI后，会不选择后者。接下来，我分析了对于Google的可行策略：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;因为还有另外一种可能性，就是Google只限定底层的Framework不能更改，第三方手机制造商还是可以在系统里加入自己的预置功能，把系统改为自己希望改为的UI。我不希望看到自定制界面的灭亡，我只希望看到自定制界面的系统也能和原生系统一样，一起升级。&lt;/p&gt;
&lt;p&gt;除非，除非Gingerbread的UI有着超级大变身一般的升级，一下子让其他所有第三方UI完全失色，甚至超过苹果。这个幅度基本等于从赛亚人直接变身为超级赛亚人之三的幅度，换句话说，基本不可能。否则，否则Google必须想出某种办法，在改进UI体验的同时，尽可能少地牺牲Android开源的特性，让别的厂商没有退出不做的打算。是的，Moto在搞自己的系统，Samsung在搞自己的系统，HTC很可能搞自己的系统，但是没关系，Google只需要保证Android比他们都好一截，那么他们仍然会帮Android占领市场份额——反正是免费的。还是那个观点，Google不需要争第一，Google只需要让自己一直不断渗透这个市场，让市场没有明显的一家独大，就可以了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;至于Google如何保证Android比这些硬件厂商的OS都好一截，这个的可能性还是很大的&lt;/strong&gt;。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;同样，到现在，我认为当时的这个推测非常正确。Google的后续系统正是按照这个轨迹发展的。唯一的偏差是两点&lt;/p&gt;
&lt;p&gt;1. Gingerbread没有达到我的期望，虽然有改进，还是很丑，还是不流畅。Honeycomb终有巨大改进，可惜非通用系统。&lt;/p&gt;
&lt;p&gt;2. ICS完全做到了这个预测，甚至基本已经达到变身超级塞亚人2.5的地步了。&lt;/p&gt;
&lt;p&gt;到现在，话题终于和本篇文章的标题关联了。是的，这就是我对ICS的评价：基本可以和iOS并驾齐驱了。无论什么方面，设计，速度，操作感，灵魂。人们总是说，Android就是喜欢搞军备竞赛，不管什么硬件，系统还是那么丑那么烂那么卡那么多Bug。ICS推出之日，即是该说法消亡之时。&lt;/p&gt;
&lt;p&gt;读到这里，有些朋友可能要说了，太明显的android fanboy的言论。其实如果你看过我一年前的&lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  target=&quot;_blank&quot;&gt;Galaxy S评测&lt;/a&gt;，或者更早关于hero的文章，就知道，我的blog评测都是尽量客观的。那我就简单归纳一下，是什么让我有此感受的。&lt;/p&gt;
&lt;p&gt;1.　快，流畅。ICS终于支持GPU加速了。我不知道是什么导致Android到今天才完全拥抱此特性(3.0算半个支持），但幸运的是，终于支持了。如果你曾经在Android和iPhone上都用过twitter的话，你一定能留意出两者scroll时流畅的区别。这个区别一去不复返了。用ICS，任何时候你都能感觉到流畅，流畅，流畅。动画切换也好，scroll也好，不管在哪里。靠，连语音输入识别都那么流畅。我相信它不会比iPhone 4s“更流畅”，但至少是“一样流畅”。&lt;/p&gt;
&lt;p&gt;2.   漂亮。天阿，这是两年来第一款让我称赞操作系统漂亮的Android手机。我不知道GN上这个无以伦比的屏幕会不会加点分，我只知道，现在的系统，一切看着都是舒服的，而不是让人皱眉。精致的图标，优雅的切换。我在各种不同的界面中都用它和LD的iPhone 4比较，可以说各有千秋，再无巨大区别。不用多说，我就简单上两个图比较。这是国内bbs.gfan.com论坛一位网友照的Galaxy S2和Galaxy Nexus设置界面的区别：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/12/1111262348034091164ce16ede.jpg&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1622&quot; title=&quot;1111262348034091164ce16ede&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/12/1111262348034091164ce16ede.jpg&quot; alt=&quot;&quot; width=&quot;800&quot; height=&quot;531&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是著名AndroidPolice网站评测图中的一张&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Screen-Shot-2011-12-03-at-11.57.37-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1623&quot; title=&quot;Screen Shot 2011-12-03 at 11.57.37 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Screen-Shot-2011-12-03-at-11.57.37-AM-1024x869.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;869&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你现在可以想象到为什么很多以Android为日常用机的朋友都会谴责界面了。&lt;/p&gt;
&lt;p&gt;顺带说一句，如果你是已有Android用户，希望知道更多ICS 界面的翻天覆地变化，可以看看Android Police推出的&lt;a href=&quot;https://www.google.com/search?ix=hca&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=getting-to-know-android-4-0&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.google.com');&quot; target=&quot;_blank&quot;&gt;getting-to-know-android-4-0&lt;/a&gt;系列。不会让你失望的。&lt;/p&gt;
&lt;p&gt;3.　直观。一个操作系统，流畅和漂亮是外在，直观的操作是核心。应该说，论直观性，ICS目前还是不如iOS。但和之前的Android版本比，确已经有了一个巨大的进步。用手势来remove进程，网页，通知，用手势来翻页。大幅度减少menu的使用，widget大小的自定制，等等等等。当你真正用的时候，你会发现，很多时候你想的是“早就应该这样了”&lt;/p&gt;
&lt;p&gt;4.   所有自带的Google服务软件完全超越其他所有平台。是的，我是说所有。Gmail, Gmap, Gvoice, Calendar, Google+, GMusic, you name it. 如果你是重度Google用户，你一旦用上，就不会再想离开这个天堂。Gmail和Gmap这些app，用起来纯粹是一种享受。更强的功能，更清新的界面，更直观的选项，更快捷的手势。&lt;/p&gt;
&lt;p&gt;5.   当Google说，他们会帮你同步手机上的everything时，它们真的是这么做的。如果你是之前Android手机用户的话，在同步完GN之后，不仅仅是你之前手机所有的apps，widgets，联系人信息都有，还同步了所有的墙纸，相片簿，以及网页里的bookmark和历史。是的，一切同步。你打开手机即可使用。&lt;/p&gt;
&lt;p&gt;6.　其他本来优势功能的继续增强。比如notification，widget，语音输入这些本来和iOS比就有优势的东西，现在的优势更大。之前一般的输入法也变得非常准确。还有有趣的头像解锁。更有意思的是，Cook刚在iPhone 4s发布会上讽刺了Android手机照相时间，ICS立刻推出了秒杀所有平台的即拍即得特性。连全景照相也是官方内置了。论算法的强大，Google还是不遑多让。&lt;/p&gt;
&lt;p&gt;如果你要问，难道这个系统就没有什么缺点么？有。某些小地方还是不够consistent，还有，还有，还有&amp;#8230;&amp;#8230;.hell, 对于喜欢Android的人来说，真没了&amp;#8230;&amp;#8230;是，GN有一些缺点，比如相机质量一般，屏幕费电。但对于ICS&amp;#8230;&amp;#8230;对不起，我真的找不出什么明显的缺陷了。&lt;/p&gt;
&lt;p&gt;那和iOS5比呢？&lt;/p&gt;
&lt;p&gt;那就得加上一个大缺陷：专门为ICS优化的app还是太少。不过这点在接下来的几个月中会大有改观。ICS不是Gingerbread，不是Honeycomb，它是unified system，也就是说，手机可用，平板可用，笔记本可用，冰箱可用，X86可用，ARM可用，连桌面电脑的显示屏&lt;a href=&quot;http://armdevices.net/2011/11/19/ice-cream-sandwich-works-on-st-ericsson-nova-a9500-arm-cortex-a9/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/armdevices.net');&quot; target=&quot;_blank&quot;&gt;都能正常显示&lt;/a&gt;。换句话说，人们只需要开发核心程序一次，然后用不同的界面配置，就可以让app运行在不同硬件上。加上ICS本身的巨大改进，开发者会蜂拥而来，做ICS oriented的app的。&lt;/p&gt;
&lt;p&gt;这是第一款，让我能彻底放弃我的iPhone 4并且没有丝毫回头之意并且还能欣赏其带来的新东西的手机。第一款。Jobs推出iPhone 1的时候说过，苹果领先别的系统至少5年。他又对了，今年是第五年。Android终于赶上了，从ICS开始。&lt;/p&gt;
&lt;p&gt;让我们期待Android和iOS从今往后的精彩战争吧。竞争，永远是对用户最好的事情。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Android-4.0-Ice-Cream-Sandwich-home-screen.jpg&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1624&quot; title=&quot;Android-4.0-Ice-Cream-Sandwich-home-screen&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Android-4.0-Ice-Cream-Sandwich-home-screen.jpg&quot; alt=&quot;&quot; width=&quot;410&quot; height=&quot;350&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;*************************************我是分割线*********************************************&lt;/p&gt;
&lt;p&gt;一个题外话。还有朋友曾经问我用过Win7没有。&lt;/p&gt;
&lt;p&gt;我用过。&lt;/p&gt;
&lt;p&gt;感觉如何？&lt;/p&gt;
&lt;p&gt;不错。简洁流畅。不是很喜欢它的UI风格，但这是个人偏好。有希望在市场开辟另一片天。&lt;/p&gt;
&lt;p&gt;为什么不写一些关于它的想法？为什么每次都拿iOS和Android比？&lt;/p&gt;
&lt;p&gt;恩&amp;#8230;&amp;#8230;不好意思，我对微软怨念太深了。所有关于微软产品的文章，让我写出来最后估计3/4篇幅都是关于微软的吐槽。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-12-06 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/06/android-graphics/&quot;  title=&quot;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像&quot;&gt;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot;  title=&quot;一个新的开源项目Libsvm-androidjni&quot;&gt;一个新的开源项目Libsvm-androidjni (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-08-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot;  title=&quot;Android Native 代码NDK开发学习笔记&quot;&gt;Android Native 代码NDK开发学习笔记 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;</content><thr:total>11</thr:total><description>昨天刚拿到Galaxy Nexus，把玩了差不多一天了。这篇文章并不想花大篇幅介绍这款机器的硬件和软件，如果你好奇，可以看一下下面这些知名网站的评测，再详细不过了 Engadget The Verge: 8.6/10（和iPhone4s同分） SlashGear Boy Genius Report TechRadar PhoneArena: 9.5/10 GigaOM:一个iPhone用户的评测 Gizmodo GigaOM 如果真要总结，那只有一句话，这是Android有史以来第一款能和苹果手机并肩的机器。这篇文章里，我就谈谈，在我眼里，Android的后续发展，和ICS的意义，当然都是结合了我在Google４个月的所见所闻以及感想。很多朋友希望看到我有一篇专门的实习总结，我想了想还是算了，首先我实习做的东西比较保密，没法说，其次也没什么写的，Google工作环境好，条件好，牛人多，大家都知道，没必要再吹一次。 很多人都觉得我是Google粉，因为我一直在鼓吹Android，而且还机缘巧合算是在Android团队里做过实习。但我想辩解的是，我是Google服务爱好者，但我确实不是fanboy。那为什么我要“鼓吹”Android？因为它geek，和我一样。它开源，给你随便折腾，随便改。难道你就未曾想尝试过在自己的手机上跑自己编译甚至修改的操作系统？Hell，那你根本就算不上一个geek。实际生活中，如果要说我是什么fans，我是“好东西”fans。我用Google的服务，Gmail, Gmap, Chrome，是因为它们确实好用。我也用iMac和MBA，是因为它们确实好用。朋友找我推荐手机，我都是仔细询问需求，然后大部分情况下都是推荐了iPhone。迄今为止，我用了一年半的iPhone4。如果你到我家来一趟，你肯定会给我贴上&amp;#8221;Apple fanboy&amp;#8221;的标签。因为我家苹果的东西太多了。 我只是喜欢用最好的东西而已。 那也许有人问，你既然用苹果，为啥还分析Android？有没有credit？我觉得我有。你要问我用过多少Android做开发，我估算一下不下十种。从最早的G1 Dream，到最新的Galaxy S2。每一款机器，我都会插进我的sim卡用一段时间，亲身感受。即使有时不是随身携带，因开发关系，也会深入了解系统。 我曾经写过两篇关于Android发展的文章。在&amp;#8221;Android并不伟大，但丝毫不令人沮丧&amp;#8220;一文中，我提到五点： 1. Android会越来越多地和云服务结合，并逐步融合Chrome OS的思想。 2. Android必须免费。一旦有强大定制化的开源系统，高度统一的收费系统就没法统治整个消费电子领域。 3. Android绝对不能被单方控制。 4. SNS和移动网络融合是一个趋势，也是目前没有明显强势选手的领域，Android能不能把握这个趋势，加入一些创新的元素，决定了Android是不是能继续保持和iPhone争锋的势头。 5. Google不能完全进入手机硬件市场。为什么说Android令人沮丧一文提出的Google收购Moto的建议，不客气地说，从目前Android发展阶段看，实在是馊主意。 1这一点Android是越做越好，以Google Music为代表。2,3也是没问题的，4则是以Google+为代表。有意思的是5。应该说，我至少错了一半。是的，Google收购Moto了，而且就是为了Android。但是为什么我说我可能只错了一半呢？我在那篇文章里面还提到： “Android的定位已经悄然起了变化，这个变化，以家居电子厂商和汽车电子厂商纷纷表示对Android的兴趣或者直接推出对应产品为起点，以Google TV的推出为标志，彻底公开在了人们面前：Android已经从一个移动设备操作系统，变成了一个消费电子设备操作系统。” 很明显，这也是苹果下一个扩展领域。对于Android来讲，Android@Home和Google TV的更新是一个明显的信号。当然，对于消费电子，特别是家庭电子，该领域太大太广，厂商众多，Google想分一杯羹谈何容易。如果所有的领域都需要别的硬件厂商的鼎力支持，有些领域可能完全就没机会打进去。何况有时候，别的硬件厂商完全就不靠谱，比如Sony做的Google TV。你会用么？反正我不会。所以，从这个层面上讲，Google收购的不是Moto的手机能力，而是硬件能力。有了Moto，Google可以做各种各样的硬件创新，并以此打入完全陌生的领域。 那么这个收购在手机领域有什么影响呢？我不知道。而且当时大部分Googler也不知道，这也是Google内部问得最多的问题。我感觉肯定有影响，只是该影响可能在2-3年后太能体现。短时间内，Google肯定还是会一碗水端平，甚至会稍微照顾别的厂商一些。 我在那篇文章里面有没有完全错误的论断呢？有。我说“Android只是Google的一个棋子。Android对于Google来说，是冗长战线上的一个坦克而已”。这个论断是完全错误的。Android对于Google来说，不是一个冗长战线上的坦克，而是一个王牌军。Google很清楚移动领域的未来，也很清楚它应该有多少资源投进Android。任何担心Android的地位会受哪怕一点点Chrome OS威胁的人，都是杞人忧天。Android会借鉴别的东西，但Android一直会是Android，Google在移动时代的王牌之一。 在写完此文不久，我就写了另一篇文章，&amp;#8221;Gingerbread，向左走还是向右走？&amp;#8220;。我在其中提到了一个观点： 今天网上广为流传的消息，是来自TechCrunch的，Android团队正在努力解决用户体验的问题。伴随而来的，是Google正在考虑停止厂商自定义UI的权利，包括Sense UI、Moto Blur、Ninja Blur等等。一旦消息属实，我们假设Android真的限制了UI的定制权利，其他厂商如果生产Android手机，必须使用原生UI，那么造成的结果是什么样的？我会说，Android很可能会大败给苹果，而且连智能手机市场老二位置都占不了。 直到今天，我认为这在当时发展情况下，也是无比正确的论断(汗)。为什么？当时的Android太丑了。我想象不出任何一个非Geek，在看到原生Android UI和iOS的UI后，会不选择后者。接下来，我分析了对于Google的可行策略： 因为还有另外一种可能性，就是Google只限定底层的Framework不能更改，第三方手机制造商还是可以在系统里加入自己的预置功能，把系统改为自己希望改为的UI。我不希望看到自定制界面的灭亡，我只希望看到自定制界面的系统也能和原生系统一样，一起升级。 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/631207166/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><content:encoded>&lt;p&gt;昨天刚拿到Galaxy Nexus，把玩了差不多一天了。这篇文章并不想花大篇幅介绍这款机器的硬件和软件，如果你好奇，可以看一下下面这些知名网站的评测，再详细不过了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.engadget.com/2011/11/24/galaxy-nexus-hspa-review/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.engadget.com');&quot;&gt;Engadget&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.theverge.com/2011/11/17/2568348/galaxy-nexus-review&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.theverge.com');&quot;&gt;The Verge&lt;/a&gt;: 8.6/10（和iPhone4s同分）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.slashgear.com/galaxy-nexus-review-21196912/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.slashgear.com');&quot;&gt;SlashGear&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bgr.com/2011/11/22/samsung-galaxy-nexus-review/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.bgr.com');&quot;&gt;Boy Genius Report&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.techradar.com/reviews/phones/mobile-phones/samsung-galaxy-nexus-1039209/review&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.techradar.com');&quot;&gt;TechRadar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.phonearena.com/reviews/Samsung-Galaxy-Nexus-Review_id2915&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.phonearena.com');&quot;&gt;PhoneArena&lt;/a&gt;: 9.5/10&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gigaom.com/apple/review-the-galaxy-nexus-from-an-iphone-owners-perspective/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/gigaom.com');&quot;&gt;GigaOM&lt;/a&gt;:一个iPhone用户的评测&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gizmodo.com/5864584/galaxy-nexus-review-two-steps-forward-one-step-back?autoplay&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/gizmodo.com');&quot;&gt;Gizmodo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gigaom.com/mobile/galaxy-nexus-first-look-video-and-impressions/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/gigaom.com');&quot;&gt;GigaOM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果真要总结，那只有一句话，这是Android有史以来第一款能和苹果手机并肩的机器。这篇文章里，我就谈谈，在我眼里，Android的后续发展，和ICS的意义，当然都是结合了我在Google４个月的所见所闻以及感想。很多朋友希望看到我有一篇专门的实习总结，我想了想还是算了，首先我实习做的东西比较保密，没法说，其次也没什么写的，Google工作环境好，条件好，牛人多，大家都知道，没必要再吹一次。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1621&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;很多人都觉得我是Google粉，因为我一直在鼓吹Android，而且还机缘巧合算是在Android团队里做过实习。但我想辩解的是，我是Google服务爱好者，但我确实不是fanboy。那为什么我要“鼓吹”Android？因为它geek，和我一样。它开源，给你随便折腾，随便改。难道你就未曾想尝试过在自己的手机上跑自己编译甚至修改的操作系统？Hell，那你根本就算不上一个geek。实际生活中，如果要说我是什么fans，我是“好东西”fans。我用Google的服务，Gmail, Gmap, Chrome，是因为它们确实好用。我也用iMac和MBA，是因为它们确实好用。朋友找我推荐手机，我都是仔细询问需求，然后大部分情况下都是推荐了iPhone。迄今为止，我用了一年半的iPhone4。如果你到我家来一趟，你肯定会给我贴上&amp;#8221;Apple fanboy&amp;#8221;的标签。因为我家苹果的东西太多了。&lt;/p&gt;
&lt;p&gt;我只是喜欢用最好的东西而已。&lt;/p&gt;
&lt;p&gt;那也许有人问，你既然用苹果，为啥还分析Android？有没有credit？我觉得我有。你要问我用过多少Android做开发，我估算一下不下十种。从最早的G1 Dream，到最新的Galaxy S2。每一款机器，我都会插进我的sim卡用一段时间，亲身感受。即使有时不是随身携带，因开发关系，也会深入了解系统。&lt;/p&gt;
&lt;p&gt;我曾经写过两篇关于Android发展的文章。在&amp;#8221;&lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  target=&quot;_blank&quot;&gt;Android并不伟大，但丝毫不令人沮丧&lt;/a&gt;&amp;#8220;一文中，我提到五点：&lt;/p&gt;
&lt;p&gt;1. Android会越来越多地和云服务结合，并逐步融合Chrome OS的思想。&lt;br /&gt;
2. Android必须免费。一旦有强大定制化的开源系统，高度统一的收费系统就没法统治整个消费电子领域。&lt;br /&gt;
3. Android绝对不能被单方控制。&lt;br /&gt;
4. SNS和移动网络融合是一个趋势，也是目前没有明显强势选手的领域，Android能不能把握这个趋势，加入一些创新的元素，决定了Android是不是能继续保持和iPhone争锋的势头。&lt;br /&gt;
5. Google不能完全进入手机硬件市场。为什么说Android令人沮丧一文提出的Google收购Moto的建议，不客气地说，从目前Android发展阶段看，实在是馊主意。&lt;/p&gt;
&lt;p&gt;1这一点Android是越做越好，以Google Music为代表。2,3也是没问题的，4则是以Google+为代表。有意思的是5。应该说，我至少错了一半。是的，Google收购Moto了，而且就是为了Android。但是为什么我说我可能只错了一半呢？我在那篇文章里面还提到：&lt;/p&gt;
&lt;p&gt;“Android的定位已经悄然起了变化，这个变化，以家居电子厂商和汽车电子厂商纷纷表示对Android的兴趣或者直接推出对应产品为起点，以Google TV的推出为标志，彻底公开在了人们面前：Android已经从一个移动设备操作系统，变成了一个消费电子设备操作系统。”&lt;/p&gt;
&lt;p&gt;很明显，这也是苹果下一个扩展领域。对于Android来讲，Android@Home和Google TV的更新是一个明显的信号。当然，对于消费电子，特别是家庭电子，该领域太大太广，厂商众多，Google想分一杯羹谈何容易。如果所有的领域都需要别的硬件厂商的鼎力支持，有些领域可能完全就没机会打进去。何况有时候，别的硬件厂商完全就不靠谱，比如Sony做的Google TV。你会用么？反正我不会。所以，从这个层面上讲，Google收购的不是Moto的手机能力，而是硬件能力。有了Moto，Google可以做各种各样的硬件创新，并以此打入完全陌生的领域。&lt;/p&gt;
&lt;p&gt;那么这个收购在手机领域有什么影响呢？我不知道。而且当时大部分Googler也不知道，这也是Google内部问得最多的问题。我感觉肯定有影响，只是该影响可能在2-3年后太能体现。短时间内，Google肯定还是会一碗水端平，甚至会稍微照顾别的厂商一些。&lt;/p&gt;
&lt;p&gt;我在那篇文章里面有没有完全错误的论断呢？有。我说“Android只是Google的一个棋子。Android对于Google来说，是冗长战线上的一个坦克而已”。这个论断是完全错误的。Android对于Google来说，不是一个冗长战线上的坦克，而是一个王牌军。Google很清楚移动领域的未来，也很清楚它应该有多少资源投进Android。任何担心Android的地位会受哪怕一点点Chrome OS威胁的人，都是杞人忧天。Android会借鉴别的东西，但Android一直会是Android，Google在移动时代的王牌之一。&lt;/p&gt;
&lt;p&gt;在写完此文不久，我就写了另一篇文章，&amp;#8221;&lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  target=&quot;_blank&quot;&gt;Gingerbread，向左走还是向右走？&lt;/a&gt;&amp;#8220;。我在其中提到了一个观点：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;今天网上广为流传的消息，是来自TechCrunch的，Android团队正在努力解决用户体验的问题。伴随而来的，是Google正在考虑停止厂商自定义UI的权利，包括Sense UI、Moto Blur、Ninja Blur等等。一旦消息属实，我们假设Android真的限制了UI的定制权利，其他厂商如果生产Android手机，必须使用原生UI，那么造成的结果是什么样的？我会说，Android很可能会大败给苹果，而且连智能手机市场老二位置都占不了。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;直到今天，我认为这在当时发展情况下，也是无比正确的论断(汗)。为什么？当时的Android太丑了。我想象不出任何一个非Geek，在看到原生Android UI和iOS的UI后，会不选择后者。接下来，我分析了对于Google的可行策略：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;因为还有另外一种可能性，就是Google只限定底层的Framework不能更改，第三方手机制造商还是可以在系统里加入自己的预置功能，把系统改为自己希望改为的UI。我不希望看到自定制界面的灭亡，我只希望看到自定制界面的系统也能和原生系统一样，一起升级。&lt;/p&gt;
&lt;p&gt;除非，除非Gingerbread的UI有着超级大变身一般的升级，一下子让其他所有第三方UI完全失色，甚至超过苹果。这个幅度基本等于从赛亚人直接变身为超级赛亚人之三的幅度，换句话说，基本不可能。否则，否则Google必须想出某种办法，在改进UI体验的同时，尽可能少地牺牲Android开源的特性，让别的厂商没有退出不做的打算。是的，Moto在搞自己的系统，Samsung在搞自己的系统，HTC很可能搞自己的系统，但是没关系，Google只需要保证Android比他们都好一截，那么他们仍然会帮Android占领市场份额——反正是免费的。还是那个观点，Google不需要争第一，Google只需要让自己一直不断渗透这个市场，让市场没有明显的一家独大，就可以了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;至于Google如何保证Android比这些硬件厂商的OS都好一截，这个的可能性还是很大的&lt;/strong&gt;。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;同样，到现在，我认为当时的这个推测非常正确。Google的后续系统正是按照这个轨迹发展的。唯一的偏差是两点&lt;/p&gt;
&lt;p&gt;1. Gingerbread没有达到我的期望，虽然有改进，还是很丑，还是不流畅。Honeycomb终有巨大改进，可惜非通用系统。&lt;/p&gt;
&lt;p&gt;2. ICS完全做到了这个预测，甚至基本已经达到变身超级塞亚人2.5的地步了。&lt;/p&gt;
&lt;p&gt;到现在，话题终于和本篇文章的标题关联了。是的，这就是我对ICS的评价：基本可以和iOS并驾齐驱了。无论什么方面，设计，速度，操作感，灵魂。人们总是说，Android就是喜欢搞军备竞赛，不管什么硬件，系统还是那么丑那么烂那么卡那么多Bug。ICS推出之日，即是该说法消亡之时。&lt;/p&gt;
&lt;p&gt;读到这里，有些朋友可能要说了，太明显的android fanboy的言论。其实如果你看过我一年前的&lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  target=&quot;_blank&quot;&gt;Galaxy S评测&lt;/a&gt;，或者更早关于hero的文章，就知道，我的blog评测都是尽量客观的。那我就简单归纳一下，是什么让我有此感受的。&lt;/p&gt;
&lt;p&gt;1.　快，流畅。ICS终于支持GPU加速了。我不知道是什么导致Android到今天才完全拥抱此特性(3.0算半个支持），但幸运的是，终于支持了。如果你曾经在Android和iPhone上都用过twitter的话，你一定能留意出两者scroll时流畅的区别。这个区别一去不复返了。用ICS，任何时候你都能感觉到流畅，流畅，流畅。动画切换也好，scroll也好，不管在哪里。靠，连语音输入识别都那么流畅。我相信它不会比iPhone 4s“更流畅”，但至少是“一样流畅”。&lt;/p&gt;
&lt;p&gt;2.   漂亮。天阿，这是两年来第一款让我称赞操作系统漂亮的Android手机。我不知道GN上这个无以伦比的屏幕会不会加点分，我只知道，现在的系统，一切看着都是舒服的，而不是让人皱眉。精致的图标，优雅的切换。我在各种不同的界面中都用它和LD的iPhone 4比较，可以说各有千秋，再无巨大区别。不用多说，我就简单上两个图比较。这是国内bbs.gfan.com论坛一位网友照的Galaxy S2和Galaxy Nexus设置界面的区别：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/12/1111262348034091164ce16ede.jpg&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1622&quot; title=&quot;1111262348034091164ce16ede&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/12/1111262348034091164ce16ede.jpg&quot; alt=&quot;&quot; width=&quot;800&quot; height=&quot;531&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是著名AndroidPolice网站评测图中的一张&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Screen-Shot-2011-12-03-at-11.57.37-AM.png&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-large wp-image-1623&quot; title=&quot;Screen Shot 2011-12-03 at 11.57.37 AM&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Screen-Shot-2011-12-03-at-11.57.37-AM-1024x869.png&quot; alt=&quot;&quot; width=&quot;1024&quot; height=&quot;869&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你现在可以想象到为什么很多以Android为日常用机的朋友都会谴责界面了。&lt;/p&gt;
&lt;p&gt;顺带说一句，如果你是已有Android用户，希望知道更多ICS 界面的翻天覆地变化，可以看看Android Police推出的&lt;a href=&quot;https://www.google.com/search?ix=hca&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=getting-to-know-android-4-0&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/www.google.com');&quot; target=&quot;_blank&quot;&gt;getting-to-know-android-4-0&lt;/a&gt;系列。不会让你失望的。&lt;/p&gt;
&lt;p&gt;3.　直观。一个操作系统，流畅和漂亮是外在，直观的操作是核心。应该说，论直观性，ICS目前还是不如iOS。但和之前的Android版本比，确已经有了一个巨大的进步。用手势来remove进程，网页，通知，用手势来翻页。大幅度减少menu的使用，widget大小的自定制，等等等等。当你真正用的时候，你会发现，很多时候你想的是“早就应该这样了”&lt;/p&gt;
&lt;p&gt;4.   所有自带的Google服务软件完全超越其他所有平台。是的，我是说所有。Gmail, Gmap, Gvoice, Calendar, Google+, GMusic, you name it. 如果你是重度Google用户，你一旦用上，就不会再想离开这个天堂。Gmail和Gmap这些app，用起来纯粹是一种享受。更强的功能，更清新的界面，更直观的选项，更快捷的手势。&lt;/p&gt;
&lt;p&gt;5.   当Google说，他们会帮你同步手机上的everything时，它们真的是这么做的。如果你是之前Android手机用户的话，在同步完GN之后，不仅仅是你之前手机所有的apps，widgets，联系人信息都有，还同步了所有的墙纸，相片簿，以及网页里的bookmark和历史。是的，一切同步。你打开手机即可使用。&lt;/p&gt;
&lt;p&gt;6.　其他本来优势功能的继续增强。比如notification，widget，语音输入这些本来和iOS比就有优势的东西，现在的优势更大。之前一般的输入法也变得非常准确。还有有趣的头像解锁。更有意思的是，Cook刚在iPhone 4s发布会上讽刺了Android手机照相时间，ICS立刻推出了秒杀所有平台的即拍即得特性。连全景照相也是官方内置了。论算法的强大，Google还是不遑多让。&lt;/p&gt;
&lt;p&gt;如果你要问，难道这个系统就没有什么缺点么？有。某些小地方还是不够consistent，还有，还有，还有&amp;#8230;&amp;#8230;.hell, 对于喜欢Android的人来说，真没了&amp;#8230;&amp;#8230;是，GN有一些缺点，比如相机质量一般，屏幕费电。但对于ICS&amp;#8230;&amp;#8230;对不起，我真的找不出什么明显的缺陷了。&lt;/p&gt;
&lt;p&gt;那和iOS5比呢？&lt;/p&gt;
&lt;p&gt;那就得加上一个大缺陷：专门为ICS优化的app还是太少。不过这点在接下来的几个月中会大有改观。ICS不是Gingerbread，不是Honeycomb，它是unified system，也就是说，手机可用，平板可用，笔记本可用，冰箱可用，X86可用，ARM可用，连桌面电脑的显示屏&lt;a href=&quot;http://armdevices.net/2011/11/19/ice-cream-sandwich-works-on-st-ericsson-nova-a9500-arm-cortex-a9/&quot; onclick=&quot;javascript:pageTracker._trackPageview('a/armdevices.net');&quot; target=&quot;_blank&quot;&gt;都能正常显示&lt;/a&gt;。换句话说，人们只需要开发核心程序一次，然后用不同的界面配置，就可以让app运行在不同硬件上。加上ICS本身的巨大改进，开发者会蜂拥而来，做ICS oriented的app的。&lt;/p&gt;
&lt;p&gt;这是第一款，让我能彻底放弃我的iPhone 4并且没有丝毫回头之意并且还能欣赏其带来的新东西的手机。第一款。Jobs推出iPhone 1的时候说过，苹果领先别的系统至少5年。他又对了，今年是第五年。Android终于赶上了，从ICS开始。&lt;/p&gt;
&lt;p&gt;让我们期待Android和iOS从今往后的精彩战争吧。竞争，永远是对用户最好的事情。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Android-4.0-Ice-Cream-Sandwich-home-screen.jpg&quot;  rel=&quot;lightbox&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-1624&quot; title=&quot;Android-4.0-Ice-Cream-Sandwich-home-screen&quot; src=&quot;http://www.kunli.info/wp-content/uploads/2011/12/Android-4.0-Ice-Cream-Sandwich-home-screen.jpg&quot; alt=&quot;&quot; width=&quot;410&quot; height=&quot;350&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;*************************************我是分割线*********************************************&lt;/p&gt;
&lt;p&gt;一个题外话。还有朋友曾经问我用过Win7没有。&lt;/p&gt;
&lt;p&gt;我用过。&lt;/p&gt;
&lt;p&gt;感觉如何？&lt;/p&gt;
&lt;p&gt;不错。简洁流畅。不是很喜欢它的UI风格，但这是个人偏好。有希望在市场开辟另一片天。&lt;/p&gt;
&lt;p&gt;为什么不写一些关于它的想法？为什么每次都拿iOS和Android比？&lt;/p&gt;
&lt;p&gt;恩&amp;#8230;&amp;#8230;不好意思，我对微软怨念太深了。所有关于微软产品的文章，让我写出来最后估计3/4篇幅都是关于微软的吐槽。&lt;br /&gt;
&lt;h3&gt;也许你还会对这些文章感兴趣&lt;/h3&gt;
&lt;ul class=&quot;related_post&quot;&gt;
&lt;li&gt;2011-12-06 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/06/android-graphics/&quot;  title=&quot;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像&quot;&gt;Hackborn的吐槽和Munn的剖析: Android graphics低性能背后的真像 (9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-12-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/12/21/libsvm-androidjni-project/&quot;  title=&quot;一个新的开源项目Libsvm-androidjni&quot;&gt;一个新的开源项目Libsvm-androidjni (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-11-17 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/11/17/view-android-native-code-profiling/&quot;  title=&quot;如何对Android的本地代码进行profiling&quot;&gt;如何对Android的本地代码进行profiling (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-08-21 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/08/21/android-native-code-study-note/&quot;  title=&quot;Android Native 代码NDK开发学习笔记&quot;&gt;Android Native 代码NDK开发学习笔记 (2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2011-01-20 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2011/01/20/computer-performance-benchmark/&quot;  title=&quot;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感&quot;&gt;聊聊电脑性能测试的演变&amp;#8211;看Android评测有感 (1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-09-29 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/09/29/android-tcpdump/&quot;  title=&quot;Android上Tcpdump的使用&quot;&gt;Android上Tcpdump的使用 (0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-07-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/07/18/samsung-galaxy/&quot;  title=&quot;Samsung Galaxy S上手感受&quot;&gt;Samsung Galaxy S上手感受 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-18 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/18/gingerbread-pivot-version/&quot;  title=&quot;Gingerbread，向左走还是向右走？&quot;&gt;Gingerbread，向左走还是向右走？ (5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-06-09 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/06/09/androidtshirt/&quot;  title=&quot;Android机器人T-shirt情侣衫照&quot;&gt;Android机器人T-shirt情侣衫照 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-05-31 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/05/31/android-is-not-great-while-it-is-good-enough/&quot;  title=&quot;Android并不伟大，但丝毫不令人沮丧&quot;&gt;Android并不伟大，但丝毫不令人沮丧 (6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-02-11 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/02/11/android21-rom-best-todate/&quot;  title=&quot;目前最好的Android2.1 ROM之一 for Hero&quot;&gt;目前最好的Android2.1 ROM之一 for Hero (4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2010-01-23 &amp;#8212; &lt;a href=&quot;http://www.kunli.info/2010/01/23/modifying-the-android-logcat-stream-for-full-color-debugging/&quot;  title=&quot;彩色的Android debugging logcat term&quot;&gt;彩色的Android debugging logcat term (0)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;center&gt;visit the &lt;a href=&quot;http://www.kunli.info&quot; &gt;website&lt;/a&gt; for more great content.&lt;/center&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/631207166/windstorm/feedsky/s.gif?r=http://www.kunli.info/2011/12/04/ice-cream-sandwich/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><category domain="http://www.kunli.info">android</category><category domain="http://www.kunli.info">mobile</category><category domain="http://www.kunli.info">Galaxy Nexus</category><category domain="http://www.kunli.info">ICS</category><pubDate>Sun, 04 Dec 2011 13:15:16 +0800</pubDate><guid isPermaLink="false">http://www.kunli.info/?p=1621</guid><dc:creator>windstorm</dc:creator><fs:srclink>http://www.kunli.info/2011/12/04/ice-cream-sandwich/</fs:srclink><fs:srcfeed>http://www.kunli.info/feed/atom/</fs:srcfeed><fs:itemid>feedsky/windstorm/~8029071/631207166/1226385</fs:itemid></item></channel></rss>
