StackOverflow の他の場所で、深度バッファ ヒストグラムに関する質問がありました - GLSL で深度バッファ ヒストグラム テクスチャを作成します。
私は iOS 画像処理アプリを作成しており、この質問に興味をそそられていますが、提供された回答は不明です。では、GLSL経由でGPUを使用して画像ヒストグラムを作成することは可能ですか?
StackOverflow の他の場所で、深度バッファ ヒストグラムに関する質問がありました - GLSL で深度バッファ ヒストグラム テクスチャを作成します。
私は iOS 画像処理アプリを作成しており、この質問に興味をそそられていますが、提供された回答は不明です。では、GLSL経由でGPUを使用して画像ヒストグラムを作成することは可能ですか?
はい、ありますが、iOS では思ったよりも少し難しくなります。これは、GPU で完全に生成およびプロットされた赤いヒストグラムで、ライブ ビデオ フィードに対して実行されます。
リンクする質問でのTommyの提案は、 ScheuermannとHensleyによるこの論文と同様に、素晴らしい出発点です。提案されているのは、散乱を使用して画像内のカラー チャネルのヒストグラムを作成することです。散乱は、点のグリッドを頂点シェーダーに渡し、そのシェーダーにその点の色を読み取らせるプロセスです。その時点での目的のカラー チャネルの値は、X 座標として書き出されます (Y 座標と Z 座標は 0 です)。次に、フラグメント シェーダーは、ターゲット内のその座標に、幅 1 ピクセルの半透明のポイントを描画します。
そのターゲットは、高さ 1 ピクセル、幅 256 ピクセルの画像で、各幅位置が 1 つのカラー ビンを表します。低いアルファ チャネル (または低い RGB 値) でポイントを書き出してから加法ブレンドを使用すると、画像内で特定のカラー値が発生する回数に基づいて、各ビンにより高い値を蓄積できます。これらのヒストグラム ピクセルは、後で処理するために読み取ることができます。
iOS のシェーダーでこれを行う際の主な問題は、反対の報告があるにもかかわらず、Apple が、頂点シェーダーでのテクスチャ読み取りは iOS では機能しないと明確に述べていることです。すべての iOS 5.0 デバイスでこれを試しましたが、どのデバイスも頂点シェーダーでテクスチャの読み取りを実行できませんでした (画面が真っ暗になり、GL エラーは発生しませんでした)。
これを回避するには、入力画像の生のピクセルを (glReadPixels()
またはより高速なテクスチャ キャッシュ経由で) 読み取り、それらのバイトを GL_UNSIGNED_BYTE 型の頂点データとして渡すことができることを発見しました。次のコードはこれを実現します。
glReadPixels(0, 0, inputTextureSize.width, inputTextureSize.height, GL_RGBA, GL_UNSIGNED_BYTE, vertexSamplingCoordinates);
[self setFilterFBO];
[filterProgram use];
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
glVertexAttribPointer(filterPositionAttribute, 4, GL_UNSIGNED_BYTE, 0, (_downsamplingFactor - 1) * 4, vertexSamplingCoordinates);
glDrawArrays(GL_POINTS, 0, inputTextureSize.width * inputTextureSize.height / (CGFloat)_downsamplingFactor);
glDisable(GL_BLEND);
上記のコードでは、ストライドを使用して画像ピクセルの一部のみをサンプリングしていることに気付くでしょう。これは、書き出すことができる最低の不透明度またはグレースケール レベルが 1/256 であるためです。つまり、その画像の 255 を超えるピクセルがその色の値を持つと、各ビンが最大になります。したがって、ヒストグラムの範囲をこの限られたウィンドウ内に収めるために、処理するピクセル数を減らす必要がありました。このダイナミックレンジを拡張する方法を探しています。
これを行うために使用されるシェーダーは次のとおりです。頂点シェーダーから始めます。
attribute vec4 position;
void main()
{
gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0);
gl_PointSize = 1.0;
}
そしてフラグメントシェーダーで仕上げます:
uniform highp float scalingFactor;
void main()
{
gl_FragColor = vec4(scalingFactor);
}
これの実用的な実装は、私のオープン ソースGPUImageフレームワークにあります。FilterShowcase の例を取得して実行し、ヒストグラムの分析とプロットを自分で確認してください。
この実装にはいくつかのパフォーマンス上の問題がありますが、これが iOS の GPU でこれを行う唯一の方法でした。私は他の提案を受け入れます。
はい、そうです。これは明らかに最善のアプローチではありませんが、OpenCLがサポートされていないため、iOSで利用できる最善のアプローチです。エレガンスが失われ、コードはおそらくそれほど単純ではありませんが、ほとんどすべてのOpenCL機能はシェーダーを使用して実現できます。
それが役立つ場合、DirectX11には計算シェーダーのFFTの例が付属しています。DX11AugustSDKリリースノートを参照してください。