小松鼠嚇了一跳,有了魔法眼鏡後,這世界看起來完全不一樣了

2012年12月24日 星期一

"視頻魔術"的爭議

最近 YIF 的許多魔術影片,引起了一些爭議。魔術師粘立人也召開了記者會表達了立場(如上面的Youtube)。魔術師羅賓雖然已在 facebook 上發表了對這個事件的看法,但是由於沒有參與記者會,加上相較於之前抵制破解魔術的積極,引起了一些議論。
這中間還牽扯了一堆是關聯的事件:
  1. 王偉忠拿國發基金1800萬元投資假魔術
  2. 美國的 Ellen 脫口秀嘲諷 YIF 的麵包魔術。
  3. 某魔術愛好者用變音的方式說劉謙, David Copperfield, Cyril 等知名魔術師也有用點視頻技巧。
用變聲的方式本質上就是不敢為自己的說法背書,就是黑函,動機可議,基本上可以不用理他。不過這篇文章本來就是要說明這個議題的,所以還是簡單說明一下,那就是用一點鏡頭技巧跟用很多影片後製是完全不一樣的事。
的確有很多電視魔術利用鏡頭的限制和剪接當成原理。但是鏡頭的限制是你本來就知道的事情。我舉個例子:
這個影片有很多地方用到了鏡頭的限制,但即使後來讓你知道他有在鏡頭後面做手腳,你還是會覺得很神奇。為什麼會這樣? 因為重點是即使去掉鏡頭的限制,你還是會覺得驚奇。
有一些魔術很巧妙的利用鏡頭,去掉鏡頭後神奇感會消失很多,不過你還是會讚嘆他巧妙地運用視角。這樣還稱得上合格,畢竟你本來知道攝影機有視角的限制。這有點像是敘述性詭計。只是魔術不像推理小說那樣有揭密過程。
剪接就比較灰色,特別是不按照時序的,已經背叛了觀眾的信任。很多魔術師也不喜歡 PSW,也有點這個意思。但每個魔術師接受的程度不同。
總之,是否會讓人覺得神奇就是魔術的判準(至於怎樣才算神奇,就屬於常識的範疇了,雖然 "There is only one problem with common sense; it's not very common." – Milt Bryce )。
上面的問題是很多人討論這個事件的重點,但我覺得實在太無聊了,所以我其實覺得稍微比較有趣是其他幾個點:
  1. 是否會劣幣驅逐良幣
  2. 是否濫用國發基金
首先 1 的問題,先決條件是 YIF 真的用後製。從麵包的魔術以及一些新聞看來,我覺得是有用後製(>80%),除非王偉忠集團有用黑暗兵法,但從以往的表現來看,他們不太可能這麼冰雪聰明。
後製魔術影片是否會驅逐"真正的魔術"?我覺得不會,我對於人類的好奇心相當有信心。
假使我錯了,真的如王偉忠所說的,跟不上潮流,大家都比較喜歡後製的魔術影片,那也無妨,就讓傳統魔術就像傳統戲曲一樣,從大眾轉向小眾,電影、電視劇變成大家主流的戲劇。
 不過我認為他的機會渺茫就是了。所以我基本上同意羅賓的觀點。但粘立人開記者會讓更多人了解這件事情我也是樂觀其成。
至於 2 跟 1 有關。假如真的後製魔術變成了新的魔術,那真的就如王偉忠說的達成目的了。 Ellen 也會從說笑變成被笑。
就算後製魔術影片沒有變成新魔術,而觀眾能夠接受用假影片打響知名度的方式,那也 OK。只是我不會是他的觀眾群。


光是上面這些東西,我不會打一篇文章的。我真正在意的是下面這件事情。在揭穿、踢爆 YIF 的同時,新聞上常常出現類似下面這樣一段話:

YIF隔空從手中抓出法國麵包、玫瑰、寶特瓶,以及從餐廳目錄中抓出飲料的影片,根本是「無中生有」,是以剪接方式操弄的「假魔術」,現實不可能完成。
也許是魔術師氣憤下無意說出,也許是新聞誤傳,但總之這段話強調了某些現象連魔術都不可能辦到。
魔術師無所謂不可能,雖然只是漫畫上說的,但我認為傳達了魔術最寶貴的價值。
魔術吸引人的地方就是神奇,就是製造可能性,就是讓人產生希望。
以前大學時去過兒童癌症病房變魔術給小朋友看,雖然那時候功力實在太差,但我覺得這是我學魔術最有價值的事情之一。
所以我覺得傳達出魔術辦不到的,所以一定是後製,有點違背了魔術師傳達希望的天職。
Las Vegas有一集是探員詢問 Lace Burton,想知道  Criss Angel 是怎麼讓人漂浮的, Lance Burton 先說用很細的線,探員堅持說沒有,然後 Lance Burton 告訴他, 那他是真的,真的讓那個女人飄浮起來了。
我覺得是挺好的答案。


最後補充一件事情,是其實有點擔心黑暗兵法,所以先打個消毒針(從我阿公、外公和我爸來看,我大概會有點遺傳性恐慌症,我大概也是陰謀論妄想症的高危險群)。
 YIF 的法國麵包魔術,是可能不用後製辦到的,至少可以達到極為類似的效果。
雖然事前就挖坑的可能性不大,但現在被逼急了,出這招然後現場表演的可能性也不是沒有。這樣對台灣魔術圈的影響就可怕了。
所以我先消毒一下,即使之後真的可以現場表演,也不代表當時影片不是後製的。如果真的沒有後製,應該第一時間就明說,不該挖坑讓人跳。

20121226 更新相關連結:
粘立人: 本人對於YIF個人沒有仇恨
羅賓: 大家姑且一看--再談「熱門話題」

20121227 更新:你會發現上面粘立人的 FB 連結失效了,也許是 YIF 粉絲,也許是惡意註冊大量帳號檢舉攻擊造成的。當然基於陰謀論者的天職,不排除自導自演的可能性,不過我覺得可能性很低。 我相當厭惡惡意檢舉的做法,特別是如果是雇工讀生惡意攻擊,這可能花的是我們的納稅錢。 可惜這種事情常常不會有實際證據。
(附帶一提,同樣的標準也適用於之前據說很多人檢舉行政院腦殘廣告詐騙的事情,不過這多多少少跟事實沾上邊,也因此至少有一點點好玩,而且是自發性的。)
更新:
粘立人帳號已回復

2012年12月23日 星期日

關於 checkio.org

checkio.org 是一個基於用寫程式來玩遊戲的網站,使用的語言是 python。剛開始,看起來就是一個有故事的 online judge 而已,只是加上一些類似遊戲的等級、成就的系統。
不過繼續玩下去,似乎會有一些變化、互動的題目(我只試了一下,所以還沒有真的碰到)。
但我的重點不是在介紹這個網站。
先介紹一個取巧的方式。一般來說,程式的題目會有點像是,下面這樣
# Withdraw without any incident 
# 120 - 10 - 0.5 - 1% = floor(109.4) = 109
# 109 - 20 - 0.5 - 1% = floor(88.3) = 88
# 88 - 30 - 0.5 - 1% = floor(57.2) = 57
from math import floor
def checkio(data):
    balance, withdrawal = data
    for a in (0.5+1.01*x for x in withdrawal if x%5==0):    
        balance = floor(balance-a) if balance >= a else balance            
    return balance

