25 Feb 2010

PyQt4 Generate Code Problem


There are some unknown problem for PyQt4 while generating code in Windows. The error message is:

"code generation failed" 
"Unable to launch $YourPythonPath/Lib/site-packages/PyQt4/.\uic."

22 Feb 2010

获取google,百度搜索排行榜





获取google,百度搜索排行榜的脚本
运行后,会在同文件夹下产生topwords.txt.

update:
1. 原脚本分别写入2次文件,在google关键字包含¥符号时,此符号本身是gb2312的,解码utf-8没问题,再编码为gbk就出错.于是改成连接字符串,然后一次写入;

2. 正则加入group,可以简化掉一个循环.


21 Feb 2010

ZT-用python爬虫抓站的一些技巧总结

很经典,总结的很细致的python抓站技巧,忍不住要转帖一下.
原文来自: http://obmem.com/?p=476
作者: observer
下面文章奉上,大家鼓掌欢迎...


学用python也有3个多月了,用得最多的还是各类爬虫脚本:写过抓代理本机验证的脚本,写过在discuz论坛中自动登录自动发贴的脚本,写过自动收邮件的脚本,写过简单的验证码识别的脚本,本来想写google music的抓取脚本的,结果有了强大的gmbox,也就不用写了。
-
这些脚本有一个共性,都是和web相关的,总要用到获取链接的一些方法,再加上simplecd这个半爬虫半网站的项目,累积不少爬虫抓站的经验,在此总结一下,那么以后做东西也就不用重复劳动了。


1.最基本的抓站
import urllib2
content = urllib2.urlopen('http://XXXX').read()

2.使用代理服务器
这在某些情况下比较有用,比如IP被封了,或者比如IP访问的次数受到限制等等。
import urllib2
proxy_support = urllib2.ProxyHandler({'http':'http://XX.XX.XX.XX:XXXX'})
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
content = urllib2.urlopen('http://XXXX').read()

3.需要登录的情况
登录的情况比较麻烦我把问题拆分一下:
-
3.1 cookie的处理
import urllib2, cookielib
cookie_support= urllib2.HTTPCookieProcessor(cookielib.CookieJar())
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
content = urllib2.urlopen('http://XXXX').read()

是的没错,如果想同时用代理和cookie,那就加入proxy_support然后operner改为
opener = urllib2.build_opener(proxy_support, 
cookie_support, urllib2.HTTPHandler)

3.2 表单的处理
登录必要填表,表单怎么填?首先利用工具截取所要填表的内容
比如我一般用firefox+httpfox插件来看看自己到底发送了些什么包
这个我就举个例子好了,以verycd为例,先找到自己发的POST请求,以及POST表单项:






可以看到verycd的话需要填username,password,continueURI,fk,login_submit这几项,其中fk是随机生成的(其实不太随机,看上去像是把epoch时间经过简单的编码生成的),需要从网页获取,也就是说得先访问一次网页,用正则表达式等工具截取返回数据中的fk项。continueURI顾名思义可以随便写,login_submit是固定的,这从源码可以看出。还有username,password那就很显然了。
-
好的,有了要填写的数据,我们就要生成postdata
import urllib
postdata=urllib.urlencode({
    'username':'XXXXX',
    'password':'XXXXX',
    'continueURI':'http://www.verycd.com/',
    'fk':fk,
    'login_submit':'登录'
})

然后生成http请求,再发送请求:
req = urllib2.Request(
    url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/',
    data = postdata
)
result = urllib2.urlopen(req).read()

3.3 伪装成浏览器访问
某些网站反感爬虫的到访,于是对爬虫一律拒绝请求
这时候我们需要伪装成浏览器,这可以通过修改http包中的header来实现
headers = {
    'User-Agent':'Mozilla/5.0 (Windows; U; 
Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'
}
req = urllib2.Request(
    url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/',
    data = postdata,
    headers = headers
)

3.4 反”反盗链”
某些站点有所谓的反盗链设置,其实说穿了很简单,就是检查你发送请求的header里面,referer站点是不是他自己,所以我们只需要像3.3一样,把headers的referer改成该网站即可,以黑幕著称地cnbeta为例:
headers = {
    'Referer':'http://www.cnbeta.com/articles'
}

headers是一个dict数据结构,你可以放入任何想要的header,来做一些伪装。例如,有些自作聪明的网站总喜欢窥人隐私,别人通过代理访问,他偏偏要读取header中的X-Forwarded-For来看看人家的真实IP,没话说,那就直接把X-Forwarde-For改了吧,可以改成随便什么好玩的东东来欺负欺负他,呵呵。
-
3.5 终极绝招
有时候即使做了3.1-3.4,访问还是会被据,那么没办法,老老实实把httpfox中看到的headers全都写上,那一般也就行了。
再不行,那就只能用终极绝招了,selenium直接控制浏览器来进行访问,只要浏览器可以做到的,那么它也可以做到。类似的还有pamie,watir,等等等等。
-
4.多线程并发抓取
单线程太慢的话,就需要多线程了,这里给个简单的线程池模板
这个程序只是简单地打印了1-10,但是可以看出是并发地。
from threading import Thread
from Queue import Queue
from time import sleep
#q是任务队列
#NUM是并发线程总数
#JOBS是有多少任务
q = Queue()
NUM = 2
JOBS = 10
#具体的处理函数,负责处理单个任务
def do_somthing_using(arguments):
    print arguments
#这个是工作进程,负责不断从队列取数据并处理
def working():
    while True:
        arguments = q.get()
        do_somthing_using(arguments)
        sleep(1)
        q.task_done()
#fork NUM个线程等待队列
for i in range(NUM):
    t = Thread(target=working)
    t.setDaemon(True)
    t.start()
#把JOBS排入队列
for i in range(JOBS):
    q.put(i)
#等待所有JOBS完成
q.join()

5.验证码的处理
碰到验证码咋办?这里分两种情况处理:
-
1.google那种验证码,凉拌
-
2.简单的验证码:字符个数有限,只使用了简单的平移或旋转加噪音而没有扭曲的,这种还是有可能可以处理的,一般思路是旋转的转回来,噪音去掉,然后划分单个字符,划分好了以后再通过特征提取的方法(例如PCA) 降维并生成特征库,然后把验证码和特征库进行比较。这个比较复杂,一篇博文是说不完的,这里就不展开了,具体做法请弄本相关教科书好好研究一下。
-
3.事实上有些验证码还是很弱的,这里就不点名了,反正我通过2的方法提取过准确度非常高的验证码,所以2事实上是可行的。
-
6.总结
基本上我遇到过的所有情况,用以上方法都顺利解决了,不太清楚还有没有其他漏掉的情况,所以本文到这里就完成了,以后要是碰上其他情况,再补充相关方法好了:)


19 Feb 2010

matlab矩形相交合并函数



问题:
有一N*4的矩形列表,其中每行数据表示一个矩形,格式为[x,y,w,h],依次是矩形左上角的x坐标,y坐标和矩形的宽w和高h.找到这些矩形中的相交矩形,并将小矩形合并入大矩形,如果同一矩形和多个矩形相交,用相交部分的面积除以矩形的面积求得一个比值,优先合并比值最大的两个矩形.最后的输出结果是一个矩形列表,其中的矩形两两都不相交.

分析见http://goo.gl/90FW.

整个问题起初困扰了我好一阵时间,因为考虑的很细,感觉需要考虑的东西很多,矩阵的东西跟着下标转来转去都转晕乎了.后来索性推倒重来,找张白纸,用笔写出伪代码,发现写下来并没有考虑的那么复杂.


function outRectList = rectMerge(inRectList)

1) 设置合并阀值tRatio, 并令outRectList = inRectList.

2) 计算最小面积矩阵matMinArea,并转化为严格上三角矩阵(其实是除了严格上三角,其他位置置1,因为要后面做除法,0不能做除数),其中(i,j)(j>i)的值是inRectList(i)和inRectList(j)这2个矩阵面积中较小的面积值.

3) 计算相交面积矩阵matAreaInt,并转化为严格上三角矩阵,其中(i,j)(j>i)的值是inRectList(i)和inRectList(j)这2个矩阵相交的面积,其他位置都为0.

4) 计算相交比值矩阵matRatio,就是用matAreaInt点除matMinArea,这样得到一个严格上三角矩阵;然后用tRatio这个阀值来判定,如果小于阀值,置0,否则保留原值.

5) 如果matRatio的元素不全为0,设置循环标志intFlag=1,否则intFlag=0.

6) while intFlag,开始循环

7) 寻找matRatio这个矩阵中的最大值,并得到其横,纵坐标i,j,这就是即将合并的矩阵序号.

8) 根据i和j,更新outRectList.具体为:去outRectList里面查找这2个矩形的面积,将面积小的矩形合并到面积大的矩形(合并法则为原面积大的矩形变大到包含原2个矩形,原小矩形从矩形列表中删除.

9) 针对新的outRectList,重新计算matMinArea,matAreaInt,matRatio.

10) 根据新的matRatio设置循环标志intFlag,进入下次循环.

end

18 Feb 2010

你开日本车 即使不是丰田 也有安全隐患


小结一下:

  1、我修过的车,最近五年的车里,丰田是非常糟糕的。它的 starter, water pump (水泵)寿命极短。即使 2010 年的车,丰田车不敢像韩国车那样10 万迈保修,Infiniti, Lexus, Acura 也不敢像Cadillac 那样10 万迈保修。

  2、丰田油门踏板的毛病出在踏板本身,不是什么脚垫之类的胡扯。

  3、加上了一块铁片,目的是防止真空管里的真空导致刹车失灵。防止卡住的作用有限。

  4、不论你开什么车,只要发现油门回不来,要立刻踩刹车,而且别松开。同时,用右手把档位往后拉,一旦拉到 1 档的位置,最大油门,车也只能跑 20 迈 / 小时。而不论什么车,有的可能不许你在高速的时候换成 N 档,但绝不会有不让你拉回到 2 档和 1 档的。只要你脚踩刹车,你一定能把档拉回到最后的 1 档。车子立刻就减速了。你这么做了,白捡了一条甚至多条命,别忘了感谢我夜里不睡觉给你打字。

  5. 没有“ Brake Override System (刹车是爷系统)”的日本车( 2010 年的 Nissan 除外),刹车很难刹住。你如果没开过日本车,那你在出门租车的时候千万别租日本车,因为你刹不住而导致追尾。那位警察租的 Lexus ,本来他可以刹住的,但他发现刹车不怎么管用,就以为刹车失灵了,才松开刹车,把真空放掉了,再刹车,就真的失灵了,最后导致四人死亡。警察一般是不开日本车的,所以,他不熟悉日本车的刹车。

  6、在西方人眼里,日本车是穷人开的。当然,很多有钱人喜欢别人认为自己是穷人,这样安全。如果您也是这样,或者开日本车就是想改变美国人的传统文化,那恭喜您。但如果您是想显示您是富人,您开日本车,不论什么牌子,您开的都是穷人车。很多中国人不知道这个,就把自己的看法强加给美国人。美国人也不会当面告诉您这个。美国人有不少瞧不起女人或黑人的,但很少有当面说出来的,两口子都不会暴露的。你可以说这是虚伪,也可以说这是教养。但骨子里的东西,不是一下子能改变的。

  7、别到人多的地方去站着,因为真理只在少数人手里。如果你买丰田就是因为丰田销售量第一,以及你身边很多中国人买丰田,你就是与在纳斯达克 5500 的时候买入的那些人是同类水平;如果你买的车,身边的中国人没有人买这个牌子的车,对于中国人来说,你就是真牛逼,因为你的心理很强大,逃出了中国传统奴性文化的束缚,你的脑袋已经属于你自己了。再过两年后,假如中国人都不再买丰田了,而你买,那表明你是牛逼中的牛逼。因为丰田一旦两年翻不过身,那它以后再造的车就像今年美国通用和福特造的车一样物美价廉、性能可靠、安全舒适。否则,就是退出历史舞台关门大吉一途。

  8、凡是看到我这篇文章的,需要做一件事,当然你把文章打印出来甚至转给别人都可以,但我要说的是:您需要做一次演习:别着急把车开走,而是坐在车里演练一下。假如你的车子突然自己加速了,你立刻踩刹车不放松。同时,右手把档往回拉,拉到最后的 1 档。当然,你不要打火。就比划一下即可。为何要有地震、火灾演练?因为演练一遍以后,真到了那个时刻,你就不慌张了。一旦慌张,看过的文章就记不得了,但演练过的程序不会忘掉。脚踩刹车,右手拉档。就这么简单。很多人在高速路上撞车死了,其中就有一部分是因为刹车故障,因为不管什么车,哪个零部件都有坏掉的可能。很多人就眼看着自己的车子往前跑而惊慌失措或者束手无策,其实,很简单:把档拉回到最后,即使刹车彻底失灵,车子也要回到20迈以下,因为油门最大的时候,1档只能跑到20迈/小时的速度,通常撞击测验用的都是35迈以上,20迈的时速是死不了人的。这么简单的演练,你只要做了,你就能保命了。这与什么车无关,什么车都有零部件失灵的可能。

  9、车子的安全是开出来的,不是造出来的!所以,要掌握处理应急的技巧,无外乎突然加速、刹车失灵、突然转向。掌握技巧和安全驾驶比车子的牌子重要。




(一)丰田油门踏板的问题到底是怎么回事

  丰田(Toyota )因为突然加速并刹不住车而引发的“丰田安全危机”风暴席卷全球,目前我们知道丰田已经开始维修,就是在油门踏板上加一个铁片!为了说明到底是咋回事,我把从丰田网站上的图找来贴在这里,图内有部分解释,我让大家知道丰田加一个铁片的道理,也能明白丰田是靠改装这个玩意忽悠它的消费者,还是真的能解决问题。



油门踏板,可以看出,丰田车用的两种油门踏板(一个是美国 CTS 公司造的,一个是日本 Denso 公司造的)外表是差不多的,看上去是可以互换的



CTS 油门踏板的工作原理。对不起,我写了错字。图中的“曹里”应该是“槽里”。这个设计是由丰田自己的工程师干的。别埋怨 CTS 。它的要命的地方在于: A 与 B 之间不能有空隙。这样,就容易“粘连”在一起。为何 CTS 给美国、德国等汽车制造厂生产的油门踏板就没问题?请看后面的解释您就明白了



丰田召回的 900 万辆车后,就是在那个地方加一个铁片




示意图。可看出铁片加的地方。对敌勒来说,这个活太容易了。一个铁片造价很低。丰田计算的是成本。比较抠门。加一个铁片的目的就是不让 A 过多进入 B,这样,最大油门得不到了,但也够用的




