カメラの構成と幾何学モデルの話

トップはこちら

https://qiita.com/Cy-San/items/a9ba0a642e96c04fbfa3

## 概要

画像処理をするためにはまず画像が必要です。
画像を作成するためのハードウェア的な内容から説明して行きます。

カメラは光を取り込みデジタル画像として保存する装置です。光には人間に見える範囲の波長の光(可視光)とそうでないものがあります。
例えば秋月には以下のようなカメラモジュールがありました。

* カラーカメラ

https://akizukidenshi.com/catalog/g/g100053/

* 赤外線カメラ

https://akizukidenshi.com/catalog/g/g100498/

こういったカメラモジュールを使用することで光を電気信号に変換し、画像として保存することができます。

また、ネットワーク越しに通信できるサーバー機能を持ったカメラや、OSSで１眼レフを作成してしまうことも！（すごい！）


* Canonのネットワークカメラ

https://canon.jp/biz/trend/what-is-nwcamera

* OSSの１眼レフカメラ

https://gitlab.com/zephray/sitina1

:::note info
ワクワクするね
:::

## カメラのハードウェア的構造

カメラは主に以下の部品を使用して画像として保存します。

![Camera.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621879/d7e28170-756d-33bc-6d81-a582eda2e4d3.png)

* レンズ・絞り・シャッター部分
外部からの光を集め、焦点を結ぶことで、対象物の像をセンサーに投影します。焦点距離や絞りによって、撮影する画像のシャープさや明るさが調整されます。
* 撮影素子(イメージセンサー)
レンズを通して入った光を電気信号に変換する部分で、CCD（Charge-Coupled Device）センサーやCMOS（Complementary Metal-Oxide-Semiconductor）センサーが使用されます。各ピクセルが光を受け取り、電荷として蓄積され、これが信号として読み取られます。
* カラーフィルター
センサーは光の強さのみを検知するため、各ピクセルごとに色を識別するためのフィルターが設置されています。一般的に「ベイヤーフィルター」が使われ、RGB（赤、緑、青）のフィルタを使ってカラー画像を生成します。
* 信号処理回路
センサーで得られたアナログ信号をデジタル信号に変換し、画像として保存するために各種処理が行われます。例えば、ノイズ除去、ホワイトバランス、彩度調整、圧縮などが含まれます。
* 記録媒体
処理された画像データは、SDカードや内部ストレージなどのメモリに保存されます。
* ファームウェア（ソフトウェア）
撮影した画像を操作したり、カメラの機能をコントロールするための内部ソフトウェアです。ファームウェアによって、露出やシャッタースピードなどの撮影設定を管理します。

## カメラ画像の幾何学的モデル
モデルとは複雑なものを抽象化や一般化して本質のみを抽出し、人間にわかりやすくしたもののことを言います。
カメラ画像の幾何学的モデルは、カメラと撮影対象との間の物理的な関係を表現し、どのようにして3次元空間の情報が2次元の画像に投影されるのか。カメラの配置、焦点距離、レンズの特性などから主に以下のモデルが使われます。

* ピンホールカメラモデル
ピンホールカメラは小さい穴を通して3次元を２次元の写真として生成するモデルです。
シンプルな構造ですが、被写体が反転してしまうので今回は紹介だけにさせてもらいます。
* 透視投影モデル（Perspective Projection Model）
ピンホールカメラでは上下左右が反転してしまうので、座標系を扱いやすくしたモデルです。
* レンズモデル
レンズを使用して光を集めて焦点を結ぶモデル。広角レンズや望遠レンズなどのレンズの種類によって画像の見え方が変わります。レンズを使用することで、より広範囲な角度から光を集められるため、明るい画像を作ることができます。

### ・透視投影モデル

透視投影モデルでは、位置関係などを以下の図のように表現する。

![PPM.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621879/3033c95a-f3f3-8afc-6a7f-18783b3c77d0.png)

* 光学中心（Optical Center）
光学中心とは、レンズを通過する光が集まる中心点を指します。モデルでは、レンズの中心付近に位置し、すべての光線がこの点を通過して、イメージセンサーやフィルムに焦点を結びます。
* 光軸（Optical Axis）
光軸は、カメラのレンズの中心を通り、レンズの前後に一直線に伸びる仮想的な線です。光学中心を通るこの軸は、カメラの視線に相当するものであり、カメラが向いている方向を示します。画像生成においては、光軸に沿った物体がカメラの正面に映ります。
* 投射面（Image Plane / Projection Plane）
投射面とは、3次元空間の物体が2次元に投影される仮想的な平面を指します。カメラモデルにおいて、投射面はカメラのセンサーやフィルムがある位置を表します。投射面上に投影された像が実際に画像として記録されます。
* 焦点距離（Focal Length）
焦点距離とは、光学中心から投射面までの距離を指します。焦点距離が長いと望遠レンズに近い効果が得られ、遠くの物体が大きく見えます。一方、焦点距離が短いと広角レンズのように、より広い範囲を撮影できます。画像のスケールや遠近感に大きな影響を与える重要なパラメータです。