if __name__ == '__main__':
    assert checkio([120, [10 , 20, 30]]) == 57, 'First'

    # With one Insufficient Funds, and then withdraw 10 $
    assert checkio([120, [200 , 10]]) == 109, 'Second'

    #with one incorrect amount
    assert checkio([120, [3, 10]]) == 109, 'Third'

    assert checkio([120, [200, 119]]) == 120 , 'Fourth'

    assert checkio([120, [120, 10, 122, 2, 10, 10, 30, 1]]) == 56, "It's mixed all base tests"
    
    print('All Ok')

他會給你一個題目說明,你要寫個 checkio 函數來符合要求,除了上面給一些參考範例外,另外會用一堆資料來測試你的 checkio 函數。上面的程式碼是第一題 ATM 以及我的解答(雖然其實可以有公式解,但是花時間算公式沒意義)。
看出程式碼的問題了嗎?他讓你的 checkio 傳回一個東西來和標準答案比較。問題在於 python 有 operator overloading。所以下面這個寫法也可以通過。
class X(object):
    def __eq__(self,n):
        return True
    def __ne__(self,n):
        return False
def checkio(x):
    return X()

當然這很明顯是個作弊招數。之所以要 __ne__ 也 overload 的原因是,checkio 測試的程式碼其實和範例給的測試方式不同。而且實際上,上面這個作法只在少數的題目有效(ATM 有效,另外還有幾題也有效)。
原因是 checkio 檢查答案的方式有好幾種。有亂數或者固定測試,有類似範例但是用 != 的測試,也有用 json 傳回結果的測試。另外還有遊戲化的互動測試(僅供參考
,我不保證真實性)。
所以這只是一個有趣的小插曲,也不是我的重點。重點是, checkio 這個網站引起我的一些想法。
其中一個我覺得挺有趣的,是寫一個 python 的密室脫逃遊戲。什麼意思呢?可以把 restricted python shell 看成一個密室。有點像是古時候 python 的 rexec 或者 plone 等也有東西。總之,就是讓使用者在一個很有限制的 python 環境。熟悉 python 的人一定會說等等,rexec 不是因為有缺陷,所以被廢止移除了嗎?沒有錯,就是因為 python 太動態、靈活了,所以很多看起來限制重重的情形,其實都是逃脫的。當然我不是說一定沒辦法弄出完全安全 python 的限制環境,只是說當限制重重時,可以 python 玩家試著使用平常沒有發現的新玩法。
所以想像這樣,打開你的 idle ,然後 import puzzle, 會看到一段說明你被關在看似空無一物的 python 環境。然後你利用有限資源和  python 技巧逃出了這個 shell,卻又進入另外一個。然後你某些提示,解出一些問題,得到了 sin, cos, 以及 floor 函數,又利用這幾個函數,解決了令一個謎題,獲得了更多 module。
這樣想想,還挺有趣的。有點像是古時候的冒險類型遊戲,還要用文字輸入 open door 之類的指令,只不過現在你要用的語言是 python 而不是英文。
不過構思還不算完整,比方是否要有圖形?純 python 還是有一些謎題?
突然想到 checkio 本身不就是一個 restricted python 環境嗎,不如直接試試看手感,應該能更容易構思。於是上去試試看。結果發現可以奪回完整的 python 就算了,竟然還可以拿到 shell。這樣算是安全問題,所以就回報了 checkio。
目前感覺這個密室脫逃遊戲的構想是挺可行的。

更新:
checkio 方面有回應,有意更正安全漏洞。

2012年12月20日 星期四

Youtube 以及音樂版權

可能有人會發現我上一篇部落格文章(視覺衝擊:立法院法案審查 + gource)的 Youtbe 影片無法觀看,原因是被一個叫做 Pirames International Srl 的第三方宣稱使用了他們的音樂。詳細情形如下。
我想幫我的影片增加配樂,所以用了 GarageBand 隨便弄了一個配樂。因為我對配樂的要求差不多只是"不要沒有聲音"而已,不是一定要創作個什麼偉大作品。
所以拿 GarageBand 隨興把 loop 拉一拉,簡單的把 loop 排列組合一下,不用多久就收工搞定。
GarageBand 中的 loops 是 Royalty-free 的,簡單的說,就是除非你把這些 loops 原封不動單獨轉賣外,是可以自由當成素材使用,包含商業使用。
當然,如果我是一個有自尊心的專業音樂人,用這些內建的素材可能會自覺不夠專業。但我不是,我只是"不要沒聲音"而已。
放上 Youtube 後,Youtube 的尖端科技判斷我的配樂跟三個第三方配樂之間有侵權疑慮。
為什麼會有這麼多侵權疑慮呢,大概因為很多和我一樣沒有專業音樂人自尊的人,使用內建的陽春素材。
影片是可以放,但是廣告關不掉。我假定廣告的收入會分給這些第三方。雖然說這也沒多少錢,關不掉廣告也不是什麼大事,最重要的,要我嚴肅宣稱這種猴子都會做的音樂是本人原創作品,其實還挺丟臉的,但沒有侵權的事情就是沒有侵權,於是我按照程序申訴。

Youtube 本身並不介入仲裁和判斷,申訴程序只是一個和第三方溝通的管道。
其中 "AdRev for a 3rd Party"在第一次申訴後就撤銷了他的版權侵權指控,想來是碰多了,聽都沒聽就撤回了。"Dance all Day" 則在我第一次申訴後重申他的版權,第二次申訴後撤回她的侵權宣稱。想來也是太多這種案例,所以要確認一下你的意願是否堅決,在撤回。
不過 Pirames International Srl 則堅持不撤回。
對於多次申訴遭拒的申訴者, Youtube會給你一個羞辱性的版權教室,確認你不是一個盜版狂。而且還會強迫你影片下架,給你記一個小過,告訴你六個月內再犯的話,就會把你停權。

 我本來想要再上傳一次另一首我的腦殘創作,然後重蹈覆轍一番,讓 Youtube 將我的帳號停權,藉此凸顯這種制度不合理。但想想 PyConTW 的所有影片還在我的帳號內(因為 pycontw 的 youtube 帳號不能上傳超過十五分鐘的影片),就算了。