Denso 的油门踏板。这个设计不存在粘住问题。要是出了问题的话,比如 sensor 坏了,那可不是靠加一个铁片就能解决的

  那么,为何丰田不把召回的车统统换成 Denso 的油门踏板呢?有人抱怨说如果换成新的油门踏板,丰田要出更多的血,买踏板要比买铁片贵多了。这是所谓的“内行”们非常恼火丰田的地方。然而,润涛阎告诉您:这两种油门踏板给出的信号可能是不一样的。 CTS 出的那个踏板是金属的,测出的是 A 与 B 之间的接触面积(踩油门越大,接触面积越大),也就是测出的是“电流”然后送给电脑。而 Denso 出的那个,中间是塑料的,测出来的不是金属与金属之间的电流,而是光学原理。中间那个塑料滚轮滚动的角度大小可以用简单的光学信号交给电脑。这样,如果丰田把召回的车换成 Denso 的油门踏板,那个电脑里边的信号处理器要更换的。

  在美国,修车店里的人不会拆开电脑去换里边的部件的,要换就得把整个电脑换掉。我担心的是:在日本出的用 Denso 油门踏板的车,不仅仅油门踏板不同而导致的电脑里的信号处理器不同,而且还有其它零件不同,比如电子油门开关。一旦换了电脑,那个部位也要换才成。这样,每部车需要数千美元(工钱加上零件钱), 900 万辆的规模,那就是数百亿美元,丰田没有那么多现金,就只好破产保护了。

  这里说一下:润涛阎自己从来都不会买丰田车的,所以,写此文不是自己恨丰田,更不是落井下石,而是真正的站在中间立场,地地道道的旁观者。也是为很多中国人的安全着想。我不在车行工作,也没有可能得到任何汽车制造厂的好处。所以,才能做到公平公正地谈论这个话题。

  (二)我在1985 年发现:日本车是垃圾

  我在高中毕业后不能立刻上大学,有机会修理内燃机,所以,那时在国内我有内燃机修理证,英文叫 License 。到了美国,我买了一部福特二手车,花了5350 美刀。我有一位国内的老同学,他姓李,也跟我先后来到美国读博,但跟我不是同一个系,他让我帮他买一辆二手车。刚好我们系里一位实验员(美国白人)要卖她的两年新的丰田 Toyota Tercel. 由于她腰部有了伤,不能开手动档,需要买一部自动档的二手车,就想把那部两年新的丰田手动档车卖掉。我跟老李商量,因为她卖车的原因清楚,可以买这辆车。老李听我的,我就帮他讨价还价,最后以 1650 美刀成交。办手续那天可热闹了!她丈夫就是老李一个导师的博士生!老李没有跟他提买车的事,因为他认为求我帮忙就够了,再说人家美国人不会关心别人的私事。我在中间讨价还价,结果人家二人是同一实验室同一老板的博士生。同学归同学,生意归生意。价格就这么定了。

  都是两年新,我的福特 5350 美刀,而他的丰田只有1650 ,相差三倍多,而且我的车里程数比他的高。

  从此以后,老李就跟我学修车。我在国内修车有个习惯:把报废的旧零件用斧子砸,看看那个厂子的零件是不是好东西。俗话说,不怕不识货,就怕货比货。丰田车也好,本田车也罢,日本车的零件是两层皮的!凡是摩擦的外面,都是特硬的好钢;里边的就是软铁。比如说吧,那个 master cylinder (刹车泵),里边的小活塞,也就是跟筷子差不多粗细,我用榔头一震,就把里边的软铁芯给拉出来了!就这么点材料,日本人还是要精打细算的,还要做成里边是软铁,外面是硬钢。

  有的零件,外面的薄皮很薄,用榔头一砸,一下子就陷下去了。美国车零件,里外都是一样的钢材。而日本车零件,用钢锉只要锉几下就可看到光亮的外表包着的黑色的软铁。

  老李当时就明白了为何日本车如此便宜(那时候,日本车便宜得很)。可惜,老李因为肝癌几年前去世了,否则,今天让他写一篇精彩的文章很容易。

  10 年后,我的新家一位邻居是日本人,他的工作就是在美国造汽车零件。他是那个厂子的经理。由于他女儿跟我女儿是同班同学,都在读小学,时常在一起做作业或玩。两家的接触就很多了。他用中文给我写出他的名字“小林青”(或者是“小林清”,我忘记了)。我跟他谈论最多的就是汽车零件了。我告诉他,日本车的零件是两层皮的!他听后脸上通红,然后他问我是从哪家媒体暴露的。我说是我自己砸出来的。他才笑了。我拿 Honda Civic 后闸刹车泵里的零件被我用锉刀锉开后看到的两层皮让他看。他说,美国的大财团都购买了日本车的股份,不可能在媒体上披露这个的。美国的媒体都是私人的,也就是财团控制的。但他说,日本车不是要开几十年,没必要里外都是好钢材。听他这么一说,我也不认为日本车是垃圾了。由于遭到了我的鄙视,他还愤愤不平,说日本人这一手可是跟你们中国学的!我一听很好奇,因为我在国内时根本就没有发现中国的零件是两层皮的。他说,当年日本的军刀都是好钢,所以,大兵只能扛长枪,只有军官才有军刀。后来得知,中国有“好钢用在刀刃上”一说,研究发现中国的刀是两种材料:刀刃上的是好钢,其它地方都是软铁。

  从此,我再也没资格跟他提日本车零件是忽悠人的垃圾这个话题了。但我告诉他:“迟早有一天这种造汽车零件的方式会捅出大漏子来的!”他摇头不信。

  今天,听说他的公司搬到佛罗里达了,我不知道他的通讯地址,否则,我一定跟他谈论这个话题。

  (三)丰田油门踏板的毛病,根本原因可能是“两层皮”导致的

  同样都是油门踏板,同样是CTS 一家出的,为何美国车德国车就没这个问题?因为人家要求所有的钢材都是一样的。而丰田的油门踏板,摩擦的部位是好钢,而不摩擦的部位是软铁。由于 A 和 B 钢材的材料不同,导致由于温度变化热胀冷缩的程度不同,在温度特低的时候,由于 A 与 B 钢材密度有异,冷缩的系数不同,可能导致接触不上。这就使得有时候你加油踩下油门踏板,车子不走,等你再加大油门,接触面积加大后突然车子窜出去。等到车子过热的时候,油门踏板的 A 与 B 由于热胀系数不同,一下子就把 A 与 B 靠在一起了,你即使松开油门踏板,踏板也回不来了,因为 A 与 B 之间太紧密了,摩擦力太大了,超过了弹簧的张力。

  那为何丰田车子会突然加速呢?按照物理学常识,油门踏板由于 A 与 B 过紧而不能弹回来,那油门也不会加大,虽然不会减小。其实,对这个问题我没看到解释。以润涛阎的猜测,也就是理论和逻辑推理,是因为开车的人发现油门没回来,卡住了,就想去踩一下,让它弹回来。可这一踩不要紧,油门踏板的 A 与 B 的接触面更大了,摩擦力也更大了,它就无法弹回来了不算,油门也加大了。这就是那位警察开Lexus 车子跑到120 迈的速度才撞毁的缘故。

  那么,到底是CTS 的油门踏板档次高,还是日本Denso 塑料芯踏板档次高?我个人认为: CTS 的档次高!因为金属的寿命要比塑料长多了。问题在于:丰田在设计油门踏板的时候用的材料是两种,而美国车德国车用的是一种。一种材料,由于热胀冷缩的系数一样,就没有丰田车的问题。日本人偷工减料,降低成本,又没有在意油门踏板,导致了这样19 人死亡的悲剧。按照我的推理,丰田油门踏板设计者太大意了,日本人只是知道中国人有“好钢用在刀刃上”的成语,不知道有“大意失荆州”的典故。如果丰田不是大意而理所当然地认为美国车德国车都用这个设计没问题,他们也不会有问题,那么,他们就会把 A 和 B 分成两个机关:两种钢材没问题,只是在 A 的背面或 B 的背面用另一弹簧顶着,而非现在的铸在一起。那样的话,不论温度怎么变化,A 和 B 的接触是恒定的,是靠背面的弹簧压住的。其实,这么简单的构想,丰田就没在意。毕竟不是发动机,也不是变速箱,一个踏板而已。所以,不起眼的地方,大意了,说不定就把公司给毁了。战争也是一样,不起眼的一个家伙当了叛徒,军事机密敌人知道了而满盘皆输的历史故事太多了。

  (四)油门踏板回不来,为何刹车不灵了?

  很多搞电脑的猜测是因为丰田在造车的时候,把电脑里的程序设置搞得出了问题,比如:油门不回来,电脑就告诉刹车别干活。

  事实上,这个猜测是不对的。丰田的车,大部分牌子我都拆过。我在美国帮朋友修车,修的最多的就是丰田,不是我愿意修丰田,而是大家都买丰田。很多人问汽车销售商的专家,为何油门回不来,刹车不灵而导致人死亡?那些所谓的专家也给不出你答案。道理在于:那些修车的人很多连大学都考不上,去专科学校学了怎么修车,就完了。他们知道哪个零件该怎么卸下来,该怎么装上去。你要问他零件里边是啥东西,道理为何,他们根本就没那好奇,也没那智商。他们只知道他们学过的,没学过的,他们不想知道。

  我来告诉您这个奥秘:当油门开到最大的时候,真空管里的真空就没有了。而刹车用的 power brake (动力刹车系统),需要真空。当油门踏板被开车的人用脚踩到了底(就是因为发现油门回不来了,才想再踩一下让它回来),油门全部打开了,此时,真空管里的真空没有了,power brake 就无效了。当然,如果碰上了体重500 磅的驾驶员,他一抬屁股就可以在右脚上踩到200 磅。200 磅是可以把刹车踩住的。因为 power brake 动力制动比人工制动大出20 倍。一般10 磅的力量就可刹住70 迈的车,要是没有了动力制动,靠脚的力量那要 200 磅。通常我们的体重还不到200 磅,很多女人100 磅左右,又不知道抬屁股刹车,一旦真空管里没有了真空,就刹不住了。

  但是,这里有个救命的窍门,您看了这篇文章,说不定万一遇到类似情况(未必是油门踏板,电脑控制的油门开关也有坏的时候!),我就成了你的救命恩人呢!

  当油门开到最大的时候,真空管里没有了真空,但只要你不放开刹车,用力刹,里边的真空不会泄露出来,你就可以把车刹住!

  那为何有19 个人因为刹不住车死了呢?因为他们不懂得这个道理!他们发现刹车不那么灵,就把刹车松开然后再踩。这就麻烦了,因为一旦松开刹车,里边的真空没有了,就再也没有办法了。所以,您看到了这篇科普文章,您以后万一发现车子油门很大,千万别松开刹车,只要你坚持踩刹车,你肯定会把车刹住的。

  (五)丰田给加一块铁片,道理何在?有没有用?

  您如果仔仔细细读完了上面的解释,您就应该知道了:加上一块铁片,油门踏板的 A 与 B 就无法让油门开到最大了。因为油门开不到最大,真空管里的真空就能够让刹车不失灵。也就是说,丰田的这个补救办法不是说车子以后不会卡住油门了,而是卡住后,也不会刹不住车。即使驾驶员反复放开刹车,因为真空没问题,车子还会刹住的。

  当然,丰田说以后不会卡住了。其实,道理在于:由于 A 与 B 的接触面积不能达到原来那么大了,摩擦力也就不会那么大了。但润涛阎以为:那块铁片不能太厚,因为太厚就无法加速了。也就是说,卡住的事还会发生的,只是即使发生,刹车系统不失灵,导致送命的情况就少了。车子能刹住,发动机发疯,那就让它疯一会好了。等你停下来,把发动机关掉,车子冷下来后,油门踏板一冷缩, A 与 B 之间就不那么紧了,弹簧就把它弹回来了。你再上路,继续享受开车的刺激。只要没有生命危险,有点刺激是人生的一种额外享受,要不怎么那么多人花钱去转那个 6 flag(编者注:美国著名的游乐场所,有很多过山车的刺激游戏) 、迪尼斯之类的呢?

  (六)加个铁片是治标,那如何治本?

  如果您在2000 年以前开过车,您应该知道,那时候的车油门踏板是直接连到油门开关上的,也就是说,你踩的是油门本身。后来,电脑的发展用在了汽车上。油门踏板不再跟油门开关相连,而是跟电脑相连。你踩的不是油门,是电脑。电脑根据信号,再给油门开关下命令。所以,问题就大了。首先,油门踏板是否会出问题,是否会卡住。然后,即使没有卡住,那个感应器是否坏了。一旦坏了,你踩油门了,车不走。但不会加速。这个道理很简单:每个车的电脑都有磨人的设定,什么意思呢?就是不论电脑出了什么问题,比如电脑得不到信号,那就死火。断不会有电脑坏了而加速的设置。但要是油门开关本身卡住了,就像油门踏板卡住一样,那就不能减速了。

  聪明的人总是有的!在2002 年,有人研究出了“ brake override system”( 中文有人翻译成“刹车优先系统”,其实 override 在这里不是“优先”,而是“霸道”。更确切的翻译应该是“刹车是爷”。爷来了,孙子们都得让路! ) 。这是什么意思呢?就是:只要你踩刹车,不论油门信号是什么,供油系统立刻把油减小到最小,专业词汇叫“怠速”,英文叫 idle ,就是发动机的转速在你不给油门的时候,小于这个转速,发动机就会死火。大于这个转速,发动机耗油太多,浪费。怠速一般是 550 ---750 转/ 分钟。这个差异取决于发动机里边的惯性轮的重量。

  凭记忆,我知道大约在2002 年,奔驰买了这个专利就把奔驰车装上了这个brake override system( 刹车是爷系统 ) 。2003 年,美国车,比如Chryslers 也买了这个专利把新车安装了这个系统。接着,宝马、大众(vw )等欧洲其它车也都安装上了这个系统。如果你买的是 2010 年的日本车,除了 Nissan 外,其它的车都没有这个系统。 2011 年以后,美国可能不允许在美国卖车,除非安装了这个系统。

  下面谈谈有没有这个系统的差异。首先,别说丰田车导致19 条人命,即使不死人,车祸也不是小事。

  同样的车,安装不安装这个系统,刹车的容易程度差异很大。比如,在 70 迈的速度下刹车,有没有这个系统,刹住车所需要的距离相差超过12 英尺!车子体重差不多的6 缸 Nissan 出的2010 Infiniti G37 ,由于有“刹车是爷系统”,比6 缸的Toyota 出的2010 车,在100 迈的速度下刹车,刹住的距离相差24 英尺之巨!为何差那么多呢?

  这里需要给您介绍一下为何这个系统叫“刹车是爷系统”。在2000 年以前的车,你可以看到发动机顶部有油门开关,一个半圆形的上面有钢丝拉着。这个钢丝就直接通往你的油门脚踏板。你一踩油门踏板,这个钢丝就拉着那个油门开关把油门打开。但你会发现有两根钢丝。其中一个是通往油门踏板的,另一个是被一个油门缓冲器拉着。你想想看,如果没有缓冲器,你的脚一放开油门踏板,油门立刻回到怠速,你会感到“咯噔”一下的。这个钢丝被一个弹簧拉着,你松开油门,油门不会一下子下来,而是缓慢下来。这样,你就感觉不到“咯噔”一下了。

  这一下,问题就来了!你松开油门去踩刹车,刹车刹的不仅仅是车子的惯性,还有高速运转的发动机!因为油门没有回来。

  有了这个“刹车是爷系统”,只要你踩刹车,油门的供油系统立刻回到怠速位置,哪怕你另一只脚去踩油门,或者油门卡住了,也不会给发动机加油。

  那么,这个系统价值是多少呢?告诉你,你肯定会骂人!这个系统,包括专利,每辆车只有 30-50 美刀!当然看车子产量。越多,越便宜。本人多年来百思不得其解,日本人太缺德,就那么几十美刀,就不给安装!别说撞死人,就是刹车,在70 迈的速度下,也差10 英尺之外!很多日本车追尾导致前边后边撞烂,买日本车的人从不开欧洲车,比如大众 VW ,并不比日本车贵,他们不知道刹车的差异有多大。

  你明天去开一开装上了这个系统的Nissan 出的Infiniti 和没有装上这个系统的丰田出的Lexus ,同一个级别的,比如都是轿车,或都是SUV。你也可以比较一下其它牌子的车。不比不知道,一比吓一跳。

  有人说,本田(Honda)就没问题。其实,目前还没有看到本田召回的消息,并不等于没有问题。我知道两个中国人去年买的本田新车,发现在路上突然加速。当然没有发生车祸。中国人不愿意告状。说不定哪天你会听到美国人状告本田,你不需要吃惊。因为本田的零件也是两层皮的!即使油门踏板不出毛病,刹车的时候油门还在高处,刹车的同时还要刹大油门的发动机,追尾是时常发生的。再说了,电动油门开关也难免不出错,汽车的近 2 万个零部件,没有哪个绝对不出毛病的。一旦出了毛病,车子突然自己加速了,要是没有“刹车是爷系统”,即使刹住,也要走很远的路程,说不定就追尾把前边的车给撞了。

  (七)日本车的另一安全隐患

  提起这件事,很多人就很生气。大家买车子时都看车子安全评级。日本车的安全评级不低,可大家不知道,这个安全评级的 5 星级是根据前边撞击、侧面撞击测出的。而顶部加压只给一个参考,甚至很多车子都不测这一项。

  什么意思呢?就是说,如果车子一旦翻过来了,四轮朝上了,车里边的人有没有生命危险。也就是说,根据车子的自身重量,在车顶部往下压,看看能否经得住。假如你的车重量是 4000 磅,翻过去的时候车子还有惯性应力,不会像我们把它抬起来翻过去慢慢放下那么柔和,就要加上一个系数。比如用 4500 磅的压力。经得住的,就是G(Good ) , 然后是A(Acceptable ),再后面就更糟糕了。

  在所有的日本车中,只有 Subaru 出的所有车种都是达标的G (好),其它的日本车有一个是本田的 Honda Element 达标外,全部不达标。只是因为美国高速公路管理局还没有把翻车能活下来作为指标,日本人就钻这个空子。尤其是丰田,连一辆达标的车都没有,丰田出了那么多种车,没有一种车是 G 。假如你开的不是Subaru ,而是其它日本车,那你就要小心了,千万别翻车,一旦翻车,你和乘客性命难保。

  问题出在哪里呢?出在车子的窗户框上。日本车为了减少成本,比如丰田,每一种车型的窗户框所用的钢材硬度都很差,单薄,而且里边是塑料。事实上,我看到过翻车四轮朝上的,一共有两次。我有一同事,曾经翻车四轮朝上了,但他的车是美国oldsmobile ,车窗框经得住车身的压力,否则他的脑袋就压扁了。

  只要你不翻车,开日本车是可以的。如果翻车,命可是难保,除非你开的是 Subaru 。

  (八)日本车是穷人开的车

  美国历史上,第一辆打入美国的日本车是 Subaru ,那是日本车里最好的车。其实,就是今天,日本车寿命最长的还是 Subaru 。很多中国人尤其是 90 年以后才来到美国的中国人,没经历过日本车便宜地跟大白菜似的。就不知道日本车的历史,那就是:日本车是为美国的穷人造的。

  1958 年,日本的Subaru 打入美国,理由就是:美国很多穷人买不起新车,需要给这个群体造车。 1958 年, Subaru 共 1 万辆进入美国,每辆车售价1997 美刀。我到了美国后,第一件事就是研究美国市场上的车。那时候没有Google,只能到图书馆看书,了解美国的汽车历史。

  打从日本的 Subaru 打入美国,美国的穷人也就有机会开新车了。一直这样,大约30 年吧,日本车是穷人开的车就成了共识,毕竟30 年不是个小数目,一个人有几个30 年啊。即使我刚到美国的时候,日本车已经开始涨价了,但那时候一看你开日本车,美国人还是认为你是穷人。这个传统很难改变,后来,年轻人不在乎自己是不是穷人富人的,社会毕竟发展了。但欧洲人就比较保守了,至今很多欧洲人依然认为开日本车的人是穷人,很掉价。

  这个是汽车文化现象,与日本车是否可靠关系不大。比如,中国人被日本人打服了,瞧得起日本人,也就觉得开日本车不掉价。但韩国人没把中国人打服过,中国人开韩国车觉得掉价,就跟美国人欧洲人开日本车觉得掉价一个道理。这与韩国车的质量、价格无关,韩国车也有八缸豪华车,但中国人看到你开的是10 万迈保修、八缸韩国车,你那牌子是啥中国人都不打听,反正认为那是掉价的,不如开日本车。

  这种汽车文化是传统造成的,当然是不科学的。车子,本来就应该是一个交通工具,没有必要与身份挂钩。社会会朝着这个方向走的无疑。但改变传统是很难的。只是很多中国人不知道这个事,还以为自己开日本车很风光。

  (九)为何在海外的中国人喜欢丰田?

  中国人有一个特点:别人买什么车我买什么车。买车前根本就不去开一开别的车是咋样的。我每次跟中国人建议别买日本车,都是无效的。中国人的传统就是“同向思维”这符合独裁者培养奴才的文化。大家都往一处想,独裁者管理起来就容易了。

  事实上,这个世界是有规律的。比如,在30 年代以前,福特车遥遥领先,它肆无忌惮地乱造车,也不担心卖不掉。后来,通用超过了福特,全球第一,也学福特当年,只想扩大销售量,不在乎质量了。后来,就有了丰田。丰田也一样,只顾扩大利润,质量就不在乎了。其实, 2010 年的车,福特和通用的车要比日本车质量好得多,因为质量上不去,那就彻底完了。没有退路。

  我小的时候都知道这个道理,因为我一边上小学,一边倒小买卖。我明白千万别随大流。大家都种白菜,我肯定种萝卜。

  小结一下:

  1、我修过的车,最近五年的车里,丰田是非常糟糕的。它的 starter, water pump (水泵)寿命极短。即使 2010 年的车,丰田车不敢像韩国车那样10 万迈保修,Infiniti, Lexus, Acura 也不敢像Cadillac 那样10 万迈保修。

  2、丰田油门踏板的毛病出在踏板本身,不是什么脚垫之类的胡扯。

  3、加上了一块铁片,目的是防止真空管里的真空导致刹车失灵。防止卡住的作用有限。

  4、不论你开什么车,只要发现油门回不来,要立刻踩刹车,而且别松开。同时,用右手把档位往后拉,一旦拉到 1 档的位置,最大油门,车也只能跑 20 迈 / 小时。而不论什么车,有的可能不许你在高速的时候换成 N 档,但绝不会有不让你拉回到 2 档和 1 档的。只要你脚踩刹车,你一定能把档拉回到最后的 1 档。车子立刻就减速了。你这么做了,白捡了一条甚至多条命,别忘了感谢我夜里不睡觉给你打字。

  5. 没有“ Brake Override System (刹车是爷系统)”的日本车( 2010 年的 Nissan 除外),刹车很难刹住。你如果没开过日本车,那你在出门租车的时候千万别租日本车,因为你刹不住而导致追尾。那位警察租的 Lexus ,本来他可以刹住的,但他发现刹车不怎么管用,就以为刹车失灵了,才松开刹车,把真空放掉了,再刹车,就真的失灵了,最后导致四人死亡。警察一般是不开日本车的,所以,他不熟悉日本车的刹车。

  6、在西方人眼里,日本车是穷人开的。当然,很多有钱人喜欢别人认为自己是穷人,这样安全。如果您也是这样,或者开日本车就是想改变美国人的传统文化,那恭喜您。但如果您是想显示您是富人,您开日本车,不论什么牌子,您开的都是穷人车。很多中国人不知道这个,就把自己的看法强加给美国人。美国人也不会当面告诉您这个。美国人有不少瞧不起女人或黑人的,但很少有当面说出来的,两口子都不会暴露的。你可以说这是虚伪,也可以说这是教养。但骨子里的东西,不是一下子能改变的。

  7、别到人多的地方去站着,因为真理只在少数人手里。如果你买丰田就是因为丰田销售量第一,以及你身边很多中国人买丰田,你就是与在纳斯达克 5500 的时候买入的那些人是同类水平;如果你买的车,身边的中国人没有人买这个牌子的车,对于中国人来说,你就是真牛逼,因为你的心理很强大,逃出了中国传统奴性文化的束缚,你的脑袋已经属于你自己了。再过两年后,假如中国人都不再买丰田了,而你买,那表明你是牛逼中的牛逼。因为丰田一旦两年翻不过身,那它以后再造的车就像今年美国通用和福特造的车一样物美价廉、性能可靠、安全舒适。否则,就是退出历史舞台关门大吉一途。

  8、凡是看到我这篇文章的,需要做一件事,当然你把文章打印出来甚至转给别人都可以,但我要说的是:您需要做一次演习:别着急把车开走,而是坐在车里演练一下。假如你的车子突然自己加速了,你立刻踩刹车不放松。同时,右手把档往回拉,拉到最后的 1 档。当然,你不要打火。就比划一下即可。为何要有地震、火灾演练?因为演练一遍以后,真到了那个时刻,你就不慌张了。一旦慌张,看过的文章就记不得了,但演练过的程序不会忘掉。脚踩刹车,右手拉档。就这么简单。很多人在高速路上撞车死了,其中就有一部分是因为刹车故障,因为不管什么车,哪个零部件都有坏掉的可能。很多人就眼看着自己的车子往前跑而惊慌失措或者束手无策,其实,很简单:把档拉回到最后,即使刹车彻底失灵,车子也要回到20迈以下,因为油门最大的时候,1档只能跑到20迈/小时的速度,通常撞击测验用的都是35迈以上,20迈的时速是死不了人的。这么简单的演练,你只要做了,你就能保命了。这与什么车无关,什么车都有零部件失灵的可能。

  9、车子的安全是开出来的,不是造出来的!所以,要掌握处理应急的技巧,无外乎突然加速、刹车失灵、突然转向。掌握技巧和安全驾驶比车子的牌子重要。


