2018年3月16日 星期五

透視投影(WarpPerspective) 與 仿射投影(WarpAffine) 實作範例代碼(source code)

透視投影(WarpPerspective) 與 仿射投影(WarpAffine) 實作範例代碼(source code)

他們指的是一個影像投射到不同視覺角度上的變化情況

透視投影

  • 是3D的
  • 投影完維持四邊形,直線還是直線但不再平行
可以查看那些鐵軌的圖片,會發現鐵軌越往遠處就會越靠近而不是平行的,儘管他們實際上是平行的,鐵軌的遠方就是透視點。(透視點也是繪圖困難的地方,尤其是人體很吃過往的經驗)
公式
假想有一張圖
把灰色的點固定不動,紅色的點任意你移動,圖片會跟紅點動,可以假想這是一個氣球的皮上面畫有圖像然後你對紅點任意 [移動or縮放] 的的概念。

仿射投影

  • 是2D的
  • 投影完會維持平行四邊形,原本平行的東西還是平行
公式其實與透視投影一樣,取前6個就是第三排Z直接不要了
一般表示方法會 m31=m32=0 m33=1
這樣一來一樣套原本的算法就不需要再除上Z了,式子帶入會被消除。
延續剛剛的概念,現在把紅點刪除一個(或者是說兩個點永遠同步移動)
他們永遠都會是平行四邊形,只是可能出現各種形狀

參考代碼

下面是程式核心的轉換代碼
轉換有分兩種,同一個矩陣可以是
原圖座標轉換到新圖座標,也就是一般看到的公式
另一種反轉是透過計算 反矩陣(逆矩陣) 而來的,詳細可以參考
https://www.wikiwand.com/zh-tw/%E9%80%86%E7%9F%A9%E9%98%B5
只是把它反過來而已,程式中我已經幫你寫上了。
有一點要注意的是,轉換過去再轉換回來會有一些誤差。
// 輸入 dst 座標, 反轉 scr 輸出.
void WarpPerspective_CoorTranfer_Inve(const vector<double>& HomogMat, double& x, double& y) {
    const double* H = HomogMat.data();
    const double i=x, j=y;

    x = (H[2] - H[8]*i) * (H[4] - H[7]*j) - 
        (H[1] - H[7]*i) * (H[5] - H[8]*j);
    y = (H[0] - H[6]*i) * (H[5] - H[8]*j) - 
        (H[2] - H[8]*i) * (H[3] - H[6]*j);

    double z = (H[1] - H[7]*i) * (H[3] - H[6]*j) - 
        (H[0] - H[6]*i) * (H[4] - H[7]*j);

    x /= z;
    y /= z;
}
// 輸入 scr 座標, 轉換 dst 輸出.
void WarpPerspective_CoorTranfer(const vector<double>& HomogMat, double& x, double& y) {
    const double* H = HomogMat.data();
    const double i=x, j=y;

    x = H[0]*i + H[1]*y +H[2];
    y = H[3]*i + H[4]*y +H[5];
    double z = H[6]*i + H[7]*y +H[8];

    x /= z;
    y /= z;

    //x=round(x);
    //y=round(y);
}

參考

沒有留言:

張貼留言