2015年3月28日 星期六

Processing: Gamma Correction

since: 2015/03/28
update: 2015/03/28
reference:
1. Processing.org
2. The Issue | LED Tricks: Gamma Correction | Adafruit Learning System


A. 前言:
     最近開始接觸 Processing, 把學習中遇到的一些問題與解決辦法記錄下來,
     這篇文章主要是說明在 Processing 中作伽瑪校正(Gamma correction)的方式. 
     目前的螢幕影像相關應用程式都會作伽瑪校正, 這邊主要是應用在對特定的
     色偏對象(通常是螢幕) 作微調的處理.

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

B. 說明:
    1. 人眼對於光線的感受能力具有非線性高動態範圍, 在較亮處與較暗處皆可
        看到物體的細節.

    2. 如下圖所示:
         水平軸方向為 LED 的發光功率, 黑色的斜線為其線性的亮度值, 但對應到人眼
         所感受到的光線卻是紅色的曲線. 垂直軸則是人眼所實際感受到的亮度值.
         (圖片來源: https://learn.adafruit.com/led-tricks-gamma-correction/)

         而在其顏色的灰階圖中, 左端有大量的不連續, 而右端幾乎是無法辨別了.

         (圖片來源: https://learn.adafruit.com/led-tricks-gamma-correction/)

    3. 解決方式是在我們的視覺上作非線性的感知補賞: 套用一個反函數, 即是作伽瑪校正.

         (圖片來源: https://learn.adafruit.com/led-tricks-gamma-correction/)

         現在灰階圖的每個階調之間更平滑了.
         (圖片來源: https://learn.adafruit.com/led-tricks-gamma-correction/)

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

C. 新增 Processing sketch:

    1. 下載並安裝 Processing, 在此使用 Pre-Releases 3.0a5 Mac OS X 版.
        底下所要製作的伽瑪校正對應表(gammaTableCorrection), 會將線性輸入值
        轉換成非線性的伽瑪校正輸出值.

    2. 開啟 Processing 新增一個 sketch 名稱存成 gamma_correction.

    3. 首先, 畫一個填滿灰色的矩形.
// simulate original input data
int colorR = 128;
int colorG = 128;
int colorB = 128;

void setup() {
  size(200, 200);
}

void draw() {
    fill(colorR, colorG, colorB);
    rect(25, 25, 150, 150);
}



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

D. 新增參數設定檔:
    1. 在 sketch 目錄內, 新增一個參數設定檔: config.txt

    2. 內容為:
/* start: gamma-correction */
// Red Correction factor(gammaRed)
2.8

// Green Correction factor(gammaGreen)
2.8

// Blue Correction factor(gammaBlue)
2.8

// Top end of INPUT range(max_in)
255

// Top end of OUTPUT range Red(max_out_red)
255

// Top end of OUTPUT range Green(max_out_green)
255

// Top end of OUTPUT range Blue(max_out_blue)
255
/* end: gamma-correction */


說明:
(1). R / G  / B Correction factor == 1.0  ---> no correction (不做校正)
(2). Correction factor 值越高, 中間色調越暗; 值越低, 中間色調越亮.
(3). Correction factor 預設值 2.8, 僅為測試用, 不太科學. 
(4). max_in 與 max_out(R / G / B) 用來設定輸入輸出最大值

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

E. 伽瑪校正處理:
    1. 新增以下程式碼到 sketch 裡:
// simulate original input data
int colorR = 128;
int colorG = 128;
int colorB = 128;


// ----------------------------------------------------
//@for gamma-correction
// load config Strings
String[] configLines;

// begin: gamma-correction table (if value == 1.0, no correction)
float gammaRed = 1.0; // Red Correction factor
float gammaGreen = 1.0; // Green Correction factor
float gammaBlue = 1.0; // Blue Correction factor

// default INPUT & OUTPUT range
int max_in = 255; // Top end of INPUT range
int max_out_red = 255; // Top end of OUTPUT range Red
int max_out_green = 255; // Top end of OUTPUT range Green
int max_out_blue = 255; // Top end of OUTPUT range Blue

int[] gammaTableRed = new int[256];
int[] gammaTableGreen = new int[256];
int[] gammaTableBlue = new int[256];
// end: gamma-correction table
// ----------------------------------------------------


void setup() {
  size(200, 200);

 
  println("original colorR = " + colorR);
  println("original colorG = " + colorG);
  println("original colorB = " + colorB);
 
  //@for gamma-correction
  // load gamma-correction parameters
  loadConfig();
 
  // Red gamma-correction
  gammaTableRed = gammaTableCorrection(gammaRed, max_out_red);
  // println("gammaTableRed: ");
  // for(int i = 0; i < gammaTableRed.length; i++) {
  //   println(gammaTableRed[i]);
  // }
 
  // Green gamma-correction
  gammaTableGreen = gammaTableCorrection(gammaGreen, max_out_green);
  // println("gammaTableGreen: ");
  // for(int i = 0; i < gammaTableGreen.length; i++) {
  //   println(gammaTableGreen[i]);
  // } 
 
  // Blue gamma-correction
  gammaTableBlue = gammaTableCorrection(gammaBlue, max_out_blue);
  // println("gammaTableBlue: ");
  // for(int i = 0; i < gammaTableBlue.length; i++) {
  //   println(gammaTableBlue[i]);
  // }    
 
  colorR = gammaTableRed[colorR];
  colorG =
gammaTableGreen[colorG];
  colorB =
gammaTableBlue[colorB];
   
  println("corrected colorR = " + colorR);
  println("corrected colorG = " + colorG);
  println("corrected colorB = " + colorB);   

}

void draw() {
    fill(colorR, colorG, colorB);
    rect(25, 25, 150, 150);
}


//@for gamma-correction
// gamma Table Correction
int[] gammaTableCorrection(float _gamma, int _maxOut) { 
  int[] gammaTableTmp = new int[256];
 
  for(int i = 0; i <= max_in; i++) {
    gammaTableTmp[i] = (int)((int)(pow((float)i / (float)max_in, _gamma) * _maxOut + 0.5));
  }
 
  return gammaTableTmp;
}

void loadConfig(){
  println("load config data ....");
  configLines = loadStrings("config.txt");

    if(configLines.length > 21) {
      println("getting data from config ....");
     
      // Gamma Correction factor
      gammaRed = Float.parseFloat(configLines[2]);
      println("gammaRed = " + gammaRed);
     
      gammaGreen = Float.parseFloat(configLines[5]);
      println("gammaGreen = " + gammaGreen);     
     
      gammaBlue = Float.parseFloat(configLines[8]);
      println("gammaBlue = " + gammaBlue);     
     
      // Top end of INPUT range
      max_in = int(configLines[11]);
      println("max_in = " + max_in);
     
      // Top end of OUTPUT range Red
      max_out_red = int(configLines[14]);
      println("max_out_red = " + max_out_red);
     
      // Top end of OUTPUT range Green
      max_out_green = int(configLines[17]);
      println("max_out_green = " + max_out_green);
     
      // Top end of OUTPUT range Blue
      max_out_blue = int(configLines[20]);
      println("max_out_blue = " + max_out_blue);
    }
    else {
      println("warnning! load config data error; use default data....");
    }
}


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

F. 實驗結果:
    實驗一: 同時將 RGB 的 gamma 值調小(設為 0.5), 灰色變淡.


    實驗二: 僅將 B 的 gamma 值調小(設為 0.8), 變成靛色了.


2015年3月14日 星期六

eMotion: Wiimote IR Sensor With OSC

since: 2015/03/14
update: 2015/03/14
reference:
1. eMotion | Adrien M / Claire B
2. Home | OSCulator

A. 藍芽連結 Wiimote:
     1. 開啟 Mac 上的藍芽功能後, 打開 Wiimote 電池蓋, 按下電池下方標示為 sync
         的紅色按鈕.

     2. 在 Mac上, 打開藍芽偏好設定:

     3. 對 Wiimote 設備, 點選 "配對"


    4. 配對完成, 顯示: "已連線"

    5. 當在藍芽偏好設定裡, 已經存有該 Wiimote 設備的記錄時, 下次只要按下 Wiimote
        的 "POWER" 即可連線.

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

B. OSCulator 設定:
     1. 先開啟 eMotion, 以方便之後 OSCulator 的 OSC 設定.

     2. 開啟 OSCulator, 點選 "Wiimote" 圖示, 針對選取的 Wiimote 設備作設定:
          > Outputs 輸出, 只需勾選: Raw IR
          > Smoothing 平滑, 將 IR 設為 0, 代表不作平滑處理

     3. 承上, 點選 "Parameters" > "I/O":
         將 TUIO Input Mode 設為: Raw & Interpreted

     4. 承上, 點選 "OSC Routing":
         > Target 選取 #1, 並設定其 URL 為 Mac 上的 eMotion OSC
         > Routes 按下左下方的 "+", 並設為剛剛 Target 的 #1
         > 都設好後, 按下 "Close".

     5. 分別對 Wiimote 可偵測到的四個 IR 來源設定 EventTypeValue:
         EventType: OSC Routing
         Value: 1 (代表上個步驟設定的 #1)

     6. 切換到 Scalings 頁面:
          View > Flip to Scalings Page

     7. 分別對 Wiimote 可偵測到的四個 IR 來源調整xy輸出的最小最大值.
         在此例為:
          Out. min: -5.0
          Out. max: 5.0

     8. 切回到 Routings 頁面:
         View > Flip to Routings Page

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

C. eMotion 設定:

     1. Tools > OSC

     2. Window > Current tool options

     3. 分別對收到的四個 IR 訊息設定其 Type 為: Current tool cursors

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

D.  eMotion 運動筆刷測試:
      1. Forces > drawForces

      2. Tools > Motion brushes

      3. Window > Current tool options

      4. 在 Wiimote IR Sensor 前放置紅外線光源(IR 筆, 打火機, 蠟燭 .... 等),
          即會觸發 Motion brushes 效果.   

2015年3月5日 星期四

eMotion: TUIO

since: 2015/03/05
update: 2015/03/05
reference:
1. eMotion | Adrien M / Claire B
2. eMotion app > Help > eMotion Help
3. TUIO

A. 前置作業:
    1. 執行 eMotion app, 開啟之前儲存的專案檔案.
        File > Open...
       
> select a project file to load.... > Open

    2. 開啟圖層視窗, 顯示選取 "pen" 圖層.
        Window > Layers

    3. 讓筆觸工具正常:
        debug > useFBO (勾選狀態)
        debug > useFBO (取消勾選狀態)

    4. 結果:

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

B. TUIO
    1. 安裝 TuioPad for iOS.
        開啟後, 按下 "Start"

    2. 回到 eMotion:
        Tools > Tuio
       
      Window > Current tool option

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

C. 運動筆刷:
    1. Tools > Motion brushes

    2. Window > Current tool options
        Behaviour 選擇 attractor(吸引)

    3. Forces > drawForces

    4. 在 iOS 上即可藉由 TUIO, 在螢幕上觸控來與 eMotion 互動.

    iOS 上的觸控螢幕:

   eMotion 視窗:

eMotion: Motion Brushes

since: 2015/03/04
update: 2015/03/05
reference:
1. eMotion | Adrien M / Claire B
2. eMotion app > Help > eMotion Help

A. 前置作業:
    1. 執行 eMotion app, 開啟之前儲存的專案檔案.
        File > Open...
       
> select a project file to load.... > Open

    2. 開啟圖層視窗, 顯示選取 "particles" 圖層.
        Window > Layers

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

B. 運動筆刷:
     1. Tools > Motion brushes

     2. Window > Current tool options
          可以選擇不同的 Behaviour(法文: 行為), 調整其屬性參數,
          當再選擇其它行為時, 屬性參數是沿用的, 可視情況再調整.

     3. 目前的行為清單:

參數:
Damping: 減震

簡易說明:
explode: 爆炸
wind: 風吹
displace: 移開
displaceOrigin: 移開原始位置(不恢復原狀)
push: 推
impulse: 脈衝
mountain: 堆積
attractor: 吸引
spring: 彈簧
vortex: 渦流
vortex2: 渦流
flag: 旗號
origin: 原點(無作用?)
shake: 搖動
fall: 落下
freeze: 凍結(畫面)
rotate3D: 3D旋轉(無作用?)
rotateX: 旋轉X軸(無作用?)
rotateY: 旋轉Y軸(無作用?)
rotateZ: 旋轉Z軸(無作用?)
fluid: 流體(無作用?)
fluidMulti: 多方面流體
fluidMovement: 流體運動
fluidDensity: 流體密度(無作用?)
fluidObstacles: 流體障礙(無作用?)
size: 尺寸(無作用?)
opacity: 不透明(無作用?)
duplicate: 複製(無作用?)
magnetic: 磁性
tornado: 龍捲風
follow: 跟隨
pinch: 收縮
earthquake: 地震

4. 例子:
     Forces > drawForces
     Behaviour 選擇 wind (風吹), 調整參數後, 在視窗上從左上往右下劃過.

2015年3月4日 星期三

eMotion: Text

since: 2015/03/04
update: 2015/03/04
reference:
1. eMotion | Adrien M / Claire B
2. eMotion app > Help > eMotion Help

A. 前置作業:
    1. 執行 eMotion app, 開啟之前儲存的專案檔案.
        File > Open...
       
> select a project file to load.... > Open

    2. 開啟圖層視窗, 新增 "text" 圖層, 只顯示選取此圖層.
        Window > Layers

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

B. 文字效果:
     1. Tools > Text

     2. Window > Current tool options
         建議保留預設值, 如果選擇其他字型, 可能會造成 Text 的 "Item 2" 變成空白, 甚至
         整個程式 crash 掉.

     3. 接著, 便可以在視窗上輸入文字, "Enter" 換行, "空白鍵" 空格等.

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

C. 施加作用力:
     1. 擺動: Forces > oscillate on
         重力: Forces > gravity on  

     2. 不固定文字:(文字專用)
         Forces > text oscillate off

     3. 效果:

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

D. 備註:
     1. 目前無法保存專案檔案內容, 應該仍是測試功能.

eMotion: Textured Particles

since: 2015/03/04
update: 2015/03/04
reference:
1. eMotion | Adrien M / Claire B
2. eMotion app > Help > eMotion Help

A. 前置作業:
    1. 執行 eMotion app, 開啟之前儲存的專案檔案.
        File > Open...
       
> select a project file to load.... > Open

    2. 開啟圖層視窗, 新增 "textured particles" 圖層, 只顯示選取此圖層.
        Window > Layers

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

B. 紋理效果:
     1. Tools > Textured particles


     2. Window > Current tool options
         Texture 選擇: particule(法文: 粒子) index

     3. 從圖片資料夾拖拉一個圖檔放到 "RELOAC" 裡.

     4. 接著便可在視窗上印出圖像紋理.

    5. 備註: 目前無法保存專案檔案內容, 應該仍是測試功能.