17 Feb 2010

matlab矩阵创建



1、 向量的创建

1)直接输入:

行向量:a=[1,2,3,4,5]

列向量:a=[1;2;3;4;5]



2)用“:”生成向量

a=J:K 生成的行向量是a=[J,J+1,…,K]

a=J:D:K 生成行向量a=[J,J+D,…,J+m*D],m=fix((K-J)/D)

3)函数linspace 用来生成数据按等差形式排列的行向量

x=linspace(X1,X2):在X1和X2间生成100个线性分布的数据,相邻的两个数据的差保持不变。构成等差数列。

x=linspace(X1,X2,n): 在X1和X2间生成n个线性分布的数据,相邻的两个数据的差保持不变。构成等差数列。

4)函数logspace用来生成等比形式排列的行向量

X=logspace(x1,x2) 在x1和x2之间生成50个对数等分数据的行向量。构成等比数列,数列的第一项x(1)=10x1,x(50)=10x2

X=logspace(x1,x2,n) 在x1和x2之间生成n个对数等分数据的行向量。构成等比数列,数列的第一项x(1)=10x1,x(n)=10x2

注:向量的的转置:x=(0,5)’



2、 矩阵的创建

1)直接输入:将数据括在[]中,同一行的元素用空格或逗号隔开,每一行可以用回车或是分号结束

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5



2)函数eye,生成单位矩阵

eye(n) :生成n*n阶单位E

eye(m,n):生成m*n的矩阵E,对角线元素为1,其他为0

eye(size(A)):生成一个矩阵A大小相同的单位矩阵

eye(m,n,classname):对角线上生成的元素是1,数据类型用classname指定。其数据类型可以是:duoble、single、int8、uint8、int16、uint16、int32、uint32 。



3)函数ones 用ones生成全1的矩阵

ones(n) : 生成n*n的全1矩阵

ones(m,n) : 生成m*n的全1矩阵

ones(size(A)) : 生成与矩阵A大小相同的全1矩阵

ones(m,n,p,…)生成m*n*p*….的全1的多维矩阵

ones(m,n,…,classname)制定数据类型为classname



4)函数zeros 函数zeros生成全0矩阵

zeros(n):生成n*n的全0矩阵

zeros(m,n:)生成m*n的全0矩阵

zeros(size(A)): 生成与矩阵A大小相同的全0矩阵

zeros (m,n,p,…)生成m*n*p*….的全0的多维矩阵

zeros (m,n,…,classname)指定数据类型为classname



5)函数rand 函数rand用来生成[0,1]之间均匀分布的随机函数,其调用格式是:

Y=rand:生成一个随机数

Y=rand(n):生成n*n的随机矩阵

Y=rand(m,n):生成m*n的随机矩阵

Y=rand(size(A)):生成与矩阵A大小相同的随机矩阵

Y=rand(m,n,p,…):生成m*n*p*…的随机数多维数组

6)函数randn 函数rand用来生成服从正态分布的随机函数,其调用格式是:

Y=randn:生成一个服从标准正态分布的随机数

Y=randn(n):生成n*n的服从标准正态分布的随机矩阵

Y=randn(m,n):生成m*n的服从标准正态分布的随机矩阵

Y=randn(size(A)):生成与矩阵A大小相同的服从标准正态分布的随机矩阵

Y=randn(m,n,p,…):生成m*n*p*…的服从标准正态分布的随机数多维数组



3、 矩阵元素的提取与替换

1) 单个元素的提取

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入b=a(1,2)

b =

2



2) 提取矩阵中某一行的元素,

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入b=a(1,:)

b =

1 2 3



3) 提取矩阵中某一列:

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入b=a(:,1)

b =

1

3



4) 提取矩阵中的多行元素

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入b=a([1,2],:)

b =

1 2 3

3 4 5



5) 提取矩阵中的多列元素

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入b=a(:,[1,3])

b =

1 3

3 5



6) 提取矩阵中多行多列交叉点上的元素

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入b=a([1,2],[1,3])

b =

1 3

3 5



7) 单个元素的替换:

如:a=[1,2,3;3,4,5],运行后:

a =

1 2 3

3 4 5

输入:a(2,3)=-1

a =

1 2 3

3 4 -1



4、 矩阵元素的重排和复制排列

1) 矩阵元素的重排

B=reshape(A,m,n):返回的是一个m*n矩阵B,矩阵B的元素就是矩阵A的元素,若矩阵A的元素不是m*n个则提示错误。

B=reshape(A,m,n,p):返回的是一个多维的数组B,数组B中的元素个数和矩阵A中的元素个数相等

B=reshape(A,…,[],…):可以默认其中的一个维数

B=reshape(A,siz) : 由向量siz指定数组B的维数,要求siz的各元素之积等于矩阵A的元素个数



2) 矩阵的复制排列 函数是repmat

B=repmat(A,n):返回B是一个n*n块大小的矩阵,每一块矩阵都是A

B=repmat(A,m,n):返回值是由m*n个块组成的大矩阵,每一个块都是矩阵A。

B=repmat(A,[m,n,p,…]):返回值B是一个多维数组形式的块,每一个块都是矩阵A



5、 矩阵的翻转和旋转

1)矩阵的左右翻转 左右翻转函数是fliplr,调用格式:

B=fliplr(A):将矩阵A左右翻转成矩阵B。

输入:A=[1,2,3;3,4,2]

A =

1 2 3

3 4 2

输入:B=fliplr(A)

B =

3 2 1

2 4 3

2)矩阵上下翻转 函数:flipud,调用格式:

B=flipud(A):把矩阵A上下翻转成矩阵B



3) 多维数组翻转 函数:flipdim,调用格式:

B=flipdim(A,dim):把矩阵或多维数组A沿指定维数翻转成B



4) 矩阵的旋转 函数:rot90,调用格式:

B=rot90(A):矩阵B是矩阵A沿逆时针方向旋转90。得到的

B=rot90(A,k):矩阵B是矩阵A沿逆时针方向旋转k*90。得到的(要想顺时针旋转,k取-1)

6、 矩阵的生成与提取函数

1) 对角线函数 对角线函数diag既可以用来生成矩阵,又可以来提取矩阵的对角线元素,其调用格式:

a) A=diag(v,k):当v是有n个元素的向量,返回矩阵A是行列数为n+|k|的方阵。向量v的元素位于A的第k条对角线上。K=0 对应主对角线,k>0对应主对角线以上,k<0对应主对角线以下。 b) A=diag(v):将向量v的元素放在方阵A的主对角线上,等同于A=diag(v,k)中k=0的情况。 c) v=diag(A,k):提取矩阵A的第k条对角线上的元素于列向量v中。 d) v=diag(A):提取矩阵A的主对角线元素于v中,这种调用等同于v=diag(A,k)中k=0的情况。 2) 下三角阵的提取 用函数tril,调用格式: a) L=tril(A): 提取矩阵A的下三角部分 b) L=tril(A,k):提取矩阵A的第k条对角线以下部分。K=0 对应主对角线,k>0对应主对角线以上,k<0对应主对角线以下。 3) 上三角阵的提取 函数triu,调用格式: a) U=triu(A): 提取矩阵A的上三角部分元素 b) U=triu(A,k): 提取矩阵A的第k条对角线以上的元素。K=0 对应主对角线,k>0对应主对角线以上,k<0对应主对角线以下

判断矩形相交

问题:给定两个矩形A和B,矩形A的左上角坐标为(Xa1,Ya1),右下角坐标为(Xa2,Ya2),矩形B的左上角坐标为(Xb1,Yb1),右下角坐标为(Xb2,Yb2)。
(1)设计一个算法,确定两个矩形是否相交(即有重叠区域)
(2)如果两个矩形相交,设计一个算法,求出相交的区域矩形


(1) 对于这个问题,一般的思路就是判断一个矩形的四个顶点是否在另一个矩形的区域内。这个思路最简单,但是效率不高,并且存在错误,错误在哪里,下面分析一下。


 如上图,把矩形的相交(区域重叠)分成三种(可能也有其他划分),对于第三种情况,如图中的(3),两个矩形相交,但并不存在一个矩形的顶点在另一个矩形内部。所以那种思路存在一个错误,对于这种情况的相交则检查不出。

仔细观察上图,想到另一种思路,那就是判断两个矩形的中心坐标的水平和垂直距离,只要这两个值满足某种条件就可以相交。

矩形A的宽 Wa = Xa2-Xa1 高 Ha = Ya2-Ya1

矩形B的宽 Wb = Xb2-Xb1 高 Hb = Yb2-Yb1

矩形A的中心坐标 (Xa3,Ya3) = ( (Xa2+Xa1)/2 ,(Ya2+Ya1)/2 )

矩形B的中心坐标 (Xb3,Yb3) = ( (Xb2+Xb1)/2 ,(Yb2+Yb1)/2 )

所以只要同时满足下面两个式子,就可以说明两个矩形相交。
1) | Xb3-Xa3 | <= Wa/2 + Wb/2
2) | Yb3-Ya3 | <= Ha/2 + Hb/2

即:

| Xb2+Xb1-Xa2-Xa1 | <= Xa2-Xa1 + Xb2-Xb1

| Yb2+Yb1-Ya2-Ya1 | <=Y a2-Ya1 + Yb2-Yb1

(2) 对于这个问题,假设两个矩形相交,设相交之后的矩形为C,且矩形C的左上角坐标为(Xc1,Yc1),右下角坐标为(Xc2,Yc2),经过观察上图,很显然可以得到:

Xc1 = max(Xa1,Xb1)

Yc1 = max(Ya1,Yb1)

Xc2 = min(Xa2,Xb2)

Yc2 = min(Ya2,Yb2)

这样就求出了矩形的相交区域。

另外,注意到在不假设矩形相交的前提下,定义(Xc1,Yc1),(Xc2,Yc2),且Xc1,Yc1,Xc2,Yc2的值由上面四个式子得出。这样,可以依据Xc1,Yc1,Xc2,Yc2的值来判断矩形相交。

Xc1,Yc1,Xc2,Yc2只要同时满足下面两个式子,就可以说明两个矩形相交。

3) Xc1 <= Xc2

4) Yc1 <= Yc2

即:

max(Xa1,Xb1) <= min(Xa2,Xb2)

max(Ya1,Yb1) <= min(Ya2,Yb2)

ps: matlab中的rectint函数用的也是这个思想.

update: matlab函数已经写好,见http://goo.gl/ofTY

15 Feb 2010

2010央视春晚下载,多个地址

2010的春晚烂到几点,虽有几点闪光之处.
不过不看可不知道有多烂,多个春晚视频下载.


可以迅雷的
1

ftp://dygod8:dygod8@d201.dygod.org:2339 /[电影天堂www.dygod.com]2010年CCTV春节联欢晚会A.rmvb


2

ftp://dygod9:dygod9@d201.dygod.org:2339 /[电影天堂www.dygod.com]2010年CCTV春节联欢晚会B.rmvb
===============================
超级高清:
free rapid downloader 可以同时下载六个.速度很快,海外也很快。

第一部分 http://u.115.com/file/t2a61bab42
第二部分 http://u.115.com/file/t2db71df7f
第三部分 http://u.115.com/file/t2293819a3
第四部分 http://u.115.com/file/t291645f3c
第五部分 http://u.115.com/file/t2c254de6b
第六部分 http://u.115.com/file/t2b3623469
第七部分 http://u.115.com/file/t2665b318c
第八部分 http://u.115.com/file/t2b29282d7
第九-十部分 http://u.115.com/file/t2cca99042

===============================
网盘下载

节目单:
---------------------------------

1.开场歌舞《虎跃龙腾贺春来》
  2.相声剧《不能让他走》演员:冯巩、闫学晶、韩雪等
  3.歌舞《让我们舞起来》演员:宋祖英
  4.小品《一句话的事儿》演员:郭冬临、牛莉
  5.歌曲《相亲相爱》演员:容祖儿、孙楠、王力宏等 
  6.舞蹈《玩具店之夜》
  7.群口相声《和谁说相声》演员:姜昆、戴志诚、赵津生
  8.舞蹈《荷塘莲雨》 
  9.小品《美丽的尴尬》黄宏 巩汉林 林永健 金玉婷
  10.歌曲《传奇》演员:王菲
  11.小品《我心飞翔》演员:殷桃、闫妮、刘敏、柴权、刘思言、陈维涵
  12.歌曲《祖国万岁》演员:韩磊等
  13.串场节目:道德模范 海地英雄家属\民族歌舞大串联《美好家园》《壮乡梅》《我和草原有个约会》《卓玛》《妹妹的山丹花儿开》《党的政策亚克西》
  14.小品《五十块钱》演员:周锦堂、尹北琛等
  15.歌曲串烧《爱》《蝴蝶飞》《青苹果乐园》演员:小虎队
  16.近景魔术 演员:刘谦
  17.少数民族舞蹈《跳春》
  18.小品《家有毕业生》演员:蔡明、郭达等
  19.歌曲《幸福》演员:张也等
  20.舞蹈《追梦》
  21.歌曲《微笑》毛阿敏
  22.杂技《试比天高》
  23.倒背百家姓 王仙妮、歌曲《龙文》演员:谭晶、陈奕迅
  24.小品《捐款》演员:赵本山、小沈阳
  25.歌曲《拍拍拍》演员:蔡国庆、解小东等
  26.歌曲《阳光路上》演员:阎维文
  27.经典老歌集锦《我们和祖国一起长大》《让我们荡起双桨》《快乐的节日》《春天在哪里》《在灿烂阳光下》演员:李谷一、蒋大为、胡松华、屠洪刚、刘和刚等
  28.歌曲《走向复兴》演员:戴玉强、殷秀梅  零点敲钟
  29.歌曲《盛世欢歌》
  30.相声《论捧逗》演员:贾玲、白凯南
  31.戏曲《红楼赞花》演员:袁慧琴、于魁智等
  32.歌曲联唱:《一亩田》、《婚礼上的歌》、《幸福的两口子》演员:汤潮、庞龙、吕薇等
  33.武术舞蹈《对弈》演员:王亚彬等
  34.歌组合《彩云之南》《姑娘我爱你》《天蓝蓝》
  35.相声《超级大卖场》演员:李伟建、武宾
  36.歌曲《我要歌唱》师鹏、姚贝娜等
  37.舞蹈《春天的芭蕾》