所以再次繼續申訴,不過這次申訴比較嚴肅,Youtube 還會警告你要負法律責任。 15 天內,如果 Pirames International Srl 沒有回應,才會重新上架。如果 Pirames International Srl 要告我,可能我就等著收傳票,還要買機票到美國的法院吧。
搜尋一下 Pirames International Srl,你可看到很多人說 Pirames International Srl 常常亂宣稱版權。
當然我絕對不是最扯的受害者。 NASA 的好奇號影片,也在 Youtube 上被宣稱是別家公司的版權物,實際上美國聯邦政府出版品是 public domain 的。根據下面這個 youtube,已經是 Public Domain 的 1913 年的老影片 The Bangville Police,也被認定侵犯七家公司的版權物。


上面的影片上傳者很憤怒自己之前上傳兩次都被下架,然後挖苦說這次我上傳無聲版本,你該不會又要宣稱沒有聲音也侵犯你們的版權吧?
很遺憾的,他可能還是侵犯了 John Cage 作品的版權

客觀而論,我認同 Youtube 的作法大體上是合理,雖然很多細節可能會讓被冤枉者感到憤怒,機器辨識的能力也不夠好。
但以使用者主觀角度來說,會造成我對這家公司的觀感下降,以及增加轉使用其他平台的意願。

2012年12月12日 星期三

視覺衝擊:立法院法案審查 + gource


昨天在 facebook 上看到立法院議程查詢資訊的分享,又在 G+ 上看到某個 project 利用 gource 將 git 歷史視覺化的影片。
由於有點孤陋寡聞,這兩個東西之前都沒注意過。想到如果把兩個東西結合在一起,不知道效果會如何?
因為一些業務軟體及文件的關係,在學校的桌機跑的是 windows,其實經過 windows 升級之後,那些用 ActiveX 行政系統也是得在虛擬機跑,不過有些(舊版的) office 文件還是只能在 windows 下面讀,相當詭異。這些是題外話,總之先抓了 gource 的可執行檔在 windows 跑。
簡單用 python 寫了個隨機生成的檔案餵給 gource,第一個碰到的問題是中文顯示。由於不想改程式碼,上網 google 了一下沒找到解答,不過觀察顯示不出來的中文字的方框數量,猜測其實只是 ttf 裡面的字不夠多, DroidSansFallback 把內附的 FreeSans ttf 檔蓋過去,果然就成功顯示中文了。
接下來想試試看顯示 User 的 Avatar 人頭圖,由於檔名要和 User 的名字一樣,但是 NTFS 檔名應該是用某種 UTF16 的編碼,而 gource 只吃 utf8 檔,所以不改 source 不行。所以切換到 linux 下來跑。
linux 下的檔名就沒有問題了。接下來要抓立法院的議程資料。我用的網址是立法院智庫下的「法律提案審議進度」。
不用砍站,稍微用瀏覽器的網頁開發工具修改一下,就能一次抓到最多 3000 筆資料。我抓了 100年1月到 101 年 11 月中的資料。
再來就是用 python 解析 html。由於 html 裡面有些 tag 其實沒有對稱,所以用很醜的方式,只處理 td tr 和 table,總之是解出資料了。提案人常常會很多,只列其中第一個。
接著需要大頭照。原來是想用 google 找大頭,不過已經有很多熱血的同志先弄好了,可以在零時政府中找到立委人頭 API。雖然網頁上提供的例子,裡面的 MD5 跟我用 python 跑的對不上,但是總之是可以抓得到(如附檔程式)。
最後,再用 Garage Band 隨手弄個背景音樂配上就完工了。


附檔:處理的資料以及抓人頭的範例。
用的參數如下:
gource --user-image-dir image -e 0.1 --camera-mode overview -i 30 -s 20 r2

2012年12月7日 星期五

媒體壟斷不可怕,可怕的是它居然有效

先說些題外話。
標題句型是套用之前說過的「黑函不可怕,可怕的是它居然有效」。這次所謂大學生怒罵質詢教育部長的新聞事件,與之前七朵花事件有些異曲同工之妙,許多人執著於所謂的態度問題。
原因很簡單,因為什麼黑函、鬥爭、媒體壟斷、官商勾結、兩岸問題一堆的太複雜了,很難說清楚誰是誰非,但是有沒有禮貌這種事情,連小孩都懂。就像大海中溺水的人一樣,慌張伸手都撲空,忽然抓住了一塊結實存在的物體,當然會緊抓不放。
這是人類的自然反應。教書時碰到一些英文不好的學生,讀英文書會讀錯、讀不懂意思。仔細詢問之下,原來是遇到一些的生字時,就自動跳過忽略,讀出來的意思當然不對。
這是人之常情,沒有什麼好苛責的,但要小心,溺水時緊裝住東西的本能反應,可能會把想救你的人一起拖下水。
言歸正傳,陳為廷對教育部長有沒有禮貌,那是他們兩人的私事。但整個事件至今,根本就是一場媒體鬧劇。
先從最開始的教育部公文說起,新聞如下:



新聞主播開頭就說
「沒想到教育居然了採取一個不可思議的動作,因為就在同一時間發了一封 email 給 37 所的大專院校,要求學校能夠蒐集提供參與活動的學生名單」
注意,主播不是說傳出、根據 xx 說之類的引述說法,而是直接當成事實在報。實際上根據鄭麗君立委臉書上提供的 email 圖片,內容並沒有要學校蒐集名單。

實際上新聞來源,應該如這則新聞所述,是誤傳(有興趣的人,可以自行前往新聞內容所提的臉書求證)。
當然很多人,包括準備向教育部長興師問罪的立委在內,後來其實都了解教育部並沒有真的要求蒐集學生名冊。但人性就是這樣,因為一開始已經認定教育部犯了不可饒恕的錯,即使後來發現不完全是這樣,但因為態度已經確定,所以自然會轉成認為即使沒有真的明文要求學生名冊,但光是關心就已經是一種暗示,是一種壓力了。

接下來是所謂學生怒罵教長。這個也是一個標題殺人法。
實際上的影片中,學生的態度也許不是每個人都能接受,但也沒有標題講得那麼誇張。


不過如前所述,假設你已經先入為主被媒體標題說服了,即使後來你看到影片不像新聞報導那麼誇張,你也會自己找理由說服自己。
不過媒體鬧劇還沒有結束。接著又出現清大發出道歉聲明的消息(抱歉我用這麼迂迴的文法,因為我沒有真的去找道歉聲明來看)。又出現了清大坦承誤判的新聞,說是
簡禎富坦言當時在國外看到《聯合報》的標題,認為校方應對此事做出回應,才會請秘書室擬稿,聲明是他和校長都看過後發出,但事後觀看陳為廷在教育部的發言完整內容,發現此事造成社會爭議,他會針對此事自請處分。
當然,名嘴們也不會置身事外,可以參考一下這則臉書
 「鄭重澄清」 今天三立新聞台徐國勇先生在新台灣加油節目中,指稱屏東教育大學教官約談助理教授(就是小弟我),質問我為什麼要帶學生去抗議,並要求我交出學生名單,這完全是無中生有的言論。 第一,我並沒有去參與抗議活動,是因為抗議活動的學生中有我的導師班學生,所以我要求學生請事假去抗議,教官曾打電話來問我好幾個學生請事假的原因。 第二,活動結束後,星期五教官室老師來電詢問學生是否都有安全回來學校,並無要我交出學生名單,我也曾詢問學校是否有什麼進一步處理,教官也明確回答就只是了解一下學生安全。 第三,學校目前並無約談任何學生,也無任何要處理學生的動作。 也請媒體朋友們無需加油添醋報導,特此聲明。