座標は以下のような三角形の比を使用した数式で表現されます。
```math
\displaylines{x = \frac{f \cdot X}{Z} \\
y = \frac{f \cdot Y}{Z} \\

(X, Y, Z) は3次元空間内の点の座標 \\
f はカメラの焦点距離 \\
(x, y) は2次元の投影平面上の点 \\}
```

Rustで書くと以下のような感じです。
```rust
// 3D座標を表す構造体
struct Point3D {
    x: f64,
    y: f64,
    z: f64,
}

// 2D座標を表す構造体
struct Point2D {
    x: f64,
    y: f64,
}

// 透視投影を行う関数
fn perspective_projection(point: &Point3D, focal_length: f64) -> Point2D {
    // 透視投影の数式
    let projected_x = (focal_length * point.x) / point.z;
    let projected_y = (focal_length * point.y) / point.z;

    // 2D座標として返す
    Point2D {
        x: projected_x,
        y: projected_y,
    }
}

fn main() {
    // 3D座標の例（X = 10, Y = 20, Z = 30 の場合）
    let point_3d = Point3D { x: 10.0, y: 20.0, z: 30.0 };

    // 焦点距離の設定
    let focal_length = 50.0;

    // 透視投影を実行
    let projected_point = perspective_projection(&point_3d, focal_length);

    // 結果の出力
    println!("Projected 2D point: (x: {}, y: {})", projected_point.x, projected_point.y);
}
```

:::note info
浮動小数点で表現すると、整数と比較してビット当たりのStep数が細かいため、表現できる範囲が広がります。そのため、画像処理の分野では浮動小数点が広く使われています。
:::
:::note info
このような座標系はカメラで使用される他にも、3Dを扱ったソフトウェアであるUnityやBlenderなどのソフトでも重要な概念になります。
:::

### ・レンズモデル
実際のカメラではこのレンズモデルが採用されていることがほとんどです。
より広範囲から光を屈折させて画像を作成します。原理上ピント合わせが必要です。

レンズは厚さを無視できるかできないかで特性が変わります。
* 薄肉レンズ
理想的なレンズとして厚さを無視して扱います。このモデルでは、すべての屈折がレンズの中心点（光学中心、主点）で行われると仮定し、単純化された計算が可能になります。薄肉レンズの焦点距離は、レンズの曲率とレンズを通る光の屈折率によって決まります。
![ThinLens.drawio-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621879/ac1d6244-c9ab-2099-d5e9-d7ba3d73ac49.png)
薄肉レンズでは、光源が無限遠点から入る場合ピントが合った画像を結像することができます。しかし、光源が近い場合にはレンズの焦点から離れた部分で結像するため、レンズを離さないとピントが合わない状態になります。
光源が近いを場合を数式で表すと、以下のような関係があります。
```math
\displaylines{ \frac{1}{f} = \frac{1}{a} + \frac{1}{b} \\

fはレンズの焦点距離 \\
aは物体距離（レンズから物体までの距離）\\
bは像距離（レンズから像までの距離）\\}
```
:::note info
直流抵抗の並列接続っぽいね。
:::

Rustで書くと以下のようになります。
```rust
// ガウスのレンズの公式を計算する関数
fn gaussian_lens_formula(object_distance: f64, image_distance: f64) -> f64 {
    // 物体距離と像距離が有効な場合、焦点距離を計算
    let focal_length = 1.0 / ((1.0 / object_distance) + (1.0 / image_distance));
    focal_length
}

fn main() {
    // 例として、物体距離と像距離を設定
    let object_distance = 100.0; // 物体までの距離
    let image_distance = 50.0;   // 像までの距離

    // ガウスのレンズ公式を用いて焦点距離を計算
    let focal_length = gaussian_lens_formula(object_distance, image_distance);

    // 結果を表示
    println!("Focal Length: {:.2} units", focal_length);
}

```