38.结束曲《难忘今宵》


文件格式: 高精度MKV/H.264+AAC.MP4
完整版下载2.3G
全部5小时38个节目, 分成5个部分.

三个网盘下载 可以快速平行下载:


下载地址:


地址1:UL:
----------------------
【CD1】
http://uploading.com/files/a5fc71md/2010ChunWan01.part1.rar/
http://uploading.com/files/6dm99ff5/2010ChunWan01.part2.rar/


【CD2】
http://uploading.com/files/253a35f5/2010ChunWan02.part1.rar/
http://uploading.com/files/37fc4359/2010ChunWan02.part2.rar/
http://uploading.com/files/b7b4e79a/2010ChunWan02.part3.rar/


【CD3】
http://uploading.com/files/dde63383/2010ChunWan03.part1.rar/
http://uploading.com/files/5de83aca/2010ChunWan03.part2.rar/


【CD4】
http://uploading.com/files/3e387eb6/2010ChunWan04.part1.rar/
http://uploading.com/files/c1d7a631/2010ChunWan04.part2.rar/


【CD5】
http://uploading.com/files/2524b375/2010ChunWan05.part1.rar/
http://uploading.com/files/67fdbbb9/2010ChunWan05.part2.rar/
http://uploading.com/files/bab87f16/2010ChunWan05.part3.rar/




地址2:(HF+DF)
-----------------------------------
【CD1】
http://hotfile.com/dl/28479157/39f0785/2010ChunWan01.part1.rar.html
or:
http://depositfiles.com/files/rbq4lfe7i

http://uploading.com/files/6dm99ff5/2010ChunWan01.part2.rar/


【CD2】
http://hotfile.com/dl/28500084/c9b9727/2010ChunWan02.part1.rar.html
http://hotfile.com/dl/28500085/97a19e8/2010ChunWan02.part2.rar.html
http://hotfile.com/dl/28509522/748ab19/2010ChunWan02.part3.rar.html

【CD3】
http://depositfiles.com/files/nve2c3i7b
http://depositfiles.com/files/uex7v94lm


【CD4】
http://depositfiles.com/files/avgb3p0nx
http://depositfiles.com/files/t9y68nvtc


【CD5】
http://depositfiles.com/files/3dzkuqdgt
http://hotfile.com/dl/28548513/5c9305b/2010ChunWan05.part2.rar.html
or
http://depositfiles.com/files/ip2tfebjt

http://hotfile.com/dl/28548511/db2d868/2010ChunWan05.part3.rar.html


2010春晚王菲<传奇>HD

2010春晚王菲<传奇>

魔术揭密-人体穿透玻璃

刘谦这么火,贴个魔术解密吧.虽说解密了,就没有那么神奇,
但是专业魔术师的表演功力和技巧还是值得一顶!
ps: 看了这个应该就明白刘谦穿玻璃的奥秘了吧?
要是还像下面回复那个哥们一样,就没辙了!

13 Feb 2010

blogspot显示增大缩小字体模块

博客字体增大缩小模块,请点击本页右上角测试效果.