看完以上的鬧劇,以後看到媒體報導時,你的態度就應該像我天天跟我一歲半小孩所說的一樣:「慢慢、等等、小心」(還有「好煩、不要吵」)。
惡質媒體之所以可怕,是因為有人相信它。
以前媒體壟斷之所以可怕,是因為沒有能與大眾媒體抗衡的媒體。
但是現在有網路了,不但能方便參考國外消息,查證資料,更讓傳統的口耳相傳升級成能與大眾媒體抗衡。

抗議媒體壟斷當然還是要做的,但更美好的未來是,讓他們即使壟斷大眾媒體了,也沒有效果。



附錄:
糗爆!魔術師凸槌 火燒頭變一團火球
根據一些消息以及魔術師本人說法,其實是主持人惡意攻擊(因為認為魔術師使用巫毒)。
報導內容用詞其實尚稱中性,但是標題應該改成「糗爆,新聞標題將攻擊事件說成是凸槌」。

2012年11月19日 星期一

用 python 解碼實價登錄的地址圖片

早上搭車的時候,在手機上看到了這個 twitter:
我在痞客邦 PIXNET 新增了篇文章:2012年9月實價登錄已經爬完了2012年9月實價登錄資料已經爬完了
聯結提到地址部份還沒有 OCR。
爺爺曾經說過:「如果手邊沒有好用的 OCR 工具,就自己寫一個」。所以我下班後就寫了一個。七拼八湊的,但勉強能跑就是了。
程式碼在 https://sites.google.com/site/xmktjw/Home/files/img2txt.zip&d=1
內含解碼結果。

需要榮尼王的地址原始圖片
Dropbox 22.37M: https://www.dropbox.com/s/4p9ol2xjib6v9zk/images-address-20121117.zip
解開放在 address 目錄。
然後還需要把新細明體 mingliu.ttc 及 ARIALN.TTF 放在 font 目錄下。

個人建議內政部和廠商可以進一步將地址及價格的圖片利用 CAPTCHA 的方式處理,就能簡單防止別人抓資料了。

更新:這不是一個一般性的OCR解法,如 Y. Chao 提到的,有開源的 OCR :tesseract-ocrocropus. 也有現成中文的訓練資料和 python module,不然自己訓練也成。
和本文作法的差異有點像是手排與自排的差異。
不,仔細想想,應該是腳踏車與汽車的差異。
改過的腳踏車可以順便處理價格的圖形,還沒有跟榮尼王的資料比對過。
 https://sites.google.com/site/xmktjw/Home/files/img2txt.zip



需要的 python module 是 numpy, opencv, pygame, pil 。然後用 python 2.7 的 idle 跑即可。
演算法很簡單的就是把新細明體的字體解出來,然後用 opencv 暴力跟實價登錄的圖片地址比對。 阿拉柏數字不曉得是什麼字體,所以先用 ARIALN.TTF粗略的抓到圖片檔中的位置,然後把 bitmap 擷取下來。
pygame 是用來弄出 TTF 字型的 bitmap。PIL 是因為我不曉得怎麼直接把 pygame 的 surface 轉成可用的 numpy array。
freq.txt 是之前中文手寫輸入法蒐集到的常用字表,不過有點壞掉的樣子,所以補了幾個字回去。


# encoding: utf8
import Image
import pygame
import numpy as np
import sys
import os
import cv2.cv as cv
import cv2
import shutil

def normalize(im):    
    im=cv2.cvtColor(im, cv2.CV_32F)
    im=cv2.cvtColor(im, cv.CV_RGB2GRAY)
    im=cv2.equalizeHist(im)
    return im

# load bitmap of a char from TTF
pygame.init()
default_font1= pygame.font.Font("font/mingliu.ttc", 12)
cache={}
internal_digit={}
def get_char(txt, fname=None, size=None):
    if txt.isdigit() and fname==None and size==None:
        return internal_digit[txt]
    if fname==None:
        if txt in cache:
            return cache[txt]
        font= default_font1
    else:
        if size == None:
            size=12
        font = pygame.font.Font(fname, size)    
    t = font.render(txt, False, (255, 255, 255), (0,0,0))
    wh=(t.get_width(), t.get_height())
    t_str=pygame.image.tostring(t, "RGBA")
    rtn=normalize(np.array(Image.fromstring("RGBA", wh, t_str)))
    if fname==None:
        cache[txt]=rtn
    return rtn

# find the bitmap of a charater in an image
def find_match(img, txt, fname=None, size=None):
    template=get_char(txt, fname, size)
    result=cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
    r=result.min()    
    c=np.unravel_index(result.argmin(),result.shape)
    pt2=(c[1]+template.shape[1], c[0]+template.shape[0])
    return r, (c[1],c[0]), pt2

# built internal digit image bitmaps
for i,nums in enumerate([u"41760", u"25",  u"9", u"8", u"3"]):
    im0=normalize(cv2.imread("num%d.png"%(i+1)))
    for c in nums:
        r, pt1, pt2=find_match(im0, c, "font/ARIALN.TTF", 13 if i<3 else 12)
        internal_digit[c]=im0[pt1[1]:pt2[1], pt1[0]:pt2[0]]

# load char table
uchars=u"0123456789~一強沂"+open("freq.txt").read().decode("big5")[3:]
uchars={x:0 for x in uchars if x not in u"\n "}

# decode an image
def decode_img(img):
    h,w=img.shape
    x=0
    rtn=u""
    uitems=list(reversed(sorted([(v,k) for k,v in uchars.items()])))
    while x < w-8:        
        part_img=img[0:h, x:x+14]
        if part_img.max()<0.1:            
            x+=14
            continue
        best_c=None        
        for v,c in uitems:
            r, pt1, pt2=find_match(part_img, c)            
            if  pt1[0]<5 and  4> r:
                rtn+=c
                uchars[c]+=1 
                x+=(pt2[0]-1)
                best_c=c
                break
        if not best_c:
            rtn+="???"            
            break 
    return rtn

# main
cv2.namedWindow("win")
for f in os.listdir("address"):    
    im0=normalize(cv2.imread("address/"+f))
    im1=cv2.cvtColor(im0, cv.CV_GRAY2RGB)
    cv2.imshow("win", im1)
    if cv2.waitKey(10)==27:
        break
    addr=decode_img(im0)    
    print f, addr
    if len(addr)<3 or addr[-3:]=="???":
        shutil.copy("address/"+f, "error/"+f)
cv2.destroyAllWindows()

2012年11月10日 星期六

