計算写真とは、計算によって写真プロセスを強化することです。通常、これは最終結果の後処理(写真編集と同様)にのみ当てはまると考える傾向がありますが、シーンの照明から始まり、次のように、写真プロセスのすべてのステップで計算を有効にできるため、可能性ははるかに高くなります。レンズ、そして最終的にはキャプチャされた画像の表示でも。
これは、通常のカメラで達成できることよりもはるかに多くのさまざまな方法で実行できるため、重要です。また、今日最も普及しているタイプのカメラであるモバイルカメラは、より大きな兄弟(DSLR)と比較して特に強力ではありませんが、デバイスで利用可能なコンピューティング能力を利用することで、うまく機能するため、これも重要です。 。
計算によって写真を向上させることができる2つの例を見ていきます。より正確には、より多くのショットを撮り、Pythonを少し使用してそれらを組み合わせるだけで、モバイルカメラハードウェアがそうではない2つの状況で素晴らしい結果が得られることを確認します。本当に輝きます—低照度と高ダイナミックレンジ。
シーンの暗い場所で写真を撮りたいが、カメラの絞り(レンズ)が小さく、露出時間が限られているとします。これは、暗いシーンを考えると、次のような画像を生成する可能性がある携帯電話カメラの典型的な状況です(iPhone 6カメラで撮影)。
コントラストを改善しようとすると、結果は次のようになりますが、これもかなり悪いです。
ネット用のユニットテストツール
何が起こるのですか?このすべてのノイズはどこから来るのですか?
答えは、ノイズはセンサーから来るということです。センサーは、光がセンサーに当たるタイミングと、その光の強さを判断しようとするデバイスです。ただし、暗い場所では、何かを登録するために感度を大幅に上げる必要があります。感度が高いということは、誤検出、つまり単にそこにないフォトンも検出し始めることを意味します。 (補足として、この問題はデバイスだけでなく、私たち人間にも影響します。次に暗い部屋にいるときは、視野に存在するノイズに注意してください。)
イメージングデバイスには常にある程度のノイズが存在します。ただし、信号(有用な情報)の強度が高い場合、ノイズは無視できます(信号対ノイズ比が高い)。信号が弱い場合(暗い場所など)、ノイズが目立ちます(信号対ノイズ比が低い)。
それでも、上記のショットよりも優れたショットを取得するために、カメラのすべての制限があっても、ノイズの問題を克服することができます。
そのためには、時間の経過とともに何が起こるかを考慮する必要があります。信号は同じままですが(同じシーンで、静的であると想定します)、ノイズは完全にランダムになります。つまり、シーンを何度も撮影すると、ノイズのバージョンは異なりますが、有用な情報は同じになります。
したがって、時間をかけて撮影した多くの画像を平均すると、信号に影響を与えずにノイズがキャンセルされます。
次の図は、簡略化された例を示しています。ノイズの影響を受けた信号(三角形)があり、異なるノイズの影響を受けた同じ信号の複数のインスタンスを平均することによって信号を回復しようとしています。
ノイズは単一のインスタンスで信号を完全に歪めるほど強力ですが、平均化するとノイズが徐々に減少し、元の信号が復元されることがわかります。
この原則が画像にどのように適用されるかを見てみましょう。まず、カメラが許容する最大の露出で被写体を複数枚撮影する必要があります。最良の結果を得るには、手動撮影が可能なアプリを使用してください。同じ場所から撮影することが重要です。そのため、(即席の)三脚が役立ちます。
通常、ショット数が多いほど品質が向上しますが、正確な数は状況によって異なります。光の量、カメラの感度などです。適切な範囲は10〜100です。
これらの画像を(可能であれば生の形式で)取得したら、Pythonで読み取って処理できます。
外国為替リスク管理戦略
Pythonでの画像処理に慣れていない場合は、画像がバイト値(0〜255)の2D配列として表されること、つまり、モノクロまたはグレースケールの画像であることに注意してください。カラー画像は、各カラーチャネル(R、G、B)に1つずつ、または垂直位置、水平位置、カラーチャネル(0、1、2)でインデックス付けされた3D配列の3つの画像のセットと考えることができます。 。
2つのライブラリを利用します:NumPy( http://www.numpy.org/ )およびOpenCV( https://opencv.org/ )。 1つ目は、配列の計算を非常に効果的に(驚くほど短いコードで)実行できるようにします。この場合、OpenCVは画像ファイルの読み取り/書き込みを処理しますが、はるかに高性能で、多くの高度なグラフィックス手順を提供します。記事の後半で使用します。
import os import numpy as np import cv2 folder = 'source_folder' # We get all the image files from the source folder files = list([os.path.join(folder, f) for f in os.listdir(folder)]) # We compute the average by adding up the images # Start from an explicitly set as floating point, in order to force the # conversion of the 8-bit values from the images, which would otherwise overflow average = cv2.imread(files[0]).astype(np.float) for file in files[1:]: image = cv2.imread(file) # NumPy adds two images element wise, so pixel by pixel / channel by channel average += image # Divide by count (again each pixel/channel is divided) average /= len(files) # Normalize the image, to spread the pixel intensities across 0..255 # This will brighten the image without losing information output = cv2.normalize(average, None, 0, 255, cv2.NORM_MINMAX) # Save the output cv2.imwrite('output.png', output)
結果(自動コントラストを適用した場合)は、ノイズがなくなったことを示しています。これは、元の画像から大幅に改善されています。
ただし、緑がかったフレームやグリッド状のパターンなど、いくつかの奇妙なアーティファクトがまだあります。今回はランダムノイズではなく、固定パターンノイズです。何が起こった?
繰り返しますが、センサーのせいにすることができます。この場合、センサーのさまざまな部分が光に対してさまざまに反応し、目に見えるパターンが生じることがわかります。これらのパターンのいくつかの要素は規則的であり、おそらくセンサー基板(金属/シリコン)と、それが入射光子をどのように反射/吸収するかに関連しています。白いピクセルなどの他の要素は、単に欠陥のあるセンサーピクセルであり、光に対して過度に敏感または過度に鈍感になる可能性があります。
幸いなことに、このタイプのノイズを取り除く方法もあります。いわゆる ダークフレーム減算 。
そのためには、パターンノイズそのものの画像が必要ですが、これは暗闇を撮影すれば得られます。はい、その通りです。カメラの穴を覆い、最大露光時間とISO値で大量の写真(たとえば100枚)を撮り、上記のように処理します。
多くの黒いフレーム(ランダムノイズのために実際には黒ではない)を平均すると、固定パターンノイズになります。この固定ノイズは一定であると想定できるため、この手順は1回だけ必要です。結果の画像は、将来のすべての低照度ショットで再利用できます。
パターンノイズ(コントラスト調整済み)の右上部分がiPhone6でどのように見えるかを次に示します。
繰り返しになりますが、グリッドのようなテクスチャがあり、白いピクセルが詰まっているように見えます。
このダークフレームノイズの値(average_noise
変数内)を取得したら、正規化する前に、これまでのショットから単純に減算できます。
average -= average_noise output = cv2.normalize(average, None, 0, 255, cv2.NORM_MINMAX) cv2.imwrite('output.png', output)
これが私たちの最後の写真です:
C ++学習プロジェクト
小型(モバイル)カメラのもう1つの制限は、ダイナミックレンジが小さいことです。つまり、細部をキャプチャできる光の強度の範囲はかなり狭いということです。
言い換えれば、カメラはシーンからの光強度の狭い帯域のみをキャプチャすることができます。そのバンドより下の強度は純粋な黒として表示され、その上の強度は純粋な白として表示され、これらの領域から詳細が失われます。
ただし、カメラ(または写真家)が使用できるトリックがあります。それは、センサーに到達する光の総量を効果的に制御するために、露出時間(センサーが光にさらされる時間)を調整することです。特定のシーンに最適な範囲をキャプチャするために、範囲を上下にシフトします。
しかし、これは妥協案です。多くの詳細が最終的な写真になりません。下の2つの画像では、同じシーンが異なる露出時間でキャプチャされています。非常に短い露出(1/1000秒)、中程度の露出(1/50秒)、長い露出(1/4秒)です。
ご覧のとおり、3つの画像のいずれも、利用可能なすべての詳細をキャプチャすることはできません。ランプのフィラメントは最初のショットでのみ表示され、花の詳細の一部は中央または最後のショットで表示されますが、表示されません。どちらも。
良いニュースは、それについて私たちにできることがあるということです。また、Pythonコードを少し使って複数のショットを作成する必要があります。
私たちが採用するアプローチは、彼の論文でその方法を説明しているPaul Debevec etal。の研究に基づいています。 ここに 。この方法は次のように機能します。
まず、同じシーン(静止)の複数のショットが必要ですが、露光時間は異なります。繰り返しになりますが、前の場合と同様に、カメラがまったく動かないようにするために三脚またはサポートが必要です。また、露出時間を制御し、カメラの自動調整を防ぐために、手動撮影アプリ(電話を使用している場合)も必要です。必要なショット数は、画像に存在する強度の範囲(3以上)によって異なります。また、保存したい詳細が少なくとも1つのショットにはっきりと表示されるように、露出時間はその範囲全体に配置する必要があります。
次に、アルゴリズムを使用して、異なる露光時間にわたる同じピクセルの色に基づいてカメラの応答曲線を再構築します。これにより、基本的に、ポイントの実際のシーンの明るさ、露出時間、および対応するピクセルがキャプチャされた画像に持つ値の間のマップを確立できます。 OpenCVライブラリからのDebevecのメソッドの実装を使用します。
# Read all the files with OpenCV files = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg'] images = list([cv2.imread(f) for f in files]) # Compute the exposure times in seconds exposures = np.float32([1. / t for t in [1000, 500, 100, 50, 10]]) # Compute the response curve calibration = cv2.createCalibrateDebevec() response = calibration.process(images, exposures)
応答曲線は次のようになります。
縦軸には、ポイントのシーンの明るさと露出時間の累積効果があり、横軸には、対応するピクセルの値(チャネルあたり0〜255)があります。
この曲線は、逆の操作(プロセスの次のステップ)を実行できるようにします。ピクセル値と露光時間が与えられた場合、シーン内の各ポイントの実際の明るさを計算できます。この明るさの値は放射照度と呼ばれ、センサー領域の単位に当たる光エネルギーの量を測定します。画像データとは異なり、はるかに広い範囲の値(したがって、高ダイナミックレンジ)を反映するため、浮動小数点数を使用して表されます。放射照度画像(HDR画像)を取得したら、それを簡単に保存できます。
# Compute the HDR image merge = cv2.createMergeDebevec() hdr = merge.process(images, exposures, response) # Save it to disk cv2.imwrite('hdr_image.hdr', hdr)
HDRディスプレイ(ますます一般的になっている)を持っている幸運な私たちにとって、この画像をその栄光の中で直接視覚化することが可能かもしれません。残念ながら、HDR標準はまだ初期段階にあるため、そのプロセスはディスプレイごとに多少異なる場合があります。
通常の表示では画像にバイト値(0〜255)チャネルが必要ですが、残りの人にとっては、このデータを引き続き利用できることは朗報です。放射照度マップの豊富さの一部を放棄する必要がありますが、少なくともそれを行う方法を制御できます。
動作する外国為替取引システム
このプロセスは トーンマッピング また、浮動小数点放射照度マップ(値の範囲が広い)を標準のバイト値画像に変換する必要があります。余分な詳細の多くが保持されるように、それを行うためのテクニックがあります。これがどのように機能するかの例を示すために、浮動小数点範囲をバイト値に圧縮する前に、HDRイメージに存在するエッジを強調(シャープ)すると想像してください。これらのエッジを強化すると、低ダイナミックレンジの画像でもエッジ(および暗黙的に提供される詳細)を保持するのに役立ちます。
OpenCVは、Drago、Durand、Mantiuk、Reinhardtなどのこれらのトーンマッピング演算子のセットを提供します。これらの演算子の1つ(Durand)を使用する方法と、それが生成する結果の例を次に示します。
durand = cv2.createTonemapDurand(gamma=2.5) ldr = durand.process(hdr) # Tonemap operators create floating point images with values in the 0..1 range # This is why we multiply the image with 255 before saving cv2.imwrite('durand_image.png', ldr * 255)
Pythonを使用すると、プロセスをさらに制御する必要がある場合に、独自の演算子を作成することもできます。たとえば、これは、値の範囲を8ビットに縮小する前に(自動コントラストステップが続く)、非常に少数のピクセルで表される強度を削除するカスタム演算子で得られた結果です。
ソフトウェア開発者を雇う方法
上記の演算子のコードは次のとおりです。
def countTonemap(hdr, min_fraction=0.0005): counts, ranges = np.histogram(hdr, 256) min_count = min_fraction * hdr.size delta_range = ranges[1] - ranges[0] image = hdr.copy() for i in range(len(counts)): if counts[i] = ranges[i + 1]] -= delta_range ranges -= delta_range return cv2.normalize(image, None, 0, 1, cv2.NORM_MINMAX)
少しのPythonといくつかのサポートライブラリを使用して、最終結果を改善するために物理カメラの限界を押し上げる方法を見てきました。これまでに説明した両方の例では、複数の低品質のショットを使用してより良いものを作成していますが、さまざまな問題や制限に対して他にも多くのアプローチがあります。
多くのカメラ付き携帯電話には、これらの特定の例に対応するストアまたは組み込みのアプリがありますが、これらを手動でプログラムし、得られるより高いレベルの制御と理解を楽しむことは明らかに難しいことではありません。
モバイルデバイスでの画像計算に興味がある場合は、 OpenCVチュートリアル:iOSでMSERを使用したリアルタイムのオブジェクト検出 仲間のApeeScapeerとエリートによる OpenCV開発者 AltaibayarTseveenbayar。
センサーは入射光を電気信号に変換し、電気信号は増幅されてデジタル化されます。その表面はピクセルに分割され、さらにチャネルに分割されます。したがって、センサーは、シーン内のすべてのポイントの赤、緑、青の光の強度に対応する3つの数値を生成します。
画像処理とは、生の画像がセンサーによってキャプチャされた後に、それを強化または変更するために実行される計算ステップを指します。
画像処理は、画像データに数値演算を適用することにより、ソフトウェアで実行されます。最も一般的な画像処理技術には、確かな数学的背景があります。
Pythonは、科学計算に適したプログラミング言語です。 NumPyは、配列に対する数値演算の実行を簡素化するPythonライブラリです。 OpenCVは、画像処理とコンピュータービジョンに焦点を当てた専門図書館です。
暗い場所で露出が制限されている場合、センサーに当たる光エネルギーはごくわずかです。センサーは信号を増幅することで補正しようとしますが、最終的にはそれ自体の電気ノイズも増幅します。
ハイダイナミックレンジ(HDR)写真とは、シーン内の物理的な光の強度をより正確にキャプチャすることです。従来のデジタル写真は、少数の強度レベル(通常は256)しか使用しません。
トーンマッピングは、HDR画像を従来の画像に変換し、ほとんどの詳細を保持して、画像を非HDRディスプレイに表示できるようにする手法です。