<script type="text/javascript"> 
/* = 请先定义下列参数 = */
var _name = "div"; 
var _attr = "id"; 
var _post = "content"; 
/* =================== */
function isdigit(c) 
{
return ((c>='0') && (c<='9')); 


function atoi(s) 

var t=0; 
for(var i=0; i < s.length; i++) 

    var c=s.charAt(i);
    if(!isdigit(c))
        return t;
    else 
        t = t*10 + (c-'0'); 

return t; 


function fontZoom(size) 

var element = document.getElementsByTagName(_name); 
for(var i=0; i < element.length; i++) 

    if(element[i].getAttribute(_attr) == _post) 
    { 
        if (element[i].style.fontSize == '') 
            element[i].style.fontSize = "14px"; 
        var fixsize = atoi(element[i].style.fontSize) + size; 
        if (fixsize <= 0) 
            fixsize = 14; 
        element[i].style.lineHeight = "1.2"; 
        element[i].style.fontSize = fixsize + "px"; 
    } 


</script>
Font Size: <a href="javascript:fontZoom(+1)" title="Zoom In"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAePC6WVlCBUZaR21_f69VWY5AQRn7FkUZ1KM7DgEhEHtYB_xFE61R0UXujtToOSOCK5YFIvH2f4g6Ozy_7_q46vffJxWdo5CBmCvttP8gSSAmIc7rdEMWH0WIAZuXJK7mBTzhrwJmGNw/" /></a> <a href="javascript:fontZoom(-1)" title="Zoom Out"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPqgoySr_M8VaRY2eaqd7NfAVN_MargELrWxWRVZmuqvQFTrzWJ5C8Zxd0udRrxniOXCWWradB33bXmqu1BdCdA8aTYnob3N1uPnCIrFucVvOPRtvAKrTpCxr_KTKvHJMwsAjmCxj51UY/" /></a>

11 Feb 2010

[转]使用文本文件(.txt)进行数据存取的技巧总结



特别说明:由于大家在 I/O 存取上以 txt 文件为主,且读取比存储更麻烦(存储的话 fwrite, fprintf 基本够用),因此下面的讨论主要集中在“txt 文件的读取”上。除了标注了“转”之外,其余心得均出于本人经验之结果,欢迎大家指正、补充。



一. 基本知识:
-------------------------------------------------- 转----------------------------------------------------
1. 二进制文件与文本文件的区别:
将文件看作是由一个一个字节(byte) 组成的, 那么文本文件中的每个字节的最高位都是0,也就是说文本文件使用了一个字节中的七位来表示所有的信息,而二进制文件则是将字节中的所有位都用上了。这就是两者的区别;接着,第二个问题就是文件按照文本方式或者二进制方式打开,两者会有什么不同呢?其实不管是二进制文件也好,还是文本文件也好,都是一连串的0和1,但是打开方式不同,对于这些0和1的处理也就不同。如果按照文本方式打开,在打开的时候会进行translate,将每个字节转换成ASCII码,而以按照二进制方式打开的话,则不会进行任何的translate;最后就是文本文件和二进制文件在编辑的时候,使用的方式也是不同的。譬如,你在记事本中进行文本编辑的时候,你进行编辑的最小单位是字节(byte);而对二进制文件进行编辑的话,最小单位则是位(bit),当然我们都不会直接通过手工的方式对二进制文件进行编辑了。

从文件编码的方式来看,文件可分为ASCII码文件和二进制码文件两种:
ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。例如,数5678的存储形式为:
ASCII码: 00110101 00110110 00110111 00111000
↓  ↓      ↓   ↓
十进制码: 5     6   7      8

共占用4个字节。ASCII码文件可在屏幕上按字符显示,例如源程序文件就是ASCII文件,用DOS命令TYPE可显示文件的内容。由于是按字符显示,因此能读懂文件内容。

二进制文件是按二进制的编码方式来存放文件的。例如,数5678的存储形式为:00010110 00101110 只占二个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作“流式文件”。

2. 文本模式(textmode)和二进制模式(binarymode)有什么区别?

流可以分为两种类型:文本流和二进制流。文本流是解释性的,最长可达255个字符,其中回车/换行将被转换为换行符“\n”,(如果以"文本"方式打开一个文件,那么在读字符的时候,系统会把所有的"\r\n"序列转成"\n",在写入时把"\n"转成"\r\n" )。二进制流是非解释性的,一次处理一个字符,并且不转换字符。

注:

\n一般会操作系统被翻译成"行的结束",即LF(Line-Feed)
\r会被翻译成"回车",即CR(Cariage-Return)
对于文本文件的新行,在UNIX上,一般用\n(LF)来表示,Mac上用\r(CR)来表示,
Windows上是用\n\r(CR-LF)来表示。

通常,文本流用来读写标准的文本文件,或者将字符输出到屏幕或打印机,或者接受键盘的输入;而二进制流用来读写二进制文件(例如图形或字处理文档),或者读取鼠标输入,或者读写调制解调器。如果用文本方式打开二进制文件,会把“0D 0A”自动变换成“\n”来存在内存中。写入的时候反向处理。而二进制方式打开的话,就不会有这个过程。但是,Unicode/UTF/UCS格式的文件,必须用二进制方式打开和读写。
---------------------------------------------------------------------------------------------------------

上述基础其实大可以略过,简言之,对用户来说:在 matlab 中存储成为二进制还是文本文件取决于fopen的方式,如果用wt,则存储为文本文件,这样用记事本打开就可以正常显示了;如果用w则存储为二进制文件,这样用记事本打开会出现小黑方块,要正常显示的话,可以用写字板或UltraEdit等工具打开。

二. Matlab的I/O文件操作使用技巧和总结:

1. Matlab 支持的I/O文件(对应“取/存”操作)类型:(所有文件I/O程序不需要特殊的工具箱)
http://www.mathworks.com/support/tech-notes/1100/1102.html

(注:从上表可以看到,matlab不支持doc格式的文档存取(因为doc文档包含很多格式控制符),请改用txt或者 dat格式)

2. Matlab 的I/O文件指南:
http://www.mathworks.com/support/tech-notes/1600/1602.html


以下是部分对应的中文译文:
--------------------------------------------------------------转 ----------------------------------------
本技术支持指南主要处理:ASCII, binary, and MAT files.
要得到MATLAB中可用来读写各种文件格式的完全函数列表,可以键入以下命令:
help iofun

MATLAB中有两种文件I/O程序:high level and low level.
High level routines: 包括现成的函数,可以用来读写特殊格式的数据,并且只需要少量的编程。
Low level routines: 可以更加灵活的完成相对特殊的任务,需要较多的额外编程。


High level routines 包括现成的函数,可以用来读写特殊格式的数据,并且只需要少量的编程。

举个例子,如果你有一个包含数值和字母的文本文件(text file)想导入MATLAB,你可以调用一些low level routines自己写一个函数,或者是简单的用TEXTREAD函数。

使用high level routines的关键是:文件必须是相似的(homogeneous),换句话说,文件必须有一致的格式。下面的段落描述一些high level file I/O routines并给出一些例子帮助理解概念。

LOAD/SAVE

主要的high level file I/O routines 是LOAD 和 SAVE函数。LOAD
可以读MAT-file data或者用空格间隔的格式相似的ASCII data. SAVE可以将MATLAB变量写入MAT-file格式或者空格间隔的ASCII data。大多数情况下,语法相当简单。下面的例子用到数值由空格间隔的ASCII file sample_file.txt :

1 5 4 16 8

5 43 2 6 8

6 8 4 32 1

90 7 8 7 6

5 9 81 2 3

Example:
用 LOAD and SAVE 读写数据




CODE:

% Load the file to the matrix, M :
M = load('sample_file.txt')

% Add 5 to M :
M = M +5

% Save M to a .mat file called 'sample_file_plus5.mat':
save sample_file_plus5 M

% Save M to an ASCII .txt file called 'sample_file_plus5.txt' :
save sample_file_plus5.txt M -ascii




UIGETFILE/UIPUTFILE

UIGETFILE/UIPUTFILE是基于图形用户界面(GUI)的。会弹出对话框,列出当前目录的文件和目录,提示你选择一个文件。UIGETFILE让你选择一个文件来写(类似Windows ‘另存为’选项?)。用UIGETFILE,可以选择已存在的文件改写,也可以输入新的文件名。两个函数的返回值是所选文件名和路径。

Example:
用 UIGETFILE 从当前目录选择一个 M-file




CODE:

% This command lists all the M-files in the current directory and
% returns the name and path of the selected file


[fname,pname] = uigetfile('*.m','Sample Dialog Box')




注意: UIGETFILE 一次只能选择一个文件。

UIIMPORT/IMPORTDATA

UIIMPORT是一个功能强大,易于使用的基于GUI的high level routine,用于读complex data files。文件也必须是homogeneous。

IMPORTDATA形成UIIMPORT的功能,不打开GUI。可以将IMPORTDATA用于函数或者脚本中,因为在函数或者脚本中基于GUI的文件导入机制并不理想。下面的例子用到包含几行文件头和文本、数值数据的文件'sample_file2.txt' :

This is a file header.

This is file is an example.

col1 col2 col3 col4

A 1 4 612.000

B 1 4 613.000

C 1 4 614.000

D 1 4 615.000

Example: Using IMPORTDATA to read in a file with headers, text, and numeric data




CODE:

% This reads in the file 'sample_file2.txt' and creates a
% structure D that contains both data and text data.
% Note the IMPORTDATA command specifies a white space
% as the delimiter of the file, but IMPORTDATA can usually
% detect this on its own

D = importdata('sample_file2.txt','') % 原文有误?

D = importdata('sample_file2.txt')




可以通过访问结构D的数据和文本域,来看结构D中的真实值,例如输入:

data = D.data

text = D.textdata

可以用UIIMPORT读同一个文件并得到同样的结构.

注意: 对于 ASCII data, 你必须检验导入向导正确的识别了列分隔符。

TEXTREAD/STRREAD

TEXTREAD 是一个强大的动态high level routine,设计用来读ASCII格式的文本和/或数值数据文件。STRREAD除是从字符串而不是文件读以外,类似于TEXTREAD。

两个函数可以用许多参数来改变其具体的工作方式,他们返回读入指定输出的数据。他们有效的提供给你一个
“两全其美”的方法,因为他们可以用一个命令读入混合的ASCII和数值数据(high level routines的做法),并且你可以改变他们以匹配你特定的应用(如同low level routines做到的)。例子:




CODE:

Example 1: Using TEXTREAD to read in an entire file into a cell array

% This command reads in the file fft.m into the cell array, file

file = textread('fft.m','%s','delimiter','\n','whitespace','');




CODE:

Example 2: Using STRREAD to read the words in a line

% This command uses the cell array created in Example 1 to
% read in each word of line 28 in 'file' to a cell array, words

words = strread(file{28},'%s','delimiter','')



CODE:

Example 3: Using TEXTREAD to read in text and numeric data from a file with headers

% This command skips the 2 header lines at the top of the file
% and reads in each column to the 4 specified outputs

[c1 c2 c3 c4] = textread('sample_file2.txt','%s %s %s %s','headerlines',2)





CODE:

Example 4: Using TEXTREAD to read in specific rows of text and numeric data from a file

% This command reads in rows B and C of the file. The 'headerlines'
% property is used to move down to the desired starting row and the
% read operation is performed 2 times

[c1 c2 c3 c4] = textread('sample_file2.txt',...
'%s %s %s %s',2,'headerlines',4)



CODE:

Example 5: Using TEXTREAD to read in only the numeric data from a file containing text and numbers

% This command reads in only the numeric data in the file. The
% 'headerlines' property is used to move down to the first row
% of interest and the first column of text is ignored with the
% '*' operator

[c2 c3 c4] = textread('sample_file2.txt','%*s %d %d %f','headerlines',3)




DLMREAD/DLMWRITE/CSVREAD

DLMREAD 和 DLMWRITE函数能够读写分隔的ASCII data,而不是用low level routines。他们比low level routines容易使用,Low level routines用几行代码实现的功能可以用DLMREAD/DLMWRITE 简化成一行。

CSVREAD用来读分隔符是逗号的文件,是DLMREAD的特殊情况。当读空格和Tab分隔的电子数据表文件时,DLMREAD特别有用。以'sample_file.txt'为例:




CODE:

Example 1: Using DLMREAD to read in a file with headers, text, and numeric data

% This reads in the file 'sample_file2.txt' and creates a matrix, D,
% with the numeric data this command specifies a white space as the
% delimiter of the file

D = dlmread('sample_file.txt','')






CODE:

Example 2: Using DLMREAD to extract the first 3 columns of the last 3 rows

% This reads in the first 3 columns of the last 3 rows of
% the data file 'sample_file.txt'into the matrix, D_partial.
% 读文件 'sample_file.txt' 前3列后3行,到矩阵D_partial.

D_partial = dlmread('sample_file.txt','',[2 0 4 2])






CODE:

Example 3: Using DLMWRITE to write a comma delimited file

% This creates a file called 'partialD.txt' that consists of
% the first 3 columns of the last 3 rows of data where each
% element is separated by a comma

dlmwrite('partialD.txt',D_partial,',')




注意: 保证DLMREAD and DLMWRITE指定范围的指标从0开始,而不是从1开始。

WK1READ/WK1WRITE

WK1READ 用来读Lotus123 电子数据表文件的数据;WK1WRITE用来写矩阵到Lotus123 电子数据表文件。

XLSREAD

XLSREAD用来读Excel的数值和文本数据。

---------------------------------------------------------------------------------------------------------

三. 具体例子分析:
Matlab网站用两个例子非常详尽地介绍了各个命令的基本用法,实际中,面对手头上的数据,如何选用合适的命令呢?以下结合几个示例给出一些总结,大家举一反三就可以了:

1. 纯数据(列数相同):
源文件:



CODE:
0 3866.162 2198.938 141.140
1 3741.139 2208.475 141.252
2 3866.200 2198.936 141.156
3 3678.048 2199.191 141.230
4 3685.453 2213.726 141.261
5 3728.769 2212.433 141.277
6 3738.785 2214.381 141.256
7 3728.759 2214.261 141.228
8 3748.886 2214.299 141.243
9 3748.935 2212.417 141.253
10 3733.612 2226.653 141.236
11 3733.583 2229.248 141.223
12 3729.229 2229.118 141.186




解答:对于这个txt文件,由于各行列数相同,故简单地使用 load,importdata均可。


2.字段名(中、英文字段均可)+数据:
源文件:


CODE:
CH0 CH1 CH2 CH3
0.000123 0.000325 0.000378 0.000598
0.000986 0.000256 0.000245 0.000698


解答:由于是记录的形式,因此各行列数必相同(缺少部分列时请自行在文件中补上 Inf 或 NaN),故直接使用 importdata 便可。

3.注释(含有独立的数字串)+数据(列数相同):
问题:这个文件有4列,但前6行是文字说明,4列数字是从第8行开始的.现在我想把这个文件的前2列和文字说明提出来组成一个新的dat文件

源文件:


CODE:
Group 2 12.02.2006 Limei
Samples of datas: 50000

CH0 CH1 CH2 CH3
0.000123 0.000325 0.000378 0.000598
0.000986 0.000256 0.000245 0.000698


目标文件:


CODE:
Group 2 12.02.2006 Limei
Samples of datas: 50000

CH0 CH1
0.000123 0.000325
0.000986 0.000256


解答:由于注释中含有独立的数字串,且注释部分没有明显的格式,这时候用importdata, load等高级命令直接读取会失败,用 textread, dlmwrite 等格式化命令也不太合适,因此只能使用低级命令进行读取。(当然了,可以跳过注释部分直接用高级命令读取数据,即:[a b c d] = textread(filename,'%f %f %f %f','headerlines',4); )。一个简单的、非通用的包含注释的读取方法如下:
-------------------------------------转 ---------------------------------------------------------------------------------------

CODE:
clc;clear;
fid = fopen('exp.txt', 'r');
fid_n=fopen('ex.dat','w');
while ~feof(fid)
tline=fgetl(fid);
if ~isempty(tline)
if double(tline(1))>=48 && double(tline(1))<=57 %数值开始 a=strread(tline); a(3:4)=[]; fprintf(fid_n,'%f %f\n',a); clear a; elseif double(tline(1))==67 %字母C开始 [b1,b2,b3,b4]=strread(tline,'%s %s %s %s'); b=[b1{1},' ',b2{1}]; fprintf(fid_n,'%s\n',b); clear b b1 b2 b3 b4; else fprintf(fid_n,'%s\n',tline); end else fprintf(fid_n,'%s\n',tline); end end fclose(fid); fclose(fid_n); --------------------------------------------------------------------------------- 4. 注释(不含独立的数字串)+数据(列数相同): 源文件: CODE: 你好 abc 欢迎来到 我们 振动论坛 vib.hit.edu.cn 1 11 111 1111 2 22 222 2222 3 33 333 3333 4 44 444 4444 5 55 555 5555 解答:直接用 importdata 便可 注:有时候注释中含有独立的数字串也可以 importdata 成功,不过得到的结果有可能不正确,建议这时候使用第3种情形的读取方式。 5. 注释与数据混排: 对此当然只能自己编程,举例: 源文件: CODE: 1 11 111 1111 你好 2 22 222 2222 欢迎来到 3 33 333 3333 振动论坛 4 44 444 4444 vib.hit.edu.cn 5 55 555 5555 解答: --------------------------------------------转 -------------------------------------- CODE: function [data]=distilldata(infile) %功能说明: %将保存数据的原始文件中的数值数据读入到一个data变量中 %使用说明: % infile——原始数据文件名; % data=数据变量 tmpfile='tmp2.mat'; fidin=fopen(infile,'r'); % 打开原始数据文件(.list) fidtmp=fopen(tmpfile,'w'); % 创建保存数据文件(不含说明文字) while ~feof(fidin) % 判断是否为文件末尾 tline=fgetl(fidin); % 从文件读入一行文本(不含回车键) if ~isempty(tline) % 判断是否空行 [m,n]=size(tline); flag=1; for i=1:n %判断一行中有没有字符(+-.Ee和空格键除外) if ~(tline(i)==' '|tline(i)=='-'|tline(i)=='.'|tline(i)=='E'... |tline(i)=='e'|tline(i)=='+'... |(double(tline(i))>=48&&double(tline(i))<=57)) flag=0; break; end end if flag==1 % 如果是数字行,把此行数据写入文件 fprintf(fidtmp,'%s\n',tline); end end end fclose(fidin); fclose(fidtmp); data=textread(tmpfile); delete(tmpfile); --------------------------------------------------------------------------------------------------------- 另外,如果要求不高,也可以使用 textread 函数跳过注释部分进行读取,不过前提是需要事先知道文件内容的结构(即哪行是数据、哪行是注释) 6.各列数据的分离: 源文件: CODE: 0 + 47038.7 1.05 09:26:07 C 2 + 46477.7 1.03 09:28:38 C 4 + 44865.7 1.04 09:28:48 C 6 + 41786.4 1.03 09:28:56 C 8 + 39896.0 0.97 09:29:03 C 10 + 37518.4 0.93 09:29:15 C 12 + 35858.5 0.92 09:29:30 C 14 + 46105.0 1.03 09:30:21 C 16 + 46168.6 6.89 09:30:30 C 18 + 48672.3 4.33 09:30:40 C 20 + 49565.7 0.49 09:30:48 C 22 + 49580.7 0.53 09:30:55 C 24 + 49602.3 0.84 09:31:03 C 26 + 49582.5 1.51 09:31:11 C 28 + 49577.0 1.39 09:31:19 C 30 + 49589.3 0.61 09:31:27 C 32 + 49578.3 1.06 09:31:29 C 34 + 49512.5 1.77 09:31:38 C 解答:直接用 [a,b,c,d,e,f]=textread(yourfilename,'%d %c %f %f %s %c'); 便可 四. 注意事项: 1. 请在 matlab 中保持当前路径在该数据文件对应的目录下进行存取,否则,存取时请给出该数据文件的具体路径。 2. 存取时,请给出该数据文件的全称(包括后缀名,读取mat文件时可省略) 3. load data.txt和A=load(‘data.txt’)的区别请参阅精华贴:[原创]写给学习 matlab 的新手们 4. 请根据读写需要来打开文件,即根据你的需要来指定 fopen 的 permission 属性为读或写。如果只用 a 进行写入,就不能用 fread 读取。此时应该写完关闭文件,然后用 r 打开读取,或者直接用 a+ 进行同时读写操作。否则,会产生莫名其妙的问题!以下代码是一个错误的例子: CODE: filename='e.dat'; fid=fopen(filename,'a'); if fid<0 error('fopen error'); end s=[1 2 3 4;5 6 7 8]; fwrite(fid,s,'float32') [dd ll]=fread(fid,inf,'float32');%把t中的数据全部读出,即s矩阵。 fclose(fid); 此时得到的dd, ll 是错误且无意义的! 五. 其他相关问题: 1. 连续读取多个文件的数据,并存放在一个矩阵中: (1) 首先是如何读取文件名: 方法一: filename=dir(‘*.jpg’); 那么第i个文件的文件名就可以表示为 filename(i).name 文件数量为:length(filename) 方法二: 先在Windows的 MSDOS(命令行)中使用以下命令生成一个list.txt文件: dir path\folder /on /b /s > path\list.txt

举例:dir d:\test /on /b /s > d:\list.txt

然后在 matlab 中使用:

filename = textread(sFileFullName,'%s');

把所有文件名读取到list细胞矩阵中,最后对filename{i}便可得到各文件名。

(2) 然后是读取文件名的数据并存储:
假设每个文件对应的数据是m*n的,则:

CODE:
k = length(filename);

Data = zeros(m,n,k);

for ii = 1:k
Data(:,:,ii) = yourreadstyle(filename{ii}); %yourreadstyle是对应的文件读取方式的函数
end




2. 连续读取多个文件的数据,并存放在多个矩阵(以文件名命名)中:
假设每个文件对应的数据是m*n的,则以上述第二种文件名读取方法为例:

CODE:
k = length(filename);
for ii = 1:k
D = yourreadstyle(filename{ii});
eval([‘Data_’, num2str(ii), ‘ = D;’]);
end



3. 文件名命名问题:
文件名为 abc00001,abc00002,... abc00009,abc00010,... abc00099,abc00100,...abc00879. 准备把这些文件名给放到一个数组里面去。

解答:

CODE:
a=cell(879,1);
for k=1:879
a{k} = sprintf('%.5d',k);
end


4. 上述各种文件格式、类型自动识别问题:可以利用正则表达式来处理,使之通用性较强。例如使用以下代码可以自动处理上面提到了例1到例5各种情形,不过由于存在自动判断,对某些例子(如例1)效率自然要低一点,而对于另外的例子(如例3、例5)效率估计要高一点(少用了一个循环)。


CODE:

function [data]=distilldata_eight(infile)
%功能说明:
%将保存数据的原始文件中的数值数据读入到一个data变量中(自动判断数据行)
%使用说明:
% infile——原始数据文件名;
% data=数据变量

tmpfile='tmp2.mat';

fidin=fopen(infile,'r'); % 打开原始数据文件(.list)

fidtmp=fopen(tmpfile,'w'); % 创建保存数据文件(不含说明文字)

while ~feof(fidin) % 判断是否为文件末尾
tline=fgetl(fidin); % 从文件读入一行文本(不含回车键)
if ~isempty(tline) % 判断是否空行
str = '[^0-9 | \. | \- | \s | e | E]'; %正则表达式为:该行中是否包含除 - . E e 数字 和 空白字符 外的其他字符
start = regexp(tline,str, 'once');
if isempty(start)
fprintf(fidtmp,'%s\n',tline);
end
end
end

fclose(fidin);

fclose(fidtmp);

data=textread(tmpfile);

delete(tmpfile)



5. 大量数据的读取问题:
可以考虑使用循环分批读取(特别是在各数据是独立的时候),或者使用稀疏矩阵来实现(对此可以参阅本版精华贴: [原创]提高matlab运行速度和节省空间的一点心得(之三))。另外,也可参考《深入浅出MATLAB 7_X混合编程》一书第一章

6. 读取整个txt文件的内容(获得文件中的所有字符):

CODE:

f = fopen('yourfilename.txt','rt'); % t 属性根据需要可省略
x = fread(f,'*char');
fclose(f);


7. 把维数不同的矩阵及其变量名保存到一个 txt 文件中,例如 a1 = 123; a2 = [1 2 3;4 5 6] ,希望得到的 txt 文件如下:


QUOTE:

a1:
123
a2:
1 2 3
4 5 6





如果写入的时候简单一点,则可以采用以下方式,不过读取的时候比较麻烦:

CODE:

a1=123;
a2=[1 2 3;4 5 6];
fid = fopen('myfile.txt', 'wt');
for i=1:2
fprintf(fid, '%s: \n %s\n', ['a',int2str(i)], mat2str(eval(['a',int2str(i)])));
end
fclose(fid);


相反,如果写入的时候复杂一点,则读取的时候会简单一点:

CODE:

a1=123;
a2=[1 2 3;4 5 6];
fid = fopen('myfile.txt', 'wt');
for i=1:2
fprintf(fid, '%s: \n', ['a',int2str(i)]);
b = eval(['a',int2str(i)]);
fprintf(fid, [repmat('%d ', 1, size(b,2)), '\n'], b');
end
fclose(fid);

来自: MATLAB中文论坛
http://www.ilovematlab.cn/thread-872-1-1.html

8 Feb 2010

[转] 理解矩阵(一,二,三)

来自CSDN大牛孟岩的<理解矩阵> (一,二,三),写的深入浅出,经典至极,收藏之.
原文请见:
http://blog.csdn.net/myan/archive/2006/04/02/647511.aspx
http://blog.csdn.net/myan/archive/2006/04/03/649018.aspx
http://blog.csdn.net/myan/archive/2007/11/03/1865397.aspx

理解矩阵(一)
线性代数课程,无论你从行列式入手还是直接从矩阵入手,从一开始就充斥着莫名其妙。比如说,在全国一般工科院系教学中应用最广泛的同济线性代数教材(现在到了第四版),一上来就介绍逆序数这个“前无古人,后无来者”的古怪概念,然后用逆序数给出行列式的一个极不直观的定义,接着是一些简直犯傻的行列式性质和习题——把这行乘一个系数加到另一行上,再把那一列减过来,折腾得那叫一个热闹,可就是压根看不出这个东西有嘛用。大多数像我一样资质平庸的学生到这里就有点犯晕:连这是个什么东西都模模糊糊的,就开始钻火圈表演了,这未免太“无厘头”了吧!于是开始有人逃课,更多的人开始抄作业。这下就中招了,因为其后的发展可以用一句峰回路转来形容,紧跟着这个无厘头的行列式的,是一个同样无厘头但是伟大的无以复加的家伙的出场——矩阵来了!多年之后,我才明白,当老师犯傻似地用中括号把一堆傻了吧叽的数括起来,并且不紧不慢地说:“这个东西叫做矩阵”的时候,我的数学生涯掀开了何等悲壮辛酸、惨绝人寰的一幕!自那以后,在几乎所有跟“学问”二字稍微沾点边的东西里,矩阵这个家伙从不缺席。对于我这个没能一次搞定线性代数的笨蛋来说,矩阵老大的不请自来每每搞得我灰头土脸,头破血流。长期以来,我在阅读中一见矩阵,就如同阿Q见到了假洋鬼子,揉揉额角就绕道走。


事实上,我并不是特例。一般工科学生初学线性代数,通常都会感到困难。这种情形在国内外皆然。瑞典数学家Lars Garding在其名著Encounter with Mathematics中说:“如果不熟悉线性代数的概念,要去学习自然科学,现在看来就和文盲差不多。”,然而“按照现行的国际标准,线性代数是通过公理化来表述的,它是第二代数学模型,...,这就带来了教学上的困难。”事实上,当我们开始学习线性代数的时候,不知不觉就进入了“第二代数学模型”的范畴当中,这意味着数学的表述方式和抽象性有了一次全面的进化,对于从小一直在“第一代数学模型”,即以实用为导向的、具体的数学模型中学习的我们来说,在没有并明确告知的情况下进行如此剧烈的paradigm shift,不感到困难才是奇怪的。

大部分工科学生,往往是在学习了一些后继课程,如数值分析、数学规划、矩阵论之后,才逐渐能够理解和熟练运用线性代数。即便如此,不少人即使能够很熟练地以线性代数为工具进行科研和应用工作,但对于很多这门课程的初学者提出的、看上去是很基础的问题却并不清楚。比如说:

* 矩阵究竟是什么东西?向量可以被认为是具有n个相互独立的性质(维度)的对象的表示,矩阵又是什么呢?我们如果认为矩阵是一组列(行)向量组成的新的复合向量的展开式,那么为什么这种展开式具有如此广泛的应用?特别是,为什么偏偏二维的展开式如此有用?如果矩阵中每一个元素又是一个向量,那么我们再展开一次,变成三维的立方阵,是不是更有用?

* 矩阵的乘法规则究竟为什么这样规定?为什么这样一种怪异的乘法规则却能够在实践中发挥如此巨大的功效?很多看上去似乎是完全不相关的问题,最后竟然都归结到矩阵的乘法,这难道不是很奇妙的事情?难道在矩阵乘法那看上去莫名其妙的规则下面,包含着世界的某些本质规律?如果是的话,这些本质规律是什么?

* 行列式究竟是一个什么东西?为什么会有如此怪异的计算规则?行列式与其对应方阵本质上是什么关系?为什么只有方阵才有对应的行列式,而一般矩阵就没有(不要觉得这个问题很蠢,如果必要,针对m x n矩阵定义行列式不是做不到的,之所以不做,是因为没有这个必要,但是为什么没有这个必要)?而且,行列式的计算规则,看上去跟矩阵的任何计算规则都没有直观的联系,为什么又在很多方面决定了矩阵的性质?难道这一切仅是巧合?

* 矩阵为什么可以分块计算?分块计算这件事情看上去是那么随意,为什么竟是可行的?

* 对于矩阵转置运算AT,有(AB)T = BTAT,对于矩阵求逆运算A-1,有(AB)-1 = B-1A-1。两个看上去完全没有什么关系的运算,为什么有着类似的性质?这仅仅是巧合吗?


* 为什么说P-1AP得到的矩阵与A矩阵“相似”?这里的“相似”是什么意思?

* 特征值和特征向量的本质是什么?它们定义就让人很惊讶,因为Ax =λx,一个诺大的矩阵的效应,竟然不过相当于一个小小的数λ,确实有点奇妙。但何至于用“特征”甚至“本征”来界定?它们刻划的究竟是什么?

这样的一类问题,经常让使用线性代数已经很多年的人都感到为难。就好像大人面对小孩子的刨根问底,最后总会迫不得已地说“就这样吧,到此为止”一样,面对这样的问题,很多老手们最后也只能用:“就是这么规定的,你接受并且记住就好”来搪塞。然而,这样的问题如果不能获得回答,线性代数对于我们来说就是一个粗暴的、不讲道理的、莫名其妙的规则集合,我们会感到,自己并不是在学习一门学问,而是被不由分说地“抛到”一个强制的世界中,只是在考试的皮鞭挥舞之下被迫赶路,全然无法领略其中的美妙、和谐与统一。直到多年以后,我们已经发觉这门学问如此的有用,却仍然会非常迷惑:怎么这么凑巧?

我认为,这是我们的线性代数教学中直觉性丧失的后果。上述这些涉及到“如何能”、“怎么会”的问题,仅仅通过纯粹的数学证明来回答,是不能令提问者满意的。比如,如果你通过一般的证明方法论证了矩阵分块运算确实可行,那么这并不能够让提问者的疑惑得到解决。他们真正的困惑是:矩阵分块运算为什么竟然是可行的?究竟只是凑巧,还是说这是由矩阵这种对象的某种本质所必然决定的?如果是后者,那么矩阵的这些本质是什么?只要对上述那些问题稍加考虑,我们就会发现,所有这些问题都不是单纯依靠数学证明所能够解决的。像我们的教科书那样,凡事用数学证明,最后培养出来的学生,只能熟练地使用工具,却欠缺真正意义上的理解。

自从1930年代法国布尔巴基学派兴起以来,数学的公理化、系统性描述已经获得巨大的成功,这使得我们接受的数学教育在严谨性上大大提高。然而数学公理化的一个备受争议的副作用,就是一般数学教育中直觉性的丧失。数学家们似乎认为直觉性与抽象性是矛盾的,因此毫不犹豫地牺牲掉前者。然而包括我本人在内的很多人都对此表示怀疑,我们不认为直觉性与抽象性一定相互矛盾,特别是在数学教育中和数学教材中,帮助学生建立直觉,有助于它们理解那些抽象的概念,进而理解数学的本质。反之,如果一味注重形式上的严格性,学生就好像被迫进行钻火圈表演的小白鼠一样,变成枯燥的规则的奴隶。

对于线性代数的类似上述所提到的一些直觉性的问题,两年多来我断断续续地反复思考了四、五次,为此阅读了好几本国内外线性代数、数值分析、代数和数学通论性书籍,其中像前苏联的名著《数学:它的内容、方法和意义》、龚昇教授的《线性代数五讲》、前面提到的Encounter with Mathematics(《数学概观》)以及Thomas A. Garrity的《数学拾遗》都给我很大的启发。不过即使如此,我对这个主题的认识也经历了好几次自我否定。比如以前思考的一些结论曾经写在自己的blog里,但是现在看来,这些结论基本上都是错误的。因此打算把自己现在的有关理解比较完整地记录下来,一方面是因为我觉得现在的理解比较成熟了,可以拿出来与别人探讨,向别人请教。另一方面,如果以后再有进一步的认识,把现在的理解给推翻了,那现在写的这个snapshot也是很有意义的。

因为打算写得比较多,所以会分几次慢慢写。也不知道是不是有时间慢慢写完整,会不会中断,写着看吧。

--------------------------------------------------------------------------


今天先谈谈对线形空间和矩阵的几个核心概念的理解。这些东西大部分是凭着自己的理解写出来的,基本上不抄书,可能有错误的地方,希望能够被指出。但我希望做到直觉,也就是说能把数学背后说的实质问题说出来。

首先说说空间(space),这个概念是现代数学的命根子之一,从拓扑空间开始,一步步往上加定义,可以形成很多空间。线形空间其实还是比较初级的,如果在里面定义了范数,就成了赋范线性空间。赋范线性空间满足完备性,就成了巴那赫空间;赋范线性空间中定义角度,就有了内积空间,内积空间再满足完备性,就得到希尔伯特空间。

总之,空间有很多种。你要是去看某种空间的数学定义,大致都是“存在一个集合,在这个集合上定义某某概念,然后满足某些性质”,就可以被称为空间。这未免有点奇怪,为什么要用“空间”来称呼一些这样的集合呢?大家将会看到,其实这是很有道理的。

我们一般人最熟悉的空间,毫无疑问就是我们生活在其中的(按照牛顿的绝对时空观)的三维空间,从数学上说,这是一个三维的欧几里德空间,我们先不管那么多,先看看我们熟悉的这样一个空间有些什么最基本的特点。仔细想想我们就会知道,这个三维的空间:1. 由很多(实际上是无穷多个)位置点组成;2. 这些点之间存在相对的关系;3. 可以在空间中定义长度、角度;4. 这个空间可以容纳运动,这里我们所说的运动是从一个点到另一个点的移动(变换),而不是微积分意义上的“连续”性的运动,

上面的这些性质中,最最关键的是第4条。第1、2条只能说是空间的基础,不算是空间特有的性质,凡是讨论数学问题,都得有一个集合,大多数还得在这个集合上定义一些结构(关系),并不是说有了这些就算是空间。而第3条太特殊,其他的空间不需要具备,更不是关键的性质。只有第4条是空间的本质,也就是说,容纳运动是空间的本质特征。

认识到了这些,我们就可以把我们关于三维空间的认识扩展到其他的空间。事实上,不管是什么空间,都必须容纳和支持在其中发生的符合规则的运动(变换)。你会发现,在某种空间中往往会存在一种相对应的变换,比如拓扑空间中有拓扑变换,线性空间中有线性变换,仿射空间中有仿射变换,其实这些变换都只不过是对应空间中允许的运动形式而已。

因此只要知道,“空间”是容纳运动的一个对象集合,而变换则规定了对应空间的运动。


下面我们来看看线性空间。线性空间的定义任何一本书上都有,但是既然我们承认线性空间是个空间,那么有两个最基本的问题必须首先得到解决,那就是:

1. 空间是一个对象集合,线性空间也是空间,所以也是一个对象集合。那么线性空间是什么样的对象的集合?或者说,线性空间中的对象有什么共同点吗?

2. 线性空间中的运动如何表述的?也就是,线性变换是如何表示的?

我们先来回答第一个问题,回答这个问题的时候其实是不用拐弯抹角的,可以直截了当的给出答案。线性空间中的任何一个对象,通过选取基和坐标的办法,都可以表达为向量的形式。通常的向量空间我就不说了,举两个不那么平凡的例子:

L1. 最高次项不大于n次的多项式的全体构成一个线性空间,也就是说,这个线性空间中的每一个对象是一个多项式。如果我们以x0, x1, ..., xn为基,那么任何一个这样的多项式都可以表达为一组n+1维向量,其中的每一个分量ai其实就是多项式中x(i-1)项的系数。值得说明的是,基的选取有多种办法,只要所选取的那一组基线性无关就可以。这要用到后面提到的概念了,所以这里先不说,提一下而已。


L2. 闭区间[a, b]上的n阶连续可微函数的全体,构成一个线性空间。也就是说,这个线性空间的每一个对象是一个连续函数。对于其中任何一个连续函数,根据魏尔斯特拉斯定理,一定可以找到最高次项不大于n的多项式函数,使之与该连续函数的差为0,也就是说,完全相等。这样就把问题归结为L1了。后面就不用再重复了。

所以说,向量是很厉害的,只要你找到合适的基,用向量可以表示线性空间里任何一个对象。这里头大有文章,因为向量表面上只是一列数,但是其实由于它的有序性,所以除了这些数本身携带的信息之外,还可以在每个数的对应位置上携带信息。为什么在程序设计中数组最简单,却又威力无穷呢?根本原因就在于此。这是另一个问题了,这里就不说了。

下面来回答第二个问题,这个问题的回答会涉及到线性代数的一个最根本的问题。

线性空间中的运动,被称为线性变换。也就是说,你从线性空间中的一个点运动到任意的另外一个点,都可以通过一个线性变化来完成。那么,线性变换如何表示呢?很有意思,在线性空间中,当你选定一组基之后,不仅可以用一个向量来描述空间中的任何一个对象,而且可以用矩阵来描述该空间中的任何一个运动(变换)。而使某个对象发生对应运动的方法,就是用代表那个运动的矩阵,乘以代表那个对象的向量。

简而言之,在线性空间中选定基之后,向量刻画对象,矩阵刻画对象的运动,用矩阵与向量的乘法施加运动。

是的,矩阵的本质是运动的描述。如果以后有人问你矩阵是什么,那么你就可以响亮地告诉他,矩阵的本质是运动的描述。(chensh,说你呢!)

可是多么有意思啊,向量本身不是也可以看成是n x 1矩阵吗?这实在是很奇妙,一个空间中的对象和运动竟然可以用相类同的方式表示。能说这是巧合吗?如果是巧合的话,那可真是幸运的巧合!可以说,线性代数中大多数奇妙的性质,均与这个巧合有直接的关系。


理解矩阵(二)
接着理解矩阵。

上一篇里说“矩阵是运动的描述”,到现在为止,好像大家都还没什么意见。但是我相信早晚会有数学系出身的网友来拍板转。因为运动这个概念,在数学和物理里是跟微积分联系在一起的。我们学习微积分的时候,总会有人照本宣科地告诉你,初等数学是研究常量的数学,是研究静态的数学,高等数学是变量的数学,是研究运动的数学。大家口口相传,差不多人人都知道这句话。但是真知道这句话说的是什么意思的人,好像也不多。简而言之,在我们人类的经验里,运动是一个连续过程,从A点到B点,就算走得最快的光,也是需要一个时间来逐点地经过AB之间的路径,这就带来了连续性的概念。而连续这个事情,如果不定义极限的概念,根本就解释不了。古希腊人的数学非常强,但就是缺乏极限观念,所以解释不了运动,被芝诺的那些著名悖论(飞箭不动、飞毛腿阿喀琉斯跑不过乌龟等四个悖论)搞得死去活来。因为这篇文章不是讲微积分的,所以我就不多说了。有兴趣的读者可以去看看齐民友教授写的《重温微积分》。我就是读了这本书开头的部分,才明白“高等数学是研究运动的数学”这句话的道理。


不过在我这个《理解矩阵》的文章里,“运动”的概念不是微积分中的连续性的运动,而是瞬间发生的变化。比如这个时刻在A点,经过一个“运动”,一下子就“跃迁”到了B点,其中不需要经过A点与B点之间的任何一个点。这样的“运动”,或者说“跃迁”,是违反我们日常的经验的。不过了解一点量子物理常识的人,就会立刻指出,量子(例如电子)在不同的能量级轨道上跳跃,就是瞬间发生的,具有这样一种跃迁行为。所以说,自然界中并不是没有这种运动现象,只不过宏观上我们观察不到。但是不管怎么说,“运动”这个词用在这里,还是容易产生歧义的,说得更确切些,应该是“跃迁”。因此这句话可以改成:

“矩阵是线性空间里跃迁的描述”。

可是这样说又太物理,也就是说太具体,而不够数学,也就是说不够抽象。因此我们最后换用一个正牌的数学术语——变换,来描述这个事情。这样一说,大家就应该明白了,所谓变换,其实就是空间里从一个点(元素/对象)到另一个点(元素/对象)的跃迁。比如说,拓扑变换,就是在拓扑空间里从一个点到另一个点的跃迁。再比如说,仿射变换,就是在仿射空间里从一个点到另一个点的跃迁。附带说一下,这个仿射空间跟向量空间是亲兄弟。做计算机图形学的朋友都知道,尽管描述一个三维对象只需要三维向量,但所有的计算机图形学变换矩阵都是4 x 4的。说其原因,很多书上都写着“为了使用中方便”,这在我看来简直就是企图蒙混过关。真正的原因,是因为在计算机图形学里应用的图形变换,实际上是在仿射空间而不是向量空间中进行的。想想看,在向量空间里相一个向量平行移动以后仍是相同的那个向量,而现实世界等长的两个平行线段当然不能被认为同一个东西,所以计算机图形学的生存空间实际上是仿射空间。而仿射变换的矩阵表示根本就是4 x 4的。又扯远了,有兴趣的读者可以去看《计算机图形学——几何工具算法详解》。

一旦我们理解了“变换”这个概念,矩阵的定义就变成:

“矩阵是线性空间里的变换的描述。”

到这里为止,我们终于得到了一个看上去比较数学的定义。不过还要多说几句。教材上一般是这么说的,在一个线性空间V里的一个线性变换T,当选定一组基之后,就可以表示为矩阵。因此我们还要说清楚到底什么是线性变换,什么是基,什么叫选定一组基。线性变换的定义是很简单的,设有一种变换T,使得对于线性空间V中间任何两个不相同的对象x和y,以及任意实数a和b,有:
T(ax + by) = aT(x) + bT(y),
那么就称T为线性变换。


定义都是这么写的,但是光看定义还得不到直觉的理解。线性变换究竟是一种什么样的变换?我们刚才说了,变换是从空间的一个点跃迁到另一个点,而线性变换,就是从一个线性空间V的某一个点跃迁到另一个线性空间W的另一个点的运动。这句话里蕴含着一层意思,就是说一个点不仅可以变换到同一个线性空间中的另一个点,而且可以变换到另一个线性空间中的另一个点去。不管你怎么变,只要变换前后都是线性空间中的对象,这个变换就一定是线性变换,也就一定可以用一个非奇异矩阵来描述。而你用一个非奇异矩阵去描述的一个变换,一定是一个线性变换。有的人可能要问,这里为什么要强调非奇异矩阵?所谓非奇异,只对方阵有意义,那么非方阵的情况怎么样?这个说起来就会比较冗长了,最后要把线性变换作为一种映射,并且讨论其映射性质,以及线性变换的核与像等概念才能彻底讲清楚。我觉得这个不算是重点,如果确实有时间的话,以后写一点。以下我们只探讨最常用、最有用的一种变换,就是在同一个线性空间之内的线性变换。也就是说,下面所说的矩阵,不作说明的话,就是方阵,而且是非奇异方阵。学习一门学问,最重要的是把握主干内容,迅速建立对于这门学问的整体概念,不必一开始就考虑所有的细枝末节和特殊情况,自乱阵脚。

接着往下说,什么是基呢?这个问题在后面还要大讲一番,这里只要把基看成是线性空间里的坐标系就可以了。注意是坐标系,不是坐标值,这两者可是一个“对立矛盾统一体”。这样一来,“选定一组基”就是说在线性空间里选定一个坐标系。就这意思。

好,最后我们把矩阵的定义完善如下:

“矩阵是线性空间中的线性变换的一个描述。在一个线性空间中,只要我们选定一组基,那么对于任何一个线性变换,都能够用一个确定的矩阵来加以描述。”

理解这句话的关键,在于把“线性变换”与“线性变换的一个描述”区别开。一个是那个对象,一个是对那个对象的表述。就好像我们熟悉的面向对象编程中,一个对象可以有多个引用,每个引用可以叫不同的名字,但都是指的同一个对象。如果还不形象,那就干脆来个很俗的类比。

比如有一头猪,你打算给它拍照片,只要你给照相机选定了一个镜头位置,那么就可以给这头猪拍一张照片。这个照片可以看成是这头猪的一个描述,但只是一个片面的的描述,因为换一个镜头位置给这头猪拍照,能得到一张不同的照片,也是这头猪的另一个片面的描述。所有这样照出来的照片都是这同一头猪的描述,但是又都不是这头猪本身。

同样的,对于一个线性变换,只要你选定一组基,那么就可以找到一个矩阵来描述这个线性变换。换一组基,就得到一个不同的矩阵。所有这些矩阵都是这同一个线性变换的描述,但又都不是线性变换本身。


但是这样的话,问题就来了如果你给我两张猪的照片,我怎么知道这两张照片上的是同一头猪呢?同样的,你给我两个矩阵,我怎么知道这两个矩阵是描述的同一个线性变换呢?如果是同一个线性变换的不同的矩阵描述,那就是本家兄弟了,见面不认识,岂不成了笑话。

好在,我们可以找到同一个线性变换的矩阵兄弟们的一个性质,那就是:

若矩阵A与B是同一个线性变换的两个不同的描述(之所以会不同,是因为选定了不同的基,也就是选定了不同的坐标系),则一定能找到一个非奇异矩阵P,使得A、B之间满足这样的关系:

A = P-1BP

线性代数稍微熟一点的读者一下就看出来,这就是相似矩阵的定义。没错,所谓相似矩阵,就是同一个线性变换的不同的描述矩阵。按照这个定义,同一头猪的不同角度的照片也可以成为相似照片。俗了一点,不过能让人明白。

而在上面式子里那个矩阵P,其实就是A矩阵所基于的基与B矩阵所基于的基这两组基之间的一个变换关系。关于这个结论,可以用一种非常直觉的方法来证明(而不是一般教科书上那种形式上的证明),如果有时间的话,我以后在blog里补充这个证明。

这个发现太重要了。原来一族相似矩阵都是同一个线性变换的描述啊!难怪这么重要!工科研究生课程中有矩阵论、矩阵分析等课程,其中讲了各种各样的相似变换,比如什么相似标准型,对角化之类的内容,都要求变换以后得到的那个矩阵与先前的那个矩阵式相似的,为什么这么要求?因为只有这样要求,才能保证变换前后的两个矩阵是描述同一个线性变换的。当然,同一个线性变换的不同矩阵描述,从实际运算性质来看并不是不分好环的。有些描述矩阵就比其他的矩阵性质好得多。这很容易理解,同一头猪的照片也有美丑之分嘛。所以矩阵的相似变换可以把一个比较丑的矩阵变成一个比较美的矩阵,而保证这两个矩阵都是描述了同一个线性变换。


这样一来,矩阵作为线性变换描述的一面,基本上说清楚了。但是,事情没有那么简单,或者说,线性代数还有比这更奇妙的性质,那就是,矩阵不仅可以作为线性变换的描述,而且可以作为一组基的描述。而作为变换的矩阵,不但可以把线性空间中的一个点给变换到另一个点去,而且也能够把线性空间中的一个坐标系(基)表换到另一个坐标系(基)去。而且,变换点与变换坐标系,具有异曲同工的效果。线性代数里最有趣的奥妙,就蕴含在其中。理解了这些内容,线性代数里很多定理和规则会变得更加清晰、直觉。

理解矩阵(三)

  这两篇文章发表于去年的4月。在第二部分结束的时候,我说:
      
矩阵不仅可以作为线性变换的描述,而且可以作为一组基的描述。而 作为变换的矩阵,不但可以把线性空间中的一个点给变换到另一个点去,而且也能够把线性空间中的一个坐标系(基)表换到另一个坐标系(基)去。而且,变换点 与变换坐标系,具有异曲同工的效果。线性代数里最有趣的奥妙,就蕴含在其中。理解了这些内容,线性代数里很多定理和规则会变得更加清晰、直觉。

这个留在下一篇再写吧。

因为有别的事情要做,下一篇可能要过几天再写了。 ”

然而这一拖就是一年半。一年半以来,这两篇粗糙放肆的文章被到处转载,以至于在Google的搜索提示中,我的名字跟“矩阵”是一对关联词汇。这对于学生时代数学一直很差的我来说,实在是令人惶恐的事情。数学是何等辉煌精致的学问!代表着人类智慧的最高成就,是人与上帝对话的语言。而我实在连数学的门都还没进去,不要说谈什么理解,就是稍微难一些的题目我也很少能解开。我有什么资格去谈矩阵这样重要的一个数学概念呢?更何况,我的想法直观是直观,未见的是正确的啊,会不会误人子弟呢?因此,算了吧,到此为止吧,我这么想。


        是时不时收到的来信逐渐改变了我的想法。

        一年半以来,我收到过不下一百封直接的来信,要求我把后面的部分写出来。这些来信大部分是国内的网友和学生,也有少数来自正在国外深造的朋友,大部分是鼓励,有的是诚挚的请求,也有少数严厉斥责我不守承诺。不管是何种态度,这都表明他们对我这一点点小小的思考成果的鼓励,特别是对于我这种思维的视角和尝试的鼓励。他们在信中让我知道,尽管我的数学水平不高,但是我这种从普通人(而不是数学家)视角出发,强调对数学概念和规则的直觉理解的思路,对于很多人是有益的。也许这条路子在数学中绝非正道,也不会走得很远,但是无论如何,在一定的阶段,对一部分人来说,较之目前数学教材普遍采用的思路,这种方式可能更容易理解一些。既然是可能对一部分人有帮助的事情,那么我就不应该心存太多杂念,应该不断思考和总结下去。


       所以,下面就是你们来信要求我写出来的东西。

       首先来总结一下前面两部分的一些主要结论:

1. 首先有空间,空间可以容纳对象运动的。一种空间对应一类对象。
2. 有一种空间叫线性空间,线性空间是容纳向量对象运动的。
3. 运动是瞬时的,因此也被称为变换。
4. 矩阵是线性空间中运动(变换)的描述。
5. 矩阵与向量相乘,就是实施运动(变换)的过程。
6. 同一个变换,在不同的坐标系下表现为不同的矩阵,但是它们的本质是一样的,所以本征值相同。

        下面让我们把视力集中到一点以改变我们以往看待矩阵的方式。我们知道,线性空间里的基本对象是向量,而向量是这么表示的:

        [a1, a2, a3, ..., an]

       矩阵呢?矩阵是这么表示的:

        a11, a12, a13, ..., a1n
        a21, a22, a23, ..., a2n
                     ...
        an1, an2, an3, ..., ann

        不用太聪明,我们就能看出来,矩阵是一组向量组成的。特别的,n维线性空间里的方阵是由n个n维向量组成的。我们在这里只讨论这个n阶的、非奇异的方阵,因为理解它就是理解矩阵的关键,它才是一般情况,而其他矩阵都是意外,都是不得不对付的讨厌状况,大可以放在一边。这里多一句嘴,学习东西要抓住主流,不要纠缠于旁支末节。很可惜我们的教材课本大多数都是把主线埋没在细节中的,搞得大家还没明白怎么回事就先被灌晕了。比如数学分析,明明最要紧的观念是说,一个对象可以表达为无穷多个合理选择的对象的线性和,这个概念是贯穿始终的,也是数学分析的精华。但是课本里自始至终不讲这句话,反正就是让你做吉米多维奇,掌握一大堆解偏题的技巧,记住各种特殊情况,两类间断点,怪异的可微和可积条件(谁还记得柯西条件、迪里赫莱条件...?),最后考试一过,一切忘光光。要我说,还不如反复强调这一个事情,把它深深刻在脑子里,别的东西忘了就忘了,真碰到问题了,再查数学手册嘛,何必因小失大呢?

        言归正传。如果一组向量是彼此线性无关的话,那么它们就可以成为度量这个线性空间的一组基,从而事实上成为一个坐标系体系,其中每一个向量都躺在一根坐标轴上,并且成为那根坐标轴上的基本度量单位(长度1)。

        现在到了关键的一步。看上去矩阵就是由一组向量组成的,而且如果矩阵非奇异的话(我说了,只考虑这种情况),那么组成这个矩阵的那一组向量也就是线性无关的了,也就可以成为度量线性空间的一个坐标系。结论:矩阵描述了一个坐标系。

        “慢着!”,你嚷嚷起来了,“你这个骗子!你不是说过,矩阵就是运动吗?怎么这会矩阵又是坐标系了?”

        嗯,所以我说到了关键的一步。我并没有骗人,之所以矩阵又是运动,又是坐标系,那是因为——

        “运动等价于坐标系变换”。

        对不起,这话其实不准确,我只是想让你印象深刻。准确的说法是:

       “对象的运动等价于坐标系的变换”。

       或者:

       “固定坐标系下一个对象的运动等价于固定对象所处的坐标系变换。”

       说白了就是:

        “运动是相对的。”        

        让我们想想,达成同一个变换的结果,比如把点(1, 1)变到点(2, 3)去,你可以有两种做法。第一,坐标系不动,点动,把(1, 1)点挪到(2, 3)去。第二,点不动,变坐标系,让x轴的度量(单位向量)变成原来的1/2,让y轴的度量(单位向量)变成原先的1/3,这样点还是那个点,可是点的坐标就变成(2, 3)了。方式不同,结果一样。

        从第一个方式来看,那就是我在《理解矩阵》1/2中说的,把矩阵看成是运动描述,矩阵与向量相乘就是使向量(点)运动的过程。在这个方式下,

       Ma = b

       的意思是:

       “向量a经过矩阵M所描述的变换,变成了向量b。”

        而从第二个方式来看,矩阵M描述了一个坐标系,姑且也称之为M。那么:

        Ma = b

       的意思是:

        “有一个向量,它在坐标系M的度量下得到的度量结果向量为a,那么它在坐标系I的度量下,这个向量的度量结果是b。”

        这里的I是指单位矩阵,就是主对角线是1,其他为零的矩阵。

        而这两个方式本质上是等价的。

        我希望你务必理解这一点,因为这是本篇的关键。

        正因为是关键,所以我得再解释一下。

        在M为坐标系的意义下,如果把M放在一个向量a的前面,形成Ma的样式,我们可以认为这是对向量a的一个环境声明。它相当于是说:

        “注意了!这里有一个向量,它在坐标系M中度量,得到的度量结果可以表达为a。可是它在别的坐标系里度量的话,就会得到不同的结果。为了明确,我把M放在前面,让你明白,这是该向量在坐标系M中度量的结果。”

       那么我们再看孤零零的向量b:

       b

       多看几遍,你没看出来吗?它其实不是b,它是:

       Ib

       也就是说:“在单位坐标系,也就是我们通常说的直角坐标系I中,有一个向量,度量的结果是b。”

       而  Ma = Ib的意思就是说:

       “在M坐标系里量出来的向量a,跟在I坐标系里量出来的向量b,其实根本就是一个向量啊!”

       这哪里是什么乘法计算,根本就是身份识别嘛。

       从这个意义上我们重新理解一下向量。向量这个东西客观存在,但是要把它表示出来,就要把它放在一个坐标系中去度量它,然后把度量的结果(向量在各个坐标轴上的投影值)按一定顺序列在一起,就成了我们平时所见的向量表示形式。你选择的坐标系(基)不同,得出来的向量的表示就不同。向量还是那个向量,选择的坐标系不同,其表示方式就不同。因此,按道理来说,每写出一个向量的表示,都应该声明一下这个表示是在哪个坐标系中度量出来的。表示的方式,就是 Ma,也就是说,有一个向量,在M矩阵表示的坐标系中度量出来的结果为a。我们平时说一个向量是[2 3 5 7]T,隐含着是说,这个向量在 I 坐标系中的度量结果是[2 3 5 7]T,因此,这个形式反而是一种简化了的特殊情况。

        注意到,M矩阵表示出来的那个坐标系,由一组基组成,而那组基也是由向量组成的,同样存在这组向量是在哪个坐标系下度量而成的问题。也就是说,表述一个矩阵的一般方法,也应该要指明其所处的基准坐标系。所谓M,其实是 IM,也就是说,M中那组基的度量是在 I 坐标系中得出的。从这个视角来看,M×N也不是什么矩阵乘法了,而是声明了一个在M坐标系中量出的另一个坐标系N,其中M本身是在I坐标系中度量出来的。

       回过头来说变换的问题。我刚才说,“固定坐标系下一个对象的变换等价于固定对象所处的坐标系变换”,那个“固定对象”我们找到了,就是那个向量。但是坐标系的变换呢?我怎么没看见?

       请看:

       Ma = Ib

       我现在要变M为I,怎么变?对了,再前面乘以个M-1,也就是M的逆矩阵。换句话说,你不是有一个坐标系M吗,现在我让它乘以个M-1,变成I,这样一来的话,原来M坐标系中的a在I中一量,就得到b了。

       我建议你此时此刻拿起纸笔,画画图,求得对这件事情的理解。比如,你画一个坐标系,x轴上的衡量单位是2,y轴上的衡量单位是3,在这样一个坐标系里,坐标为(1,1)的那一点,实际上就是笛卡尔坐标系里的点(2, 3)。而让它原形毕露的办法,就是把原来那个坐标系:

       2 0
       0 3

       的x方向度量缩小为原来的1/2,而y方向度量缩小为原来的1/3,这样一来坐标系就变成单位坐标系I了。保持点不变,那个向量现在就变成了(2, 3)了。

       怎么能够让“x方向度量缩小为原来的1/2,而y方向度量缩小为原来的1/3”呢?就是让原坐标系:

      2 0
      0 3

       被矩阵:

       1/2   0
         0   1/3

       左乘。而这个矩阵就是原矩阵的逆矩阵。

       下面我们得出一个重要的结论:

        “对坐标系施加变换的方法,就是让表示那个坐标系的矩阵与表示那个变化的矩阵相乘。”

        再一次的,矩阵的乘法变成了运动的施加。只不过,被施加运动的不再是向量,而是另一个坐标系。

        如果你觉得你还搞得清楚,请再想一下刚才已经提到的结论,矩阵MxN,一方面表明坐标系N在运动M下的变换结果,另一方面,把M当成N的前缀,当成N的环境描述,那么就是说,在M坐标系度量下,有另一个坐标系N。这个坐标系N如果放在I坐标系中度量,其结果为坐标系MxN。

        在这里,我实际上已经回答了一般人在学习线性代数是最困惑的一个问题,那就是为什么矩阵的乘法要规定成这样。简单地说,是因为:

        1. 从变换的观点看,对坐标系N施加M变换,就是把组成坐标系N的每一个向量施加M变换。

        2. 从坐标系的观点看,在M坐标系中表现为N的另一个坐标系,这也归结为,对N坐标系基的每一个向量,把它在I坐标系中的坐标找出来,然后汇成一个新的矩阵。

        3. 至于矩阵乘以向量为什么要那样规定,那是因为一个在M中度量为a的向量,如果想要恢复在I中的真像,就必须分别与M中的每一个向量进行內积运算。我把这个结论的推导留给感兴趣的朋友吧。应该说,其实到了这一步,已经很容易了。

        综合以上1/2/3,矩阵的乘法就得那么规定,一切有根有据,绝不是哪个神经病胡思乱想出来的。
 
        我已经无法说得更多了。矩阵又是坐标系,又是变换。到底是坐标系,还是变换,已经说不清楚了,运动与实体在这里统一了,物质与意识的界限已经消失了,一切归于无法言说,无法定义了。道可道,非常道,名可名,非常名。矩阵是在是不可道之道,不可名之名的东西。到了这个时候,我们不得不承认,我们伟大的线性代数课本上说的矩阵定义,是无比正确的:

        “矩阵就是由m行n列数放在一起组成的数学对象。”

        好了,这基本上就是我想说的全部了。还留下一个行列式的问题。矩阵M的行列式实际上是组成M的各个向量按照平行四边形法则搭成一个n维立方体的体积。对于这一点,我只能感叹于其精妙,却无法揭开其中奥秘了。也许我掌握的数学工具不够,我希望有人能够给我们大家讲解其中的道理了。

        我不知道是否讲得足够清楚了,反正这一部分需要您花些功夫去推敲。

        此外,请大家不必等待这个系列的后续部分。以我的工作情况而言,近期内很难保证继续投入脑力到这个领域中,尽管我仍然对此兴致浓厚。不过如果还有(四)的话,可能是一些站在应用层面的考虑,比如对计算机图形学相关算法的理解。但是我不承诺这些讨论近期内会出现了。

7 Feb 2010

图像处理:腐蚀,膨胀,开运算及闭运算


图像的形态学运算:腐蚀,膨胀,开运算及闭运算

形态学图像处理的基本思想是利用一个称作结构元素的“探针”收集图像的信息.腐蚀,膨胀,开运算及闭运算这些形态学方法可以对图像进行滤波,平滑操作.腐蚀和膨胀可以看作单边滤波器,而开运算和闭运算可以看作双边滤波器.



如果将原图设定为A,探针图像设定为B,则一般情况下B的尺寸远小于A,用B对A进行各种操作.

腐蚀

定义: 设B的原点在左上角,则用B腐蚀A即,B能完全落入A时,B的原点的集合.
作用: 消除A的边界杂点.
例子:
A =
     0     1     1     1     0     0     0     0
     0     0     1     1     1     0     0     0
     0     0     0     1     1     1     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
>> B = strel('square',2)
B =
Flat STREL object containing 4 neighbors.

Neighborhood:
     1     1
     1     1
>> C = imerode(A, B)
C =
     0     0     1     0     0     0     0     0
     0     0     0     1     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
如上显式,能将B完全包容在A中时,B的原点只可能在A(1,3)和A(2,4),在结果C中也只有这2点的值为1,其余均为0.如下图:

>> subplot(1,2,1);imshow(A,'notruesize');
>> subplot(1,2,2);imshow(C,'notruesize')




膨胀

定义: B中有任意点落入A时,B的原点的集合.换句话,B与A交集不为空时B的原点的集合.
作用: 合并图像边缘的背景点到图像中.(图像变粗,变大)
例子: (A,B与上面相同)
>> D = imdilate(A,B)
D =
     0     1     1     1     1     0     0     0
     0     1     1     1     1     1     0     0
     0     0     1     1     1     1     1     0
     0     0     0     1     1     1     1     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
>> subplot(1,2,1);imshow(A,'notruesize');
>> subplot(1,2,2);imshow(D,'notruesize')
结果如下:



开运算

定义: 以相同的算子B对图像A进行先腐蚀后膨胀操作(并不能恢复原图像)
作用: 去掉凸角来平滑图像边缘(可以用来分开相连的区域).
例子:
>> E = imopen(A,B)
E =
     0     0     1     1     0     0     0     0
     0     0     1     1     1     0     0     0
     0     0     0     1     1     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
>> subplot(1,2,1);imshow(A,'notruesize');
>> subplot(1,2,2);imshow(E,'notruesize')
结果如下:



闭运算

定义: 以相同的算子B对图像A进行先膨胀后腐蚀操作.
作用: 填充凹角来平滑图像边缘.
例子:
>> F = imclose(A,B)
F =
     0     1     1     1     0     0     0     0
     0     0     1     1     1     0     0     0
     0     0     0     1     1     1     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0
>> subplot(1,2,1);imshow(A,'notruesize');
>> subplot(1,2,2);imshow(F,'notruesize')
结果如下:




===============================================
可以参考另外2篇类似的介绍文章:
http://www.cnblogs.com/tekson/archive/2009/08/03/1538006.html

http://blog.sina.com.cn/s/blog_4a93ccea0100d25q.html

4 Feb 2010

such as, for example, e.g., i.e., etc., et al.


在英文论文的编辑加工中,常会遇到such as, for example, e. g. , i. e. , etc. 和et al. 的错误及混淆使用。这里,举例分析这几个词的意义,并阐述其正确用法。


1) such as。常列举同类人或事物中的几个例子。

其典型的表示式为a plural + such as + single instance( s) of the group to which the plural refers。

正确使用的是: The Arts Faculty deals only with humanities subjects such as history and literature.

混淆使用的是: The Science Faculty deals only with the measurable such as physics and seismology.

论文中常出现such as与and so on或etc. 连用, 这是不正确的。

① 如 It is noted that the features such as clean cut ratio denoted by Rc , die roll height denoted by Hdr and die roll width denoted by Wdr , and so on (有的出现etc.) , are better than the ones with the other models.

应为 It is noted that the features, such as clean cut ratio denoted by Rc , die roll height denoted by Hdr and die roll width denoted by Wdr , are better than the ones with the other models.

当使用such as时,读者已理解后面接着的会是一些不完整的列举,因此不需加上and so on或 etc. 等。

② 因为such as是对前面的复数名词部分起列举作用,若全部列举出,要改用namely,意思为“即”。文章中出现的He knows four languages, such as Chinese, English, Japanese and German,应将such as改成namely(或i. e. )及后面加逗号, 即He knows four languages, namely, Chinese, English, Japanese and German.

③ 用such as来形容复数名词( the plural)可以放在such与as中间,一般插在被列举事物与前面的名词之间。

2) for example。用来举例说明,由它引出介绍普遍概念的例子,使用范围要比such as自由。可以出现在句首、句末或有时可作为独立语,插在句中,不影响句子其他部分的语法关系。