Diamond Dash 的 Python BOT


Diamond Dash 是 Facebook 以及 iOS 上面常見的社群 Puzzle Game,其實沒有怎麼在玩,所以也只有十幾級而已。玩的時候想起了以前寫的寶石方塊機器人。發現我已經記不太清楚那時候是在什麼平台下面,用什麼語言寫的了。翻了很久硬碟,才找到程式碼。我的收納習慣太糟,如果沒有放在 blog 上,大概就找不到了。 所以改寫了一下,成為 Diamond Dash 版,放在這裡。
功能很簡單,就是抓螢幕的圖,然後用白點在遊戲視窗標出可以消去的方塊。
程式寫得很草率,只是剛好能動。需要 pywin32,只適用於 windows 下的 firefox 。
而且最重要的是,其實對分數沒有什麼幫助。
import win32ui, win32gui, win32con
import time

def find_windows_by_title(title):
    wins=[]
    win32gui.EnumWindows(lambda i,e:e.append(i) ,wins)
    return [w for w in wins if title in win32gui.GetWindowText(w)]

def get_child_windows(w):
    wins=[]    
    try:
        win32gui.EnumChildWindows(w, lambda i,e:e.append(i) ,wins)
    except:
        pass    
    return wins

def find_game_windows():    
    browser_windows=find_windows_by_title("Diamond Dash")    
    child_windows=sum(map(get_child_windows, browser_windows),[])
    cond1=lambda r:(r[2]-r[0],r[3]-r[1])==(760,500)
    cond2=lambda i:win32gui.IsWindowVisible(i)
    cond=lambda i:cond1(win32gui.GetWindowRect(i)) and cond2(i)
    return filter(cond, child_windows)

def get_color(bits):
    return ord(bits[2])|(ord(bits[1])<<8)|(ord(bits[0])<<16)

def do_the_math(m):
    gmap=[[[(j,i)] for i in range(10)] for j in range(9)]    
    for j in range(9):
        for i in range(10):            
            if j>0 and m[j][i]==m[j-1][i]:
                gmap[j-1][i].extend(gmap[j][i])
                gmap[j][i]=gmap[j-1][i]
            if i>0 and m[j][i]==m[j][i-1]:
                gmap[j][i-1].extend(gmap[j][i])
                for j2,i2 in gmap[j][i]:
                    gmap[j2][i2]=gmap[j][i-1]
    for j in range(9):
        for i in range(10):
            gmap[j][i]=len(gmap[j][i])
    return gmap

def main_loop(win):
    dc=win32ui.CreateDCFromHandle(win32gui.GetDC(win))
    mem_dc=dc.CreateCompatibleDC()
    bitmap = win32ui.CreateBitmap()
    # 400 = 40 pixels * 10 diamonds
    # 360 = 40 pixels * 9 diamonds
    bitmap.CreateCompatibleBitmap(dc,400,360)
    mem_dc.SelectObject(bitmap)
    # 160=40 pixels * 4 colors(RGBA).
    # 1600=160 * 10 diamonds
    row=lambda s:[get_color(bits[i:i+3]) for i in range(s,s+1600,160)]
    while 1:
        time.sleep(0.005)
        mem_dc.BitBlt((0, 0), (400, 360), dc, (81+15, 92+15), win32con.SRCCOPY)
        bits = bitmap.GetBitmapBits(True)            
        # 64000 = 1600 * 40 576000=64000 * 9
        matrix=map(row, range(0, 576000, 64000))
        rtn=do_the_math(matrix)
        for j,y in enumerate(range(92,450,40)):
            for i,x in enumerate(range(81,480,40)):
                box=(x+20,y+20,x+30,y+30)
                if rtn[j][i]>=3:
                    dc.FillSolidRect(box, 0xffffff)
                    
wins=find_game_windows()
print "find", wins
if wins:
    main_loop(wins[-1]) # Using the last window works for me.
else:
    print "Unable to find games."

2012年11月7日 星期三

GeoGebra 開箱

在臉書上看到蔡炎龍老師利用 GeoGebra 做出的這個圖片。題目看起來還挺有趣的,所以就想了一下。第一個想法是用複數,在白板上面稍微算了一下果然可行。但直覺這種東西應該有幾何上的意義,所以盯著這個圖片看了一陣子,總算看出了圖形化的證明。
但一來憑空想像的圖形有時會出錯,二來要怎麼把這個解法貼出?
於是,我想不妨試看看這個蔡老師推廣的 GeoGebra 好了。
第一步當然是先用 google 找到 GeoGebra 網站,發現是 Java 軟體,點一下然後等一下就能打開。稍微摸索一下,就上手畫出跟上面一樣的圖形。這也多虧有上面的圖當範本,讓我知道 GeoGebra 能畫出這樣的圖形,才能往正確的方向嘗試,幾乎可以說是打開就會用了。
接著就要做圖形化的證明。傳統的方式,我們會用輔助線的方式來做圖形證明。像是過某點作與某線段平行的直線之類的,然後再說新作出來多邊形和原來的哪個全等。
GeoGebra 也能做同樣的事,不過還有更好的做法。與其弄一堆平行的輔助線,我把原來的圖形繞著一個點旋轉 180 度,這樣平行以及全等就是自然而然的事情了。
準備儲存圖片時,發現可以輸出 GIF 動畫。心想這樣更好,但是找不到動畫時間軸的要怎麼弄,所以便宜行事 Google 了一下,了解 slider 的用法。
最後的結果如下:

由這個動畫,可以很清楚的了解兩個正方形中心相連的那個線段的幾何意義,當然也就清楚知道為什麼會垂直了。
也由於是 Java,什麼平台都能跑,拿來畫畫圖看起來還挺方便的。

2012年11月1日 星期四

Win8 安裝 (x32升x64 無 DVD/USB)與心得