* 厚肉レンズ
厚肉レンズはレンズの厚みを考慮したレンズです。実際のレンズは薄肉レンズのように無視できるほど薄くはなく、レンズの厚さが光の進行に影響を与えるため、屈折がレンズ内の複数の面で発生します。厚肉レンズでは前方と後方で２つの主点があります。さらにそれぞれの主点に前後２つの焦点を持ちます。
![ThickLens.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621879/4216f534-791b-08e1-1455-bf824a63ea94.png)
図では表現していませんが、焦点距離の関係は以下のようになっています。
```math
\displaylines{
\frac{1}{f} = \frac{(n - 1)}{t} \ (\frac{(n - 1) t}{n R_1 R_2} + \frac{1}{R_1} - \frac{1}{R_2}) \\

fはレンズの焦点距離 \\
nはレンズの屈折率 \\
tはレンズの厚さ \\
R_1はレンズの前面の曲率半径 \\
R_2はレンズの後面の曲率半径 \\
}
```

:::note info
ガンダムではミノフスキー粒子が発明されてしまったため、レーダーといった電子的な索敵・通信手段が使えなくなりました。
その結果、光学的な技術が研究されるようになったらしいよ。
:::

### ・歪曲収差(わいきょくしゅうさ)
歪曲収差とは、レンズによって画像が歪んでしまう現象のことを指します。これは、特に広角レンズや望遠レンズで顕著に現れる理論的な結像からのズレの一種で、物体の形が本来の形とは異なる歪みを伴って画像上に現れることを意味します。歪曲収差は、レンズを通過した光線が中心付近ではなく、レンズの周辺部を通過するときに発生しやすい現象です。
歪曲収差には、主に2つの種類があります。
* 樽型収差（Barrel Distortion）
中心部に近い光線が周辺部に向かって拡大されることで、画像全体が「樽」のように膨らんだ形に歪む現象です。広角レンズなどでよく見られ、画像の端が内側に引っ込む形になります。直線的なものが外に膨らんで見えるのが特徴です。 |井| → (井)
広角レンズの特性によって、レンズの周辺部が引き伸ばされてしまうために発生します。
* 糸巻き型収差（Pincushion Distortion）
中心部に近い光線が周辺部に向かって縮小されることで、画像全体が「糸巻き」のように引き伸ばされた形に歪む現象です。望遠レンズでよく見られ、画像の端が外側に引っ張られる形になります。直線的なものが内側に縮むように見えるのが特徴です。 |井| → )井(
望遠レンズでは、レンズの中心部を通る光が収束しすぎて、周辺部分が内側に引っ込んだ形になります。

計算に使用される補正パラメータはレンズ固有の値が使用されます。そのため、カメラのキャリブレーション時に求め、撮影時に補正することになります。

### 周辺光量の低下
周辺光量が低下する現象とは、レンズを通して撮影した画像の中心部に比べて周辺部が暗くなる現象のことです。これは、光学系やレンズの設計に起因する問題で、特に広角レンズや低品質のレンズで顕著に見られることがあります。この現象にはいくつかの要因が関係しています。

* 口径食（Optical Vignetting）
口径食は、レンズの設計そのものに起因するものです。レンズに入射する光の角度が大きくなるほど、光の通過が困難になり、レンズの周辺部に向かう光が十分に集まらないため発生します。特に、レンズの周辺にある光線がレンズを通過する際、光路が歪み、周辺部分の光量が低下します。
* 自然光学ビネット効果（Natural Vignetting）
レンズの設計に基づいた物理的な現象で、光がレンズの周辺に向かうときの入射角度が大きくなることにより、相対的な露光量が減少します。これは、コサインの4乗則に従う現象で、入射光の角度が大きくなると光量が減少するというものです。
光はある点から放射状に広がっていき、広がるとエネルギーは別れるため減衰します。
![Vignetting.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621879/8ccb3b0e-b95e-92dd-a791-6e07bd4b00a9.png)
例えば、上図では光源のエネルギーは同じですが、距離が離れて面積が４倍になった場合、エネルギーが分割されていることになるため、面積1の位置に比べて光量が落ちることになります。
面積のサイズは角度に依存し、キツくなればキツくなるほど減衰率が高くなります。

:::note info
この現象は結構難しい問題となっている印象があります。
例えば、画像の解像度を上げる方法として撮影素子の面積を大きくする方法があります。
しかし、撮影素子を大きくした場合には光源から端の部分までの距離が伸びることになります。
この後説明する画角の話などを踏まえるとレンズと撮影素子の距離は近づけたい場合があるため、極端な話以下のようになってしまいます。
![column.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3621879/a04367aa-4293-278b-0a19-b414010d6f64.png)
このようにハードウェア的な性能は限界に近い状態という噂です。
そのためソフトウェア的に解像度を上げる方法として、超解像が話題になるわけですね。
:::