例如, Cryptography operations, for example, decryption or signing, in a given period only involve the corresponding temporary secret key without further access to the helper.

同样for example ( e. g. )表示泛泛地举几个例子,并没有囊括所有的实例,其中就已经包含“等等”,如果再加etc. 或and so on,就画蛇添足了。

如论文中出现的这句话是不当的:Writing instructors focus on a number of complex skills that require extensive practice (e. g. , organization, clear expression, logical thinking, etc. 正确的为e. g. , organization, clear expression, and logical thinking.

3) e. g.。是拉丁文exempli gratia的缩写,意思是“举个例子,比如”,等同于“for example”,目的是用例子来说明前面的观点,用法与for example相同。

4) i. e.。源于拉丁语,是id est的简略形式。其意思就是“那就是说,换句话说”,等同于“that is, in other words”和“namely”,目的是用来进一步解释前面所说的观点。

正确的用法是Use a comma to enclose ( i. e. , both before and after) the year in a month day year sequence. 而文章中出现的这句The evaluation noted that the employee had frequently exhibited irresponsible behavior ( i. e. , coming to work late, failing to complete projects) ,应该用“e. g. ”而不是用“i. e. ”,因为插入句是对“irresponsible behavior”的列举补充。

5) etc.。是et cetera的缩写,意思是“等等”,相当于“and so on”。可用来列举事物,若要列举人,则需用et al. 或用and others。