在 preview 及 RTM 版本時,已經在 VirtualBox 上裝過了 Win8。因為主力筆電換了台 MBA,所以這次就放心地將之前的筆電來實機灌正式版 Win8 Pro。
不過問題是我原本的 Win7 是 32bit。原因也是當初選擇直接升級 Win7,所以只能 x32 升 x32。這次反正重要資料大多已經轉移了,就放心地完整升級 x64 版本。
先用一台 Win7 64 版的 PC 購買及下載了 Win8 x64 的 DVD ISO,接著,就發現糟糕了。
手邊沒有空白 DVD,也沒有 USB 隨身碟。實際上就算有空白DVD 也沒用,筆電的 DVD driver 已經拆下了。
直接用虛擬光碟跑 setup 是不行的,因為 x32 的 win7 根本不讓你跑 x64 的 setup。
靈機一動,想到手機裡有 Micro SD,然後剛好有轉接卡,所以就 bootsect /nt60 f: /force 之後,將 Win8 DVD 的檔案放到 SD 卡內。沒想到我的 LifeBook T4215 無法用 SD 開機。
如果能將 Android 手機當成外接硬碟開機也不錯,不過似乎也找不到簡單的現成解法。
隨便借個隨身碟也行,但是不知哪根筋不對,就是突然很執著想不用隨身碟來安裝。
所以決定用 grub 或者 windows 的 boot menu 來啟動光碟。 先嘗試用 boot menu,所以抓了 EasyBCD 來弄。果然順利啟動了光碟,但是會卡在找不到驅動程式。後來在安裝過程中的 X: 磁碟機,試了一些目錄讓他找驅動程式,結果搜尋了半天卡住了,只好重開機。
其實即使找到驅動程式也不是很放心,因為照理來說是不會發生這種問題的,所以很可能是 EasyBCD 沒有完全處理好光碟的模擬。 所以改使用 unetbootin。 用 unetbootin 將 ISO 安裝成從 C: 啟動,結果更慘,無法啟動光碟。 本來已經放棄了,重開機想確認一下還能回到 win7,結果不小心按錯,換成使用 EasyBCD 來啟動 ISO,結果這次居然順利啟動了安裝光碟,然後順利完成安裝。
想來是找來 ubootin, EasyBCD 也會怕競爭,終於肯認真工作的緣故。
回想起來,後來就再也沒機會完成原本想重新啟動進 win7 的動作了,因為 win7 很快就被我刪除了。 不禁感到一股淡淡的哀傷。

win8 的使用邏輯和之前有點不同。對於沒有多點觸控螢幕的電腦來說,鍵盤快捷鍵的使用機會大增。
比方大多數人第一個會注意到的,就是開始功能表不見了,所以會讓人有不知從何開始的感覺。實際上取代開始功能表的是在 Metro 桌面按 Windows+Q 的快捷鍵或者直接打字。跑出來像是上面的東西,然後你在搜尋框中,可以打程式名稱來搜尋。
過去的 Alt-F4, Alt-Tab 及 Ctrl-Alt-Del 都可用,外加 Windows+C,Z,Q,Tab,I,K,F,G 一堆新的。Screenshot 用 Windows+Scr。

第二個注意到的,可能是 Chrome 或者 Firefox 不見了。不過其實大多數使用者可能因為用得太習慣,忘記 Chrome 和 Firefox 本來就是另外抓的。裡面的 IE 一樣保有上網抓 Chrome 和 Firefox 的功能。商店裡面也能抓到 Google Search。不過 IE10 其實看起來還不差就是了。
IE10 有兩種介面,Metro UI 和傳統 windows UI。 就像是當年 Win 3.x 那種 GUI 配上 DOS 模式的感覺,  Win8 也是 Metro UI 背後配上 Win7 模式。可以靠 Windows 鍵跳回 Metro 磚頭頁,也可以用 Windows+D 跳到傳統桌面。
兩種雖然都是 GUI,但是使用上的感覺並不一致。比方我的 T4215 是 Tablet PC,所以有隻觸控筆。在傳統 UI 下,可以使用觸控筆的手勢拉網頁。但是在 Metro UI 下卻不行。
Metro App 的使用邏輯還沒有完全統一。有的時候搜尋可以用 Windows+Q 或直接打字(有時兩者皆可,有時則只有 Windows+Q),有時則是滑鼠右鍵或 Windows-Z 叫出選單(像是地圖)。
優點也有一些。Live 帳號的整合度不錯,遊戲方面還能與 Xbox live 整合,雖然有時要回確認馬有點麻煩。檔案複製時的資訊非常完整,中文手寫輸入法很不錯。硬碟重組感覺很快。商店內也有些不錯的免費軟體,比方 Onenote 就是免費的。

2012年10月27日 星期六

Macbook Air 11" 2012 使用心得

查看今年在 coscup 的  irc log,發現我的旗艦筆電慘遭嘲笑:
11:38 < *******> [R1] 講者故意帶了很慢的電腦來展示
憤而決定更換新機。
開玩笑的,真正的原因是我常常上課或演講帶著筆電跑來跑去,雖然我連拿著磚塊般的 Xoom 都舉重若輕, 但因為加上電線、書本一堆的,常常還是覺得有點狼狽,所以就打算使用輕薄一點的機型。速度倒不是主要考慮的因素。雖然可能的選項還挺多的,但總之,最後選到了 Macbook Air 11" 2012 128G SSD 這款。
記得我的上一台蘋果電腦,是.......沒有。小學時家裡放了一台舅舅借的 Apple II 相容機。不過那時我還不會寫程式。後來學寫程式也是從 Apple II 的 basic 開始,但那時自己沒有機器,都是借用學校的。後來為了想拿麥金塔當獎品,參加蘋果的電腦繪圖比賽,最後拿到兒童組亞軍,只拿到一本「蘋果戰爭」的書。後來用 executor, pearpc, virtualbox 等模擬器跑過一些蘋果的作業系統,但沒有真的在用。所以我對 osx 完全不熟。
所以,以新手的角度,簡單的描述一下心得讓有類似需求的人參考。


  1. 效能方面,配備有 1.7ghz 雙核心 core i5,GPU 是內建的 HD4000。記憶體我升級到 8G, cpu 雖然也有升級的選項, 但我認為 core i5 已經足夠。實際上使用的心得也是如此。效能方面大致上符合需求。
  2. 重量 1.08 公斤。雖然比 Xoom 還重,但也許是外型扁平(空氣浮力?),也許是心理因素,拿起來並不感覺特別重。總之,比之前的筆電好攜帶多了。機器可以放入我為了 Kindle 買的套子。事實上,我常常將 Kindle 加上 MBA一起放入平板套中攜帶,有時還將手機一起塞進去。
  3. 續航力是比較不滿意的地方,不過這是購買前已經了解到的事情。待機之類的耗電不多,開機很快,所以不用的時候,關機即可。但問題是持續使用的情形下,使用時間比平板要短一些。兩三個小時的使用不成問題,但時間久一點(比方一整天),跑的東西多一點,就會有點擔心電力的問題。雖然不見得真的會沒電,但因為這個擔心,可能會讓你考慮要多帶個充電器。
  4. 螢幕雖小,但解析度還可以,所以其實使用上問題不大。我有實際試過在搭乘客運時 coding,的確可以工作。不過有老花眼之後,可能就不行了。
  5. 找不到怎麼改字體大小,除了改解析度的方式外。
  6. OS X 的使用一開始並不順手,但磨合期不會太長。最主要是要熟悉多點觸控手勢。由於螢幕小,大多數是使用單視窗邏輯去操作,所以固定在最上層選單使用起來不像 ubuntu 的 unity 那樣彆扭。
  7. 中文輸入法的設定/安裝經驗不好。由於我使用許氏鍵盤注音,所以得額外安裝支援許氏鍵盤的輸入法。一開始使用 Openvanilla,但後來發現酷音要另外裝。上網找了一些安裝方式都裝不起來,我就放棄了。最後使用 Yahoo 的輸入法。但是 Yahoo 輸入法要選擇許氏鍵盤居然還要靠秘技才行?
  8. 軟體包含許多實用的軟體,比方說 quick time 能將螢幕畫面錄下來。想放上 youtube,可能會想自己配樂。雖然 youtube 有提供一些音樂讓你配音,但其中一些似乎會強迫在你影片中放廣告。所以,可以自己用 garageband 放一些簡單的配樂進去。Facetime 的畫質和效果就我個人的經驗來說,是同類型最佳。
  9. xcode 我用了一下,還沒有上手。
  10. 由於 128G 的 SSD 不很大,根據網路上的資訊,我選擇用相對較省空間的 brew 來管理開源向的套件。當然也裝上了 python。雖說 osx 的底層是 bsd,但很多東西的支援度還是有差。比方上圖是最近練習寫的小遊戲,用的是 pyglet。pyglet 在 mountain lion 上跑不起來。當然最後我還是跑起來了,因為用了 1.2 alpha,而且還修改了裡面的 bug 才能跑(搜尋網路找到的)。但即使如此,跑起來還是有小問題。
  11. 另外一個例子是 pcsx。下載官網事先編譯好的可執行套件,會發現無法使用硬體加速 plugin。原本我打算自己寫,不過下載好 source 後發現其實自己 compile 之後就有硬體加速的 plugin 了。總之,就是開源向的東西支援完整度沒有那麼好。不過,一部分的原因也是因為 mountain lion 本身的向下相容性問題。

