這個月的頭條就是筆者找到工作了,從事Android UI的設計。最近發現API Demo的sample已經不夠參考了,因為不同的device跟輸入方式所需要的UI是大大不同,而API demo基本上是以手機的應用為主,今天如果我是要設計成Nettop或是TV用的UI,絕不是把畫面放大就能草草交差的事。雖然筆者滿懷雄心壯志,但是在業界打滾幾年後也知道公司根本不會有那個耐心等我好好設計架構、做user survey甚至是發好幾版的demo template;"time to market" kills designs,難怪路上滿滿都是山寨UI。
大家也都知道現在工作難找,筆者也被凹了。對我來說,這也就只是一份工作罷了,如果可以,我還寧願自己寫程式去賣。
3.28.2009
2.18.2009
癮科技也有Android專屬子頻道了
By
Michael
網址是 http://android.cool3c.com/
這是比較偏向user端的site,開發者也可以藉此觀察使用者的需求。
順便更新一下近況,歷經過年,最近的工作機會“似乎”有那麼多了一些,所以最近忙著更新自傳履歷還有K書,不管未來是做什麼工作,基本功是一直要練的。明天又要去面試了,先這樣。
這是比較偏向user端的site,開發者也可以藉此觀察使用者的需求。
順便更新一下近況,歷經過年,最近的工作機會“似乎”有那麼多了一些,所以最近忙著更新自傳履歷還有K書,不管未來是做什麼工作,基本功是一直要練的。明天又要去面試了,先這樣。
1.04.2009
[C語言] Rounding 四捨五入
By
Michael
前陣子有公司找我去面談,結果被打槍了,心情低落了一陣子,所以一段時間沒文章。最近在實驗室BBS有學弟妹分享如何在Matlab呼叫C寫的code(因為Matlab實在跑太慢了,更不用說Mac版的),不過這不是重點,因為我的畢業論文就用過這招了,那段程式是用inline assembly做四捨五入,所以我想就來分享一點使用C語言實作Rounding(四捨五入)的各種方法與經驗。
一般人想到用C實作四捨五入,會有幾種方法?就我所知,至少有將近10種或是更多(不好意思,學藝不精),以下分享最簡單到稍難的方法,除此以外大概還有C++專屬的用法、CPU限定的用法(跟32/64-bit有關)以及使用magic number的用法,這些我就不多著墨了,有興趣的讀者可以用我前面提供的線索去找找。
1. 利用C語言中浮點數轉整數會把小數點去掉的特性,這是ANSI C裡頭制定的規格,所以大部份的平台都可以使用(沒有浮點數的就別來亂了),程式大概長這樣:
inline int myIntRound(double dInput)
{
if(dInput >= 0.0f)
{
return ((int)(dInput + 0.5f));
}
return ((int)(dInput - 0.5f));
}
2. 使用math.h中的round()函式,唯一要特別注意的是接回傳值是用double或int,永遠別忽略type casting所帶來的effort,使用方法很簡單,把值丟進去就行了:
double dResult = round(dInput);
3. GCC的math.h中可以找到nearbyint()這個函式,用法跟round()一樣:
double dResult = nearbyint(dInput);
4. 接下來這個方法其實有點脫褲子放屁,如果你的math.h沒有提供round()可以派上用場。一樣include math.h,我們改用floor()及ceil()來實作,程式碼如下:
inline double myFloorRound(double dInput)
{
if(dInput >= 0.0f)
{
return floor(dInput + 0.5f);
}
return ceil(dInput - 0.5f);
}
5. 接下來要介紹的方法就比較不那麼跨平台了,我們要使用frndint這個FPU指令,並且以inline assembly實作,在使用x86 CPU的Win32上的實作上大概長得像這樣:
inline double myDoubleRound(double dInput)
{
double dResult;
__asm__ (
"frndint;": "=t" (dResult) : "0" (dInput)
);
return dResult;
}
順道一提的是,某些math.h中的round就是這樣寫的。
6. 一樣用inline assembly,我們用到了fld及fistp這兩個指令,程式碼如下:
inline int double2int(double dInput)
{
int nResult = 0;
__asm {
fld dInput
fistp nResult
}
return nResult;
}
其實在使用fistp之前應該要先用fldcw設定rounding的方式,可以設定為最近的int,或是floor/ceil等。
=========== 我是分隔線 ===========
現在讓我們來測試一下各種方法的效能如何,筆者使用的環境是Mac OS X 10.5.6(Intel)、GCC 4.0.1,compile參數為-O2 -fasm-blocks,每個方法呼叫100000000次,以-3.5做為input,測試結果如下:
Math.round: 0.048509 sec, result = -4
Math.nearbyint: 0.045757 sec, result = -4
myIntRound: 0.045828 sec, result = -4
myDoubleRound: 0.045824 sec, result = -4
myFloorRound: 0.045940 sec, result = -4
double2int: 0.222163 sec, result = -4
前面的5種方法速度都在誤差範圍內,只有double2int的速度特別慢,這件事告訴我們:拔獅子的鬃毛不一定會長出頭髮,就算用inline assembly也不一定會比較快!另外不知道是不是筆者的compiler特別愛作怪,inline assembly加上volatile甚至還會拖慢,以myDoubleRound來說好了,我在__asm__後面加上__volatile__,測試結果竟然要0.457702 sec,足足慢了10倍!
小小做個總結好了,其實C語言有很多不起眼卻可以探討的主題,翻一翻GCC的code也可以挖到不少寶。以四捨五入來說,每種方法都各有優缺點,使用math.h的方法最容易實作,卻也會讓program image變大;使用myIntRound的方法如果回傳後是塞到double就需要cast的effort;採用myDoubleRound的方法需要FPU指令。要使用何種方法就見人見智囉。
一般人想到用C實作四捨五入,會有幾種方法?就我所知,至少有將近10種或是更多(不好意思,學藝不精),以下分享最簡單到稍難的方法,除此以外大概還有C++專屬的用法、CPU限定的用法(跟32/64-bit有關)以及使用magic number的用法,這些我就不多著墨了,有興趣的讀者可以用我前面提供的線索去找找。
1. 利用C語言中浮點數轉整數會把小數點去掉的特性,這是ANSI C裡頭制定的規格,所以大部份的平台都可以使用(沒有浮點數的就別來亂了),程式大概長這樣:
inline int myIntRound(double dInput)
{
if(dInput >= 0.0f)
{
return ((int)(dInput + 0.5f));
}
return ((int)(dInput - 0.5f));
}
2. 使用math.h中的round()函式,唯一要特別注意的是接回傳值是用double或int,永遠別忽略type casting所帶來的effort,使用方法很簡單,把值丟進去就行了:
double dResult = round(dInput);
3. GCC的math.h中可以找到nearbyint()這個函式,用法跟round()一樣:
double dResult = nearbyint(dInput);
4. 接下來這個方法其實有點脫褲子放屁,如果你的math.h沒有提供round()可以派上用場。一樣include math.h,我們改用floor()及ceil()來實作,程式碼如下:
inline double myFloorRound(double dInput)
{
if(dInput >= 0.0f)
{
return floor(dInput + 0.5f);
}
return ceil(dInput - 0.5f);
}
5. 接下來要介紹的方法就比較不那麼跨平台了,我們要使用frndint這個FPU指令,並且以inline assembly實作,在使用x86 CPU的Win32上的實作上大概長得像這樣:
inline double myDoubleRound(double dInput)
{
double dResult;
__asm__ (
"frndint;": "=t" (dResult) : "0" (dInput)
);
return dResult;
}
順道一提的是,某些math.h中的round就是這樣寫的。
6. 一樣用inline assembly,我們用到了fld及fistp這兩個指令,程式碼如下:
inline int double2int(double dInput)
{
int nResult = 0;
__asm {
fld dInput
fistp nResult
}
return nResult;
}
其實在使用fistp之前應該要先用fldcw設定rounding的方式,可以設定為最近的int,或是floor/ceil等。
=========== 我是分隔線 ===========
現在讓我們來測試一下各種方法的效能如何,筆者使用的環境是Mac OS X 10.5.6(Intel)、GCC 4.0.1,compile參數為-O2 -fasm-blocks,每個方法呼叫100000000次,以-3.5做為input,測試結果如下:
Math.round: 0.048509 sec, result = -4
Math.nearbyint: 0.045757 sec, result = -4
myIntRound: 0.045828 sec, result = -4
myDoubleRound: 0.045824 sec, result = -4
myFloorRound: 0.045940 sec, result = -4
double2int: 0.222163 sec, result = -4
前面的5種方法速度都在誤差範圍內,只有double2int的速度特別慢,這件事告訴我們:拔獅子的鬃毛不一定會長出頭髮,就算用inline assembly也不一定會比較快!另外不知道是不是筆者的compiler特別愛作怪,inline assembly加上volatile甚至還會拖慢,以myDoubleRound來說好了,我在__asm__後面加上__volatile__,測試結果竟然要0.457702 sec,足足慢了10倍!
小小做個總結好了,其實C語言有很多不起眼卻可以探討的主題,翻一翻GCC的code也可以挖到不少寶。以四捨五入來說,每種方法都各有優缺點,使用math.h的方法最容易實作,卻也會讓program image變大;使用myIntRound的方法如果回傳後是塞到double就需要cast的effort;採用myDoubleRound的方法需要FPU指令。要使用何種方法就見人見智囉。
12.22.2008
Manage items with codes 用條碼管理物品
By
Michael
不知道各位有沒有這種經驗,筆者小時候曾經在家裡冰箱的冷凍庫中找到兩年前的冷凍包子,每年過年冰箱都要進行一次“新陳代謝”,看起來好像沒什麼,最多就是吃壞肚子罷了,但是東西堆在冰箱內會影響氣流的流動,使得冰箱變得更為耗電,以及冷媒的消耗和加速冰箱的折損率;雖然沒有正式的統計,但是我相信全台灣堆在冰箱內的過期食物應該會造成不少多餘的碳排放。事實上,不只是冰箱內的食物可以管理(藏在冰箱內的私房錢也需要管理),所有買回家的東西,都可以管理,問題是,怎麼管理?其中一個簡單的解決方案是:透過條碼管理。
拜照像手機與內建鏡頭的的筆電所賜,現在越來越容易取得商品上的Barcode。在日本,到處都可以見到印上QR Code 的商品,QR Code就是所謂的二維條碼,可以嵌入比一維條碼更多的資訊以及更高的污損容錯率(簡單來說,就是弄髒一點甚至破掉都還可以還原),這張圖就是內嵌本站網址的二維條碼:
拜照像手機與內建鏡頭的的筆電所賜,現在越來越容易取得商品上的Barcode。在日本,到處都可以見到印上QR Code 的商品,QR Code就是所謂的二維條碼,可以嵌入比一維條碼更多的資訊以及更高的污損容錯率(簡單來說,就是弄髒一點甚至破掉都還可以還原),這張圖就是內嵌本站網址的二維條碼:
只要拿起有QR Code辨識軟體的手機對著螢幕拍下這張圖,馬上就可以方便地連上本站(或是加入書籤);而在台灣,幾乎所有商品都有印上一維條碼,最常見的就是13個數字的EAN-13 編碼,以及圖書專用的ISBN碼,現在甚至連去大賣場買水果也有Barcode,我們可以把這些Barcode當作是物品的ID來進行管理。以上是整個系統的概念。
在實作上,已經有Open Source的project可供取用,目前最方便的,應該是使用Java所寫的ZXing。ZXing支援了各多種Platform與Barcode的應用,平台方面除了基本一定要有的J2SE/J2ME,也支援RIM、Android、iPhone(QR Code only,用Obj-C寫的)等平台,簡直就是佛心來著!有興趣的朋友可以嘗試玩看看,筆者小測了一下覺得還蠻好玩的。
在Android上,有套叫CompareEverywhere的軟體就是將Barcode scanning與Google API整合,除了透過Barcode查詢物品與比價,還能在地圖上顯示附近有賣這項物品的商店,在Youtube上可以找到Demo影片。而Android平台中就有內建SQLite,可以將物品資訊存在DB中更方便使用。
在Mac上比較著名的軟體大概就是Delicious Library,目前已經推出到2.0版,這個版本可以輸出對iPhone最佳化的的web格式,可以參考Mobile01上的介紹 。功能看起來是不賴,不過筆者一向是比較支持Open source……
從單純的管理冰箱過期食物為出發點,可以延伸出相當多的應用,例如家庭主婦最愛的比價功能,或是查詢過去的購買記錄(可以避免買到一樣的東西,像最近筆者又不小心多買了一條洗面乳)、家中的庫存(螢幕顯示冰箱還有一把空心菜),歷史價格、網路上的折價券,或是幫助記帳(終級的記帳方式就是在消費的同時就記帳),可以說是一個很實用的個人/家庭進銷存系統。透過手機的普及以及Open source的貢獻,現在一般家庭也能享用大賣場及便利商店的科技;筆者希望能透過這個小小的科技能減少碳排放以及資源的浪費。
後記:雖然說照像手機很普及,不過筆者剛好沒有照像手機,在找到工作賺夠錢之前,請原諒我先打打嘴砲…
12.16.2008
[DDMS] Capture screen 擷取畫面
By
Michael
所謂工欲善其事,必先利其debugger,想要在Android上面開發程式,總免不了要跟DDMS親蜜親蜜…(快說不下去了),由於日後免不了要和大家分享使用畫面,或是有撰寫使用說明的需要,所以擷取畫面是必不可少的功能。在Android中當然可以寫個utility把Activity的畫面抓下來,不過,這種小事當然不需要用到牛刀,DDMS就可以做到了。以下的說明是在Eclipse,也就是Google官方所建議的開發環境中,使用其他IDE的話,如果沒有和DDMS結合得很好,可能需要手動把DDMS叫出來。
在Eclipse的右上角有個DDMS的tab,不過我剛裝好ADT的時候,其實並沒有找到DDMS的tab,而是像這樣:
這時候要按一下
會出現下拉式選單,選擇Others會出現這樣的視窗,然候選取DDMS按OK:
接著就會在右上角看到DDMS的圖示(如果找不到請拉一下左邊斜斜的地方,可以調整工具列):
點選DDMS以後就可以看到DDMS的視窗,此時還沒有跑模擬器,當然是空空如也。所以接下來就是要Run要跑的程式囉!Run程式基本上不在本篇的範圍內,所以我假設各位都已經有先玩過了,當程式Run起來後,點選剛剛那個DDMS的圖示切換到DDMS視窗,我們可以在左上的窗格看到這樣的畫面:
這個Window的功能是顯示所有正在模擬器上面跑的process以及相關的功能,還有…我們所要的Screen capture功能(都已經用圖提示這麼明顯了)!在模擬器執行的狀態下,我們可以擷取到任何顯示在Android上的畫面,包括開機畫面。另外,我們也可以在獨立執行的DDMS中使用快速鍵Ctrl + s來抓畫面。以下就是API Demos中的OpenGL ES畫面:
是不是又大又清晰呢?雖然筆者用Mac可以很容易地按下cmd+shift+4來抓螢幕的任何畫面,不過還是沒有DDMS來得方便,在DDMS中還可以隨時Update要抓的畫面,對一些畫面變化很多的程式來說,DDMS提供了蠻方便的工具,希望對各位有幫助。往後如果還有其他有關DDMS的心得也會放上來看各位分享。
參考資料: Using DDMS - Android
在Eclipse的右上角有個DDMS的tab,不過我剛裝好ADT的時候,其實並沒有找到DDMS的tab,而是像這樣:
這時候要按一下
會出現下拉式選單,選擇Others會出現這樣的視窗,然候選取DDMS按OK:接著就會在右上角看到DDMS的圖示(如果找不到請拉一下左邊斜斜的地方,可以調整工具列):
點選DDMS以後就可以看到DDMS的視窗,此時還沒有跑模擬器,當然是空空如也。所以接下來就是要Run要跑的程式囉!Run程式基本上不在本篇的範圍內,所以我假設各位都已經有先玩過了,當程式Run起來後,點選剛剛那個DDMS的圖示切換到DDMS視窗,我們可以在左上的窗格看到這樣的畫面:
是不是又大又清晰呢?雖然筆者用Mac可以很容易地按下cmd+shift+4來抓螢幕的任何畫面,不過還是沒有DDMS來得方便,在DDMS中還可以隨時Update要抓的畫面,對一些畫面變化很多的程式來說,DDMS提供了蠻方便的工具,希望對各位有幫助。往後如果還有其他有關DDMS的心得也會放上來看各位分享。
參考資料: Using DDMS - Android
12.13.2008
Face detection in Android
By
Michael
以前曾經做過Face detection的研究(雖然指導教授認為這個topic已經被做到爛了),拜數位相機普級所賜,人臉偵測一下變成了人人口袋都有的技術。人臉偵測在相機的應用上之所以普級,在我的觀察中有幾個因素:
1. 自動對焦。一般消費者用DC拍有人臉的照片(自拍或是合照),都是希望能人臉能是對焦的部份,但是過去的DC所設計的對焦點並無法完全反映出人臉所在的位置,於是常常發生脫焦的現象。人臉偵測解決了這項缺失,有些廠商更進一步發展出了微笑快門等等的應用。
2. 自動曝光。除了脫焦的困擾外,另一項困擾DC使用者的還有「臉色太難看」,也就是臉色不是太白就是太黑,這也是因為早期的DC大概只有點測光、中央區域以及全域測光,雖然稍懂攝影觀念的人知道可以用曝光鎖定的方式來得到正確的曝光,但對一般使用者來說太煩複了,另一方面也不是每一台相機都提供曝光鎖定的功能,這時候人臉偵測技術就成瞭解決方案之一。
3. 方便編修。當人臉可以被偵測出來以後,就可以套用很多影像處理在人臉上了,簡單一點的像磨皮、去紅眼(去紅眼不一定要人臉偵測,不過有人臉做參考比較好處理)等,或是套用魚眼效果、少女漫畫效果,進一步還可以直接把臉換掉變成史瑞克。沒有人臉偵測的話,要做這些事就只能把人臉一個一個慢慢框起來…
那人臉偵測跟手機結合在一起有沒有搞頭?當然有!我們先看一段VCR:
手機跟相機最大的差別當然就在手機可以打電話,因此手機比相機多出了通訊錄的功能,結合網路或是手機內建的相機就可以很方便地將聯絡人的照片加入通訊錄中;另外再加上人臉辨識的話還可以讓手機遺失時減少被盜用的危險。
不過前面說了那麼多,除了給外行的看熱鬧以外,對於像正在看這篇文章的Android開發者來說,有哪些門道呢?該不會要porting OpenCV到Android平台上吧?放心, Google早就很貼心地幫各位準備好android.media.FaceDetector這個package了,只要將參數設好,然後將讀到的image (Bitmap格式)丟進去,它就會吐出一堆Face的Array了,而且不但有座標,連角度都有(你不會真的認為每個人都會安份地給你拍照吧),而且是三維的角度都有!有興趣的朋友可以試試這個package,並且試試能不能想出更kuso、更imba的應用(例如加在遊戲當中)!
12.07.2008
Android 3D UI
By
Michael
最近對Android的3D部份有興趣,先請大家看看這段影片:
很炫吧?
Android使用OpenGL ES,在Android平台上可以同時顯示3D與2D,跟iPhone相較之下,Android賦予開發者極大的彈性。不喜歡內建的撥號程式? 沒問題,換掉!不喜歡內建的桌面?沒問題,通通換掉!對許多開發者來說,Android平台可以說是別於iPhone的另一種天堂,但是事情就真的這麼美好嗎? Android的3D效能如何? 有什麼樣的極限? 穩定性如何? 3D的耗電量如何?這些都將是我會親自去實作與探討的部份,歡迎有興趣的同好一起來討論喔!
訂閱:
文章 (Atom)