e.g. 和 etc. 不能出现在同一句话中,因为 e.g. 是表示泛泛的举几个例子,并没有囊括所有的实例,其中就已经包含“等等”,如果再加一个 etc. 就画蛇添足了,

6) et al.。是拉丁文简写。其一为et alibi (以及其他地方) ,相当于and elsewhere;其二为et alii (以及其他人) ,相当于and others。


matlab的正则表达式


引言.啥是正则表达式?正则表达式是干啥的?
我理解就和我们在word或者其他编辑软件里点的查找、替换的作用是差不多的,不过功能要强大的多,当然使用起来也稍微复杂一些。
书上的定义差不多是这样的:正则表达式就是一个表达式(也是一串字符),它定义了某种字符串模式。利用正则表达式,可以对大段的文字进行复杂的查找、替换等。
matlab提供的正则表达式函数有三个:
regexp——用于对字符串进行查找,大小写敏感;
regexpi——用于对字符串进行查找,大小写不敏感;
regexprep——用于对字符串进行查找并替换。


稍微介绍一下这三个函数,以regexpi为例,也可以先跳过这里,看过正文之后回头再来看看这里。

[start end extents match tokens names] = regexpi('str', 'expr')
start为匹配字符串的起始位置;end为匹配字符串的终止位置;extents为扩展内容,和'tokens'指示符一起用,指示出现tokens的 位置;match即找到的匹配字串;tokens匹配正则表达式中标记(tokens)的字串;names为匹配到的命名标记的标记名。