以不到四萬元的機器來說,我認為是滿意的。目前大致上取代了 xoom 和原本筆電的功能。

2012年10月9日 星期二

用 Python 將漫畫轉 PDF 給 Kindle DX 用



Kindle DX 的 824x1200 解析度拿來看黑白漫畫還算合適。可以直接轉圖檔來看,但是 Kindle DX 的看圖軟體並不是很穩定。也可以用一些免費的 pdf 工具來把圖檔組合轉成 pdf 檔,但並不是很能隨心所欲的控制解析度。
所以這裡利用 python 的 reportlab 來做。
底下是先利用 PIL 先將圖檔切兩半,然後增加對比,壓縮成 JPEG,最後再利用reportlab 將圖檔放入 pdf 中即可。
from glob import iglob
from sys import argv
from io import BytesIO
from PIL import Image, ImageOps
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
dxsize=(776,1150)
pathname=argv[1]
c = canvas.Canvas( pathname+".pdf",pagesize=dxsize)
for fn in sorted(iglob(pathname+"/*.jpg")):
    img=Image.open(fn).convert("L")    
    w,h=img.size    
    im_split = map(img.crop, [(w/2,20, w, h), (0,20, w/2, h)])    
    im = [img.crop((0,20,w,h))] if w < h else im_split    
    for imgx in im:
        imgx=imgx.resize(dxsize, Image.ANTIALIAS)
        imgx=ImageOps.autocontrast(imgx, cutoff=10)
        tmpio=BytesIO()
        imgx.save(tmpio, "JPEG", quality=70)
        tmpio.seek(0)        
        c.drawImage(ImageReader(tmpio), 0, 0)
        c.showPage()
c.save()

裡面的 dxsize 是根據 mobileread 的網友實驗出來,kindle dx 中 pdf 可用的最大圖檔解析度。雖然 pagesize 的單位是 point 而不是 pixel,但看起來似乎這樣是對的設定。
由於抓來的圖檔對比太弱,利用 autocontrast 來加強對比。
im_split 那行是將圖切回左右兩頁,上面的 20px 是去掉漫畫網站的 mark。
ImageReader 其實吃 PIL 的 Image,但為了能夠控制 JPEG 的壓縮率,所以利用 BytesIO 來當暫存檔。由於某些 PIL bug 的緣故,雖然理論上 Image.save 應該要能吃 BytesIO,但是上面的程式碼會出錯,因為 PIL 沒有處理某些 BytesIO 丟出的 exception,所以我手動修改 PIL 的程式碼讓,save 能吃 BytesIO,也許改成 StringIO 也可以避開這個問題。
原先還想說是否要 dithering,不過至少漫畫看起來還可以接受。

倒也不是非得一定要用 python 寫,我同時也有抓 pdf fill 這樣的現成工具。只是剛好網路有點慢,還沒有抓完 pdf fill,已經先裝好 PIL、 reportlab,然後寫出上面那個程式的雛型了(不過原來沒有用 BytesIO 而且是用 reportlab 比較高階的寫法)。

2012年9月30日 星期日

從 Linus、飛機失火到魔法老師

圖片來源 Matt Cunnelly
最近在 Linux 的作者 Linus Torvalds ,因"飛機最大的問題就是窗戶打不開"的言論,在 Goolge+ 上罵美國共和黨總統候選人羅姆尼為「他媽的腦殘」 "He really seems to be a f*cking moron." 隔天又馬上在 Google+ 上改口說道:「他好像是開玩笑的」
這個故事告訴我們的是,即使像是 Linus 這樣,邏輯思考能力足以開發作業系統,分析能力足以在龐大程式碼找出 Bug 的人,在某些時候,一樣會被媒體誤導。畢竟有時因媒體的特性,部份資訊會無可避免的遺失(比方文字資訊不容易傳達語氣)。更別說有時有些資訊來源是別有目的的。
最近有所謂照南國小魔法老師七朵花事件。這中間誰對誰錯不是本文的重點。重點是,這裡面有黑函,還有黑函 2.0。

黑函也是一種資訊,只不過是一種消息來源不明確的資訊。消息來不明確,不見得資訊就不能用。比方如果有個不明來源的資訊,利用基礎的數論,在一張 A4 紙的空間上證明了 Fermat's Last Theorem,每個懂數學的人都可以直接驗證這個證明是否正確。如果正確,那這個證明真的是有意義的。資訊來源是否匿名,就不是那麼重要。但如果這張 A4 紙上同時宣稱這是 Fermat 當年沒有寫下的證明,我們雖然可以判斷裡面的數學手法和工具是否符合 Fermat 的風格,但相對來說比較難證實這件事。有消息來源,至少還能找到作者,也許還能確認他手上是否真的有當年的手稿。

這次會造成家長連署,進而會需要讓校長讓調班的事件,起因應該是黑函和口語(所謂的七朵花在苗栗風評很差,懶人包中也有提到)。
很多時候,匿名資訊代表著發布資訊者不願意為這個資訊負責。
這是黑函可怕的地方,大多數人並不在意消息怎麼來的。不是沒注意到而已,而是根本不在意。因為大多數人沒有 Linus 邏輯能力、分析能力,還有自省能力。
 不過更可怕的是黑函 2.0 。這次事件讓絕大多數人氣憤的,是那個七朵花在會議中對長官態度惡劣的 youtube 影片。絕大多數人不關心的是,該影片的上傳者,是一個註冊不到一天的人上傳的,而且用了個 Chen Charly 這樣不知道是誰的名字。

