2017年3月22日 星期三

連結直接發出 WhatsApp

如想用連結直接發出 WhatsApp,只需要把連結寫成:
whatsapp://send?text=You%20are%20so%20smart&phone=+85294129112
「text=」後是文字訊息,「&phone=」後的是包含區碼的電話號碼。

2017年3月20日 星期一

解決 json_encode 亂碼問題

在開發微信機械人時遇到一個問題,所有在 PHP 中加入到數組的中文字,在經過 json_encode 後會變成亂碼。就像是:
{"KEY01":"\u6700\u65b0\u8cc7\u8a0a","KEY02":"\u95dc\u65bc\u54c1\u724c","KEY03":"\u5e97\u8216\u4f4d\u7f6e"}
之前用了一個愚蠢的解決方法,先以特訂的關鍵字注入數組,完成 json_encode 後,才用 str_replace 方式把關鍵字替換成中文字, 避開因 json_encode 而導致的亂碼問題。但原來有一個聰明的做法。只要在 json_encode 後加入 JSON_UNESCAPED_UNICODE 參數。例如:
$menuArray = array(
   "KEY01"=>"最新資訊",
   "KEY02"=>"關於品牌",
   "KEY03"=>"店舖位置",
);
echo("<br>JSON: ".json_encode($menuArray));
echo("<br>JSON_UNESCAPED_UNICODE: ".json_encode($menuArray, JSON_UNESCAPED_UNICODE));
echo("<br> ");
上面程式的執行結果如下:
JSON: {"KEY01":"\u6700\u65b0\u8cc7\u8a0a","KEY02":"\u95dc\u65bc\u54c1\u724c","KEY03":"\u5e97\u8216\u4f4d\u7f6e"}
JSON_UNESCAPED_UNICODE: {"KEY01":"最新資訊","KEY02":"關於品牌","KEY03":"店舖位置"}

2017年3月18日 星期六

新的 JPEG 編碼器:guetzli


Google 推出了一個新的 JPEG 編碼器:guetzli。它的效能比一般的編碼器能節省 20-30% 的儲存空間,很適合用在網頁中的 JPEG 圖像。這個 guetzli 算法已在 GitHub 上開源。我就在 MacBook Pro 上進行安裝。由於我的 macOS 已裝有 Homebrew,因此只需要在 Terminal 中輸入「brew install guetzli」便能順利安裝。在 App Store 拿了 Mario 的 App Icon 來進行測試,一張 256x256 像素的圖檔在 Preview 生成 100% 質素 JPEG,得出 97KB;而利用 guetzli 指令「guetzli --quality 100 mario.png quetzli.jpg」生成 100% 質素 JPEG,得出 83KB。的確比一般編碼器生成的 JPEG 更能節省空間。


我把 Preview 及 guetzli 的輸出拿來比較,說算放大到 400%,肉眼也看不出有任何分別。如果把兩張圖做「比較」處理,再把差別強烈放大,才能得出最右圖的分別。既然肉眼上看不出,那當然選用細小的 guetzli 編碼。不過,代價是這個編碼器在編碼時需要用上更多的資源。

2017年3月13日 星期一

Pix2Pix 的地圖訓練成果


上週五開始,花了 26 小時訓練了地圖模型。今日拿來測試,對於之前的經驗,我沒有抱太大的期望。以下是 Pix2Pix 按照左面的輸入圖產生出右面的輸出。四張示範圖出來的效果也差不多,目前也看不清楚。希望日後有待改進。

2017年3月12日 星期日

學習使用燈光(二)

前天,一位任職燈光 20 年的朋友來教授打燈技巧,也分享了他一些作品的燈光設定。我一直使用的器材只有一台相機、一條 5V 白光 LED 帶、一支黃光 LED 棒。


朋友指要拍出好的燈光效果,他用上了五個光源。左右各一個、產品背後一個,都是用來襯托出產品的邊緣。前方一個用來帶出主體的內容。而每個光源有時需要不同的明亮及顏色;也帶了不同顏色的濾鏡給我。濾鏡除了能改變光源顏色外,有些還能令光線變得柔和、令影子變得模糊。如果想要拍得美觀,光源不一定要直射到主體身上,可以是用反光布或反光板,會有不一樣的效果。


很多時候,他使用強光電筒作為光源;還帶了兩支過來給我參考了。今天,我專程跑到鴨寮街街頭購買,那是朋友買左面電筒的地方。盛惠 HK$79 連鋰電及充電器。

後來,我在黃金商場對面的深水埗電子特賣城遇到更強光度、更實惠、更美觀的電筒。只需 HK$49。既然光源不只一個,那乾脆買多一支。


在多光源的情況下,朋友會用到長臂夾來設定位置。我在花園街以 HK$10 買了一個。


工具升級了,雖然還欠一個大支架,但總算能拍到更高要永的照片:要有三四個光源不是問題;要不同顏色不是問題;要強力光源不是問題。現在只待下次有新產品進行拍攝工作。

2017年3月11日 星期六

利用 Pillow 縮小圖像尺寸

平時要把體積較大,特別是由 Photoshop 儲存出來的圖像時,我會用 macOS 本身的 Preview 來另存檔案。通常輸出來的檔案都會變得細小。主要是 Photoshop 儲存了太多與圖像無關的資訊;像是參考線、打印機、...等資料。可是,昨天遇到一個問題。手上一個 PNG 檔,無論用 Preview 怎樣另存 JPG 檔案、把畫質怎麼調,得出來的檔案大小都在 3MB 以上。最題是圖像本身只有 640x1136,並不是一個高解像的體質,以 JPG 格式來說,不應有如此龐大。於是利用十六進制編輯器打開檔案:

發現內含大量文字訊息。我不知道有甚麼用,但可以肯定跟影像無關,可以刪去。但要怎樣做呢?我選用 Python 的 Pillow 去達成。經過下面幾行代碼,便能把 PNG 輸出成細小的 JPG。體積由原來的 3MB 變成 97KB!

2017年3月10日 星期五

小天使,生日快樂!


小天使,生日快樂!

2017年3月9日 星期四

在 CentOS 7 安裝 CUDA 8.0(二)

前天的「在 CentOS 7 安裝 CUDA 8.0」有一點瑕疵,於是以「sudo yum remove nvidia-*」把所有事情推倒重來。上次用的 CUDA 是 rpm 版本,今次到 Nvidia 官網下載 runfile 版本。


按照指示以「sudo sh cuda_8.0.61_375.26_linux.run」進行安裝,也再次安裝 cuDNN 程式庫。


由於之前 Docker 版的 TensorFlow 找不到 GeForce GTX 680 顯示卡,於是我決定直接安裝 TensorFlow 1.0。跟據 TensorFlow 官網的指示以 virtualenv 方式安裝。用 Python 3.n + GPU 的版本,亦即是「pip3 install --upgrade tensorflow-gpu」。完成後進入 Python3 輸入幾行程式去印證 TensorFlow 成功安裝。


成功後,再一次執行 Pix2Pix 的訓練,會出現要求使用 TensorFlow 1.0.0 的錯誤。而我手上的卻是 TensorFlow 1.0.1。於是我打開 pix2pix.py,把第 539 行的「1.0.0」改為「1.0.1」後,再進行訓練。

原先單純用 CPU 需要 6425 分鐘的訓練,改用 GeForce GTX 680 GPU 版本變成 639 分鐘,足足快了十倍!

2017年3月8日 星期三

解決 CodeSign 問題


已經有八個月沒有寫 iOS App。今日開了一個新項目,想用模擬器打開,豈料在組譯時出現「Command /usr/bin/codesign failed with exit code 1」。以前,這會是 Provisioning Profile 的問題,可是無論我用指定的 Provisioning Profile 或是 Wildcard 都解決不了錯誤。最後,在網上找到以下這個絕招:
cd ~/Library/Developer/Xcode/DerivedData
xattr -rc .

2017年3月7日 星期二

在 CentOS 7 安裝 CUDA 8.0


今日在公司找到一張 Nvidia 的顯示卡,型號是 GeForce GTX 680。查看 官網資料,這張卡支援 CUDA,意味著可以拿來進行 Machine Learning 的訓練工作。我感覺找到寶物一樣!

我把它安裝到一台 PC 上,把原來的 AMD 顯示卡換掉。開機正常。之後就是要安裝 CUDA 驅動程式及 cuDNN 程式庫。步驟如下:
  1. yum update
  2. yum install gcc gcc-c++
  3. sudo yum install kernel-devel-$(uname -r) kernel-headers-$(uname -r)
  4. Download CUDA Toolkit 8.0 from https://developer.nvidia.com/cuda-downloads

  5. sudo rpm -i cuda-repo-rhel7-8-0-local-ga2-8.0.61-1.x86_64.rpm
  6. sudo yum clean all
  7. sudo yum install cuda
  8. reboot
  9. vi /etc/profile
    export PATH=/usr/local/cuda-8.0/bin:$PATH
    export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64:/usr/local/cuda-8.0/extras/CUPTI/lib64:$LD_LIBRARY_PATH
    
  10. mkdir ~/cuda-test
  11. cd ~/cuda-test
  12. cuda-install-samples-8.0.sh test
  13. cd NVIDIA_CUDA-8.0_Samples/1_Utilities/deviceQuery
  14. make
  15. ./deviceQuery
    CUDA Device Query (Runtime API) version (CUDART static linking)
    
    Detected 1 CUDA Capable device(s)
    
    Device 0: "GeForce GTX 680"
      CUDA Driver Version / Runtime Version          8.0 / 8.0
      CUDA Capability Major/Minor version number:    3.0
      Total amount of global memory:                 1998 MBytes (2095382528 bytes)
      ( 8) Multiprocessors, (192) CUDA Cores/MP:     1536 CUDA Cores
      GPU Max Clock rate:                            1058 MHz (1.06 GHz)
      Memory Clock rate:                             3004 Mhz
      Memory Bus Width:                              256-bit
      L2 Cache Size:                                 524288 bytes
      Maximum Texture Dimension Size (x,y,z)         1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096)
      Maximum Layered 1D Texture Size, (num) layers  1D=(16384), 2048 layers
      Maximum Layered 2D Texture Size, (num) layers  2D=(16384, 16384), 2048 layers
      Total amount of constant memory:               65536 bytes
      Total amount of shared memory per block:       49152 bytes
      Total number of registers available per block: 65536
      Warp size:                                     32
      Maximum number of threads per multiprocessor:  2048
      Maximum number of threads per block:           1024
      Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
      Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
      Maximum memory pitch:                          2147483647 bytes
      Texture alignment:                             512 bytes
      Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
      Run time limit on kernels:                     No
      Integrated GPU sharing Host Memory:            No
      Support host page-locked memory mapping:       Yes
      Alignment requirement for Surfaces:            Yes
      Device has ECC support:                        Disabled
      Device supports Unified Addressing (UVA):      Yes
      Device PCI Domain ID / Bus ID / location ID:   0 / 1 / 0
      Compute Mode:
      < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >
    
    deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 8.0, NumDevs = 1, Device0 = GeForce GTX 680
    Result = PASS