若不需要所有的输出,可以用下面的方式指定所需输出。
[v1 v2 ...] = regexpi('str', 'expr', 'q1', 'q2', ...)
'q1','q2',...为'start','end','tokens','tokensExtents','match','names'之一,意义与上面的解释一样。v1,v2...的输出顺序与q1,q2...一致。


第一部分——单个字符的匹配
我们先从简单的开始——以regexpi函数为例。假设你要搜索一个包含字符'cat'的字符串,搜索用的正则表达式就是 'cat'。如果搜索对大小写不敏感,单词'catalog'、'Catherine'、'sophisticated'都可以匹配。也就是说:
正则表达式:'cat'
匹配:'cat', 'catalog', 'Catherine','sophisticated'
这个好像和我们通常在记事本里ctrl+F弄出来的东西差不多哈,呵呵。。。(btw:为了方便,下面的叙述中字符串和正则表达式的''都省略不写。)
1 句点符号 '.' ——匹配任意一个(只有一个)字符(包括空格)。
假设你在玩英文拼字游戏,想要找出三个字母的单词,而且这些单词必须以't'字母开头,以'n'字母结束。另外,假设有一本英文字典,你可以用正则表达式 搜索它的全部内容。要构造出这个正则表达式,你可以使用一个通配符——句点符号'.'。这样,完整的表达式就是t.n,它匹配tan、 ten、tin和ton,还匹配t#n、tpn甚至t n,还有其他许多无意义的组合。这是因为句点符号匹配所有字符,包括空格:
小整理:正则表达式:t.n
匹配:ten, tin, ton, t n, tpn, t#n, t@n
Matlab例子程序:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='t.n';
o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串
[o11,o22,o33]=regexpi(str,pat,'start','end','match') %同时输出起始位置和子串
输出为:
o22 =
3 8 13 18 23 28 33 36
o33 =
'ten' 'tin' 'ton' 't n' 'tpn' 't#n' 't@n' 'T&n'
o1 =
1 10 18 23 31 39 48 51
o2 =
3 12 20 25 33 41 50 53
o3 =
'ten' 'tin' 'ton' 't n' 'tpn' 't#n' 't@n' 'T&n'
o11 =
1 10 18 23 31 39 48 51
o22 =
3 12 20 25 33 41 50 53
o33 =
'ten' 'tin' 'ton' 't n' 'tpn' 't#n' 't@n' 'T&n'
2 方括号符号 '[oum]' ——匹配方括号中的任意一个
为了解决句点符号匹配范围过于广泛这一问题,你可以在方括号('[]')里面指定看来有意义的字符。此时,只有方括号里面指定的字符才参与匹配。也就是 说,正则表达式t[aeio]n只匹配tan,Ten,tin和toN等。但'Tmn','taen'不匹配,因为在方括号之内你只能匹配单个字符:
小整理:正则表达式:t[aeio]n
匹配:tan, ten, tin, ton
matlab 例子程序:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='t[aeiou]n';
o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串
[o11,o22,o33]=regexpi(str,pat,'start','end','match') %同时输出起始位置和子串
输出结果为
o1 =
1 10 18
o2 =
3 12 20
o3 =
'ten' 'tin' 'ton'
o11 =
1 10 18
o22 =
3 12 20
o33 =
'ten' 'tin' 'ton'
3 方括号中的连接符 '[c1-c2]' ——匹配从字符c1开始到字符c2结束的字母序列(按字母表中的顺序)中的任意一个。
如[a-c]匹配a,b,c,A,B,C
即:正则表达式:t[a-z]n
匹配:tan, tbn,tcn,tdn,ten,…, txn, tyn,tzn
matlab 例子程序:
clear;clc
str='ten,&8yn2tin6ui>&ton, t n,-356tpn,$$$$t#n,4@).,t@nT&nY';
pat='t[a-z]n';
o1=regexpi(str,pat,'start')%用'start'参数指定输出o1为匹配正则表达式的子串的起始位置
o2=regexpi(str,pat,'end')%用'start'参数指定输出o1为匹配正则表达式的子串的结束位置
o3=regexpi(str,pat,'match')%用'match'参数指定输出o2为匹配正则表达式的子串
[o11,o22,o33]=regexpi(str,pat,'start','end','match') %同时输出起始位置和子串
4 \n 等 ——特殊字符
就是由'\'引导的,代表有特殊意义或不能直接输入的单个字符。在使用printf函数输出时我们常用'\n'来代替回车符,这里也是 同样的道理,用\n在正则表达式中表示回车符。类似的还有\ t横向制表符,'\*'表示'*'等。后一种情况用在查询在正则表达式中有语法作用的字符。详见下文。
下面是一些匹配单个字符的转义字符正则表达式及所匹配的值。
\xN或\x{N} 匹配八进制数值为N的字符
\oN或\o{N} 匹配十六进制数值为N的字符
\a Alarm(beep)
\b Backspace
\t 水平Tab
\n New line
\v 垂直Tab
\f 换页符
\r 回车符
\e Escape
\c 某些在正则表达式中有语法功能或特殊意义的字符c,要用\c来匹配,而不能直接用c匹配,如.用正则表达式\.匹配,而\用正则表达式\\匹配
matlab程序例子
clear;clc
str='l.[a-c]i.$.a';
pat1='.';pat2='\.';
o=regexpi(str,pat1,'match')
o1=regexpi(str,pat2,'match')
输出为:
o =
'l' '.' '[' 'a' '-' 'c' ']' 'i' '.' '$' '.' 'a'
o1 =
'.' '.' '.'
5 \w,\s和\d——类表达式
和上面的\n等表中的转义字符有所不同,\w,\s,\d等匹配的不是某个特定的字符,而是某一类字符。具体说明如下:
\w匹配任意的单个文字字符,相当于[a-zA-Z0-9_];
\s匹配任意的单个空白字符,相当于[\t\f\n\r];
\d匹配任意单个数字,相当于[0-9];
\S匹配除空白符以外的任意单个字符,相当于[^\t\f\n\r]——方括号中的^表示取反;
\W匹配任意单个字符,相当于[^a-zA-Z0-9_];
\D匹配除数字字符外的任意单个字符,相当于[^0-9]。
matlab程序例子,这里引用的是matlab帮助中的例子:
str='easy as 1,2,3';%这个字符串可真有点意思,呵呵
pat='\d';
[o1,o2]=regexpi(str,pat,'start','match')
输出结果为:
o1 =
9 11 13
o2 =
'1' '2' '3'

第二部分串的匹配
1. 多次匹配
比如,我们要匹配'ppp',那么就可以用正则表达式'ppp',还有一种更简单一点的记法'p{3}'。正则表达式中的'{}'用来表示匹配前面的表达 式的出现次数。就是说,'p{2,3}',匹配'pp'和'ppp'。除了'{}',还有几个字符,用在表示单个字符的正则表达式后面表示次数,详见下 表,表中的expr表示第一部分我们讲过的所有表达式。
expr? 与expr匹配的元素出现0或1次,相当于{0,1}
expr* 与expr匹配的元素出现1次或更多,相当于{0,}
expr+ 与expr匹配的元素出现1次或更多,相当于{1,}
expr{n} 与expr匹配的元素出现n次,相当于{n,n}
expr{n,} 与expr匹配的元素至少出现n次
expr{n,m} 与expr匹配的元素出现n次但不多于m次
假设我们要在文本文件中搜索美国的社会安全号码。这个号码的格式是999-99-9999。用来匹配它的正则表达式如图所示。在正则表达式中,连字符 (“-”)有着特殊的意义,它表示一个范围,比如从0到9。因此,匹配社会安全号码中的连字符号时,它的前面要加上一个转义字符“\”。完整的正则表达式 为[0-9]{3}\-[0-9]{2}\-[0-9]{4}
假设进行搜索的时候,你希望连字符号可以出现,也可以不出现——即,999-99-9999和999999999都属于正确的格式。这时,你可以在连字符号后面加上“?”数量限定符号。完整的正则表达式为[0-9]{3}\-?[0-9]{2}\-?[0-9]{4}
下面我们再来看另外一个例子。美国汽车牌照的一种格式是四个数字加上二个字母。它的正则表达式前面是数字部分“[0-9]{4}”,再加上字母部分 “[A-Z]{2}”。完整的正则表达式为[0-9]{4}[A-Z]{2}
另外,当我们使用expr*时,matlab 将尽可能的匹配最长的字符子串。如:
str = 'xyz';
regexp(hstr, '<.*>', 'match')
ans =
''
如果我们希望匹配尽可能短的字符子串时,可以在上面我们使用的字符串后使用'?',也就是expr*?,如:
str = 'xyz';
regexp(hstr, '<.*?>', 'match')
ans =
'' '' '' ''
还有一种是expr*+ ,这种表达式的用法很诡异,没弄懂在什么地方有用。如果哪位大侠有高见,望不吝赐教!
这个表达式的执行过程是这样的,先执行expr*,“游标”(如果有的话)就指到了与expr*匹配的字符子串的最末端,然后从那里开始再检查下一个字符与后面的表达式是否匹配,如果匹配就继续向前(如果一直成功则返回最长的字符串),如果不匹配则直接返回空。例如:
str = 'xyz';
regexp(hstr, '<.*+>', 'match')
ans =
{}
regexp(hstr, '<.*+', 'match') ans = 'xyz'
2. 逻辑运算符
简单的例子比如'exp|exp2',表示或者满足exp或者满足exp2。还有其他一些正则表达式之间的关系如下:
(expr) 将expr标记为一组、匹配expr,并将匹配的字符子串标记起来以供后面使用。——关于这部分内容第三部分(tokens)还会有详细介绍
(?:expr) 说明expr为一组,相当于数学表达式中的()
例如:>>lstr='A body or collection of such stories';
>>regexp(lstr,'(?:[^aeiou][aeiou]){2,}','match')
ans =
'tori'
上面的表达式中{2,}对[^aeiou][aeiou]起作用,如果去掉分组,则只对[aeiou]起作用,如下所示:
>>regexp(lstr,'[^aeiou][aeiou]{2,}','match')
ans =
'tio' 'rie'
(?>expr) expr中的每个元素是一个分组
(?#expr) 这个比较容易理解啦,就是expr放在(?#和)之间是就是注释。如:
>>regexp(lstr, '(?# Match words in caps)[A-Z]\w*', 'match')
ans =
'A'
expr1|expr2 匹配两者之一即可,expr1或者expr2
>>regexp(hstr, '[^aeiou\s]o|[^aeiou\s]i', 'match')
ans =
'bo' 'co' 'ti' 'to' 'ri'
^expr 匹配expr,并且出现在原字符串最前端的子串
expr$ 匹配expr,并且出现在原字符串最末端的子串
>>regexpi(lstr, '^a\w*|\w*s$', 'match')
ans =
'A' 'stories'
\>regexpi(hstr, '\ 匹配expr,并且出现在一个单词最末端的子串
>>regexpi(hstr, '\w*tion\>', 'match')
ans =
'collection'
\ 更严格的单词匹配,如:以s开头,并且以h结尾的单词
>>regexpi(hstr, '\', 'match')
ans =
'such'
3. 左顾右盼——利用上下文匹配
这个也比较容易理解。就是利用上下文的匹配来找到我们要找的内容。
expr1(?=expr2) 找到匹配expr1的子串,如果其后的字符串也匹配expr2
如,下面的例子查找所有在','之前的单词。
>> pstr = ['While I nodded, nearly napping, ' ...
'suddenly there came a tapping,'];
>>regexpi(pstr, '\w*(?=,)', 'match')
ans =
'nodded' 'napping' 'tapping'
expr1(?!expr2) 找到匹配expr1的子串如果其后的字符串不匹配expr2
下面的例子匹配所有不在','之前的单词
>>regexpi(pstr, '\w*(?!=,)', 'match')
ans =
Columns 1 through 6
'While' 'I' 'nodded' 'nearly' 'napping' 'suddenly'
Columns 7 through 10
'there' 'came' 'a' 'tapping'
(?<=expr1)expr2 找到匹配expr2的子串,如果其前面的字符串也匹配expr1 下面的例子查找所有在','之后的单词,注意:','之后可能有空格 >>regexpi(pstr,'(?<=,\s*)\w*','match') ans = 'nearly' 'suddenly' (?>regexpi(pstr,'(?>poestr = ['While I nodded, nearly napping, suddenly there came a tapping,'];
>>[mat tok ext] = regexp(poestr, '(\S)\1', 'match', 'tokens', 'tokenExtents');
>>mat
mat =
'dd' 'pp' 'dd' 'pp'
>>tok{:}
ans =
'd'
ans =
'p'
ans =
'd'
ans =
'p'
>>ext{:}
ans =
11 11
ans =
26 26
ans =
35 35
ans =
57 57
2. 如何使用标记?
(expr) 记录所有匹配表达式的字符,并做为一个标记,以备后面使用
这个例子说明了标记的生成过程:
>>pstr='andy ted bob jim andrew andy ted mark';
>> [t,m]=regexp(pstr,pat,'tokens','match')
t =
{1x1 cell} {1x2 cell} {1x1 cell} {1x1 cell} {1x2 cell}
m =
'andy' 'ted' 'andrew' 'andy' 'ted'
>> t{:}
ans =
'y'
ans =
't' 'd'
ans =
'rew'
ans =
'y'
ans =
't' 'd'
\N 匹配同一条正则表达式里的第N个标记中的字符串。如\1匹配第一个标记;
一个例子,用来查找html语句中类似abc的部分:
>>hstr = 'Default

';
>>expr = '<(\w+).*?>.*?';
>> [mat tok] = regexp(hstr, expr, 'match', 'tokens');
>> mat{:}
ans =

ans =
Default
>> tok{:}
ans =
'tr'
ans =
'table'
$N 在一个替换字符串中插入与第N个标记相匹配的字符串(只用于regexprep函数)
一个例子,将匹配到的第一个token和第二个token的位置互换:
>> regexprep('Norma Jean Baker', '(\w+\s\w+)\s(\w+)', '$2, $1')
ans =
Baker, Norma Jean
(?expr) 记录所有匹配表达式expr的字符,做为一个标记,并设定一个名字name
\k 与名为name的标记相匹配
这个例子和这部分第一个例子是一样的,只不过使用了命名的标记。
>>poestr = ['While I nodded, nearly napping, ' ...
'suddenly there came a tapping,'];
>>regexp(poestr, '(?\S)\k', 'match')
ans =
'dd' 'pp' 'dd' 'pp'
(?(tok)expr) 如果标记tok已经产生,则匹配表达式expr。if-then结构。其中的标记可以是数字标记,也可以是命名标记
(?(tok)expr1|expr2) 如果标记tok已经产生,则匹配表达式expr1,否则匹配表达式expr2。if-then-else结构
这个例子有点意思,是用来检查一个句子中的性别用词是否匹配,表达式的意思就是,如果前面用的是'Mrs'那么后面就匹配 'her',如果前面用的是'Mr'(也就是没有匹配到'Mr'后面的's',则后面匹配'his')。
>>expr = 'Mr(s?)\..*?(?(1)her|his) son';
>>[mat tok] = regexp('Mr. Clark went to see his son', expr, 'match', 'tokens')
mat =
'Mr. Clark went to see his son'
tok =
{1x2 cell}
>>tok{:}
ans =
'' 'his'
如果把句子中的his改成her,则结果如下:
>>[mat tok] = regexp('Mr. Clark went to see her son', expr, 'match', 'tokens')
mat =
{}
tok =
{}
没有与之匹配的结果,呵呵。。。

第四部分多行字符串与多正则表达式
这是最后一部分,也是最容易的一部分了。
1. 多字符串与单个正则表达式匹配
多个字符串存在一个元胞数组里之后,每一个字符串与正则表达式匹配,返回值的维数与元胞数组相同。
>>cstr = { ...
'Whose woods these are I think I know.' ; ...
'His house is in the village though;' ; ...
'He will not see me stopping here' ; ...
'To watch his woods fill up with snow.'};
>>idx = regexp(cstr, '(.)\1');
>>idx{:} ans = % 'Whose woods these are I think I know.'
8 % |8
ans = % 'His house is in the village though;'
23 % |23
ans = % 'He will not see me stopping here'
6 14 23 % |6 |14 |23
ans = % 'To watch his woods fill up with snow.'
15 22 % |15 |22
2. 多个字符串与多个正则表达式匹配
这种情况下,应该满足字符串元胞数组中字符串的个数和正则表达式的个数相等——但维数不一定要相等——如可以用4*1的元胞数组与1*4的正则表达式相匹配。
expr = {'i\s', 'hou', '(.)\1', '\>s = regexprep(cstr, '(.)\1', '--', 'ignorecase')
s =
'Whose w--ds these are I think I know.'
'His house is in the vi--age though;'
'He wi-- not s-- me sto--ing here'
'To watch his w--ds fi-- up with snow.