黑函不可怕,可怕的是它居然有效。
日常生活中,充斥著不明來源的「黑函」。吃什麼樣的食物才健康,什麼東西有電磁波會致癌,還有某某某的性愛光碟。
可怕的是它居然有效。

2012年9月15日 星期六

3D 超任模擬器

這是基於 snes9x 的簡單修改,增加雙眼視覺 3D 立體效果。
 不是什麼新點子,但如果你搜尋一下網路,就會發現說得人多,做得人少(大部份的情節是某人問說 snes9x 有沒有支援 3d stereoscopy,然後會有人說不行、沒意義等等的,有時也有人說應該可以,但就是沒有人真的去弄)。

3D 遊戲要弄出深度很簡單,但超任明明是 2D 畫面,要怎樣弄出深度?
因為超任有四層 background,一層 sprite,每層 background 和 sprite 又有不同的優先權等等的差別,所以可以依照繪製的順序給出深度(雖然得出的深度不見得理想),而 snes9x 的實作中,也給出了 z-buffer,所以有內建的深度可用,所以只要簡單的依照深度將 tile 位移即可。

目前的實作在 https://github.com/tjwei/snes9x-3d,只支援 odd-even-rows,還有 linux/gtk,因為這是我桌機的設定。 為了要放上 youtube,所以改了個 left-right 的版本(只是左右有點搞不清),然後用 recoredmydesktop 來錄。但是錄起來有 window 的邊,所以又用了 HandBrake 手動修掉邊。
由於影片製作的過程很家庭手工,所以有點不太順,實際上使用的效果會比影片要好一點。
有些遊戲效果還不錯,有些則不怎麼樣。

在 evo 3d 上看,似乎要深度加強一點,所以也錄了一個深度加強版。 由於我 compile 的 Snesoid 會 crash,所以 port 到 evo 3d 上要等等了。

Demo 如下
深度較強,適合小螢幕,只有快打旋風二



深度較弱,比較長

2012年9月6日 星期四

窮人的 3D 全像 : 使用 Android 手機



這是一個簡單的實做,利用隨手可得 Android Phone 來製作 Swept-volume display。顯示的是一個立方體,其中兩面顯示英文字母,一面顯示黃色,其他幾面是空心的。因為手機螢幕及錄影機的 framerate 的緣故,錄得不是很好,(有點類似錄 CRT 電視的情況),實際上的效果要好些。 其他還有弄一些單純的方塊,方塊中加個圓管,十字架,方塊中一個小方塊,但就沒有錄了。

 視覺暫留顯示(POV Display) 不罕見,如下面的影片

 

 Volume Display 最常見的就是 Led Cube,




 上面兩個都是常見的 DIY project,Swept-volume display 差不多就是上面兩個東西的混合。
用手機的好處就是 X,Y 的解析度是 480x800,不是 LED Cube 的 8x8 能比的。做 POV Display,也不用額外的硬體,單純用人力揮動配合手機的 accelerometer 即可。
但 Z 軸的解析度就很差。假設手一秒來回揮動三次,一般手機螢幕更新率是 60Hz,那表示 Z 方向從頭到尾移動一次只花了 1/6 秒,畫面只更新了 10 次。外加一些誤差(手的誤差和 sensor 的更新率),去頭去尾之後,Z 軸的解析度也只有 6~8。
當然你也可以手揮動得慢一點,但是太慢了就無法讓眼睛產生視覺暫留。
總之,暫時無法弄出 Leia 公主。修改之後應該還可以再擠出一些 Z 軸的 frame 出來。

更新:新影片,攝影技巧好得多。比較有信心能弄出 Leia 公主或初音了。

2012年8月30日 星期四

正在用 Javascript 寫的 Playstation 模擬器


這是用 emscripten 移植到 javascript 上的 pcsx 模擬器的測試影片(Final Fantasy 8, Crash Bandicoot, Chrome)。 還在很早期的階段,目前尚未釋出。 測試影片中,沒有用 HLE (雖然應該可用),沒有用 webgl (soft render,因為比較好測試和 C 版本的差異),沒有用 Dynarec。 過程中找出不少 emscripten 的 bug,都提出 issue 和 patch,有一些問題目前已在官方版本中解決了。有一些修正目前還未匯入官方版本,影片中可以看到其中的差異。 我也給了一個 dataview 的初始 patch,解決了很多 safe_heap 的問題,但速度方面有問題。 之前放在 github 上的超任模擬器,由於 emscripten 更新,所以需要修改才能正確編譯。 我應該會弄一個 fork 出來,比較方便。 9/1 Update Video:
HLE=1, Firefox Nightly
Rage Racer, Parasite Eve, Grand Turismo Duke Nukem

2012年8月22日 星期三

COSCUP 2012

這次印象深刻的演講有幾個,


Jserv 的現場寫程式相當有意思,表現非常熟練。

 

還有 imcat 不說話的閃電秀。

上面兩個都有 Live Coding 的風格和趣味(但不是一般定義的 live coding)

「; 的故事」的說故事技巧很不錯,值得學習。


N900 露出計的這個講得也不錯。 armvisor, pqemu,python->spidermonkey, pyton object vs javascript prototype 也都內容豐富。
此外還聽了深美國小推廣使用 kde 的經驗,相當有趣的經驗。
Win8/IE10的講解非常清楚,美中不足的是沒有在 IE10 demo 跑超任模擬器。
機器人的那場,雖說聽不太懂,但能感受講者的熱情。

一些沒聽到演講如:酷音輸入法(人太多,沒辦法呼吸)、人人編程(跑去聽機器人)就等著看影片了。

BoF 參加了獨立遊戲那群,除了了解到 LuaJIT 又有進步還有獨立遊戲的現況之外,也回想起之前寫過一些遊戲,還找人拍分解動作弄動畫的往事。


其他時間多半在 python 攤位,雖然攤位簡陋,但很多朋友捧場,讓我感受到了社群的熱情。
至於這次我給的演講。很感謝聽眾的熱情回應,讓整場演講效果不錯。當然自己還是發現不少缺點。也只能自我安慰說,畢竟這種只講一場的東西,很難完美。
很感謝 Jedi 送的簡報原力,裡面就有討論到其中一些缺點。
不過對於避免 Live demo 這點,我個人是持不同的意見是了。雖然 Live demo 有時被濫用,但 Live 還是有其無法取代的現場魅力。

2012年8月21日 星期二

N64 emulators in JS


剛剛發現兩個 N64 JS 模擬器的網址
http://n64js.blogspot.co.uk/
http://code.google.com/p/1964js/

看起來挺酷的。雖然兩者都還沒有到真的能玩的地步,但效果其實已經很不錯了。 Dynarec 的部份可以參考借鏡。


2012年8月20日 星期一

我的 COSCUP 2012 投影片


用 Javascript 模擬超任 from weijr

投影片中的影片看不到,但應該都可以在我的youtube 頻道上找到。 
 
20121227 更新:
coscup 提供錄影