1

私がやりたいことは、OpenGL Shader のテクスチャのピクセル データにアクセスすることです。その後、最大の赤成分を持つピクセルの座標を取得できるように、それらの赤成分を比較します。CPU の処理能力を備えた Objective C で実行できます。コードを以下に示します。

- (void)processNewPixelBuffer:(CVPixelBufferRef)pixelBuffer
{
    short maxR = 0;
    NSInteger x = -1, y = -1;

    CVPixelBufferLockBaseAddress(pixelBuffer, 0);    
    height = CVPixelBufferGetHeight(pixelBuffer);
    width = CVPixelBufferGetWidth(pixelBuffer);

    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
    uint8_t *src_buff = CVPixelBufferGetBaseAddress(pixelBuffer);

    short** rawData = malloc(sizeof(short*) * height);
    for (int i = 0; i < height; i++){
        rawData[i] = malloc((sizeof(short) * width));
        for (int j = 0; j < width; j++)
            rawData[i][j] = (short)src_buff[(i + width * j) * 4];
    }

    for (int j = 0; j < height; j++)
    for (int i = 0; i < width; i++)
        if (rawData[i][j] >= maxR) {
            maxR = rawData[i][j];
            x = i;
            y = j;
        }

    free(rawData);
}

ですから、私の質問は、GPU を使用してこのプロセスを実行する方法を教えてください。OpenGL Shader で pixelBuffer をテクスチャとして作成できます。

頂点シェーダー

attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

void main()
{
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate.xy;
}

フラグメントシェーダー

varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture; //The input sample, in RGBA format

void main()
{
    // Code here
}

最大の赤成分を持つピクセルを見つけることができるようにシェーダーを変更するにはどうすればよいですか? 次に、そのピクセルを赤に、他のピクセルを白に変えたいと思います。それは可能ですか?

4

1 に答える 1

6

できることは、従来のリダクション シェーダーを使用することです。画面サイズのクワッドを入力テクスチャの半分のサイズのテクスチャ/画面にレンダリングし (FBO を使用するのが最適です)、フラグメント シェーダーで各ピクセルの最大 2x2 テクセル ブロックを計算し、最大値と対応するテクスチャ座標:

//no need for any textrue coords, we render screen-aligned anyway
uniform sampler2D inputImageTexture; //The input sample, in RGBA format
uniform vec2 invImageSize; // (1/width, 1/height)

void main()
{
    vec2 coord = (2.0 * floor(gl_FragCoord.xy) + 0.5) * invImageSize;
    float ll = texture2D(inputImageTexture, coord).r;
    float lr = texture2D(inputImageTexture, coord+vec2(invImageSize, 0.0)).r;
    float ul = texture2D(inputImageTexture, coord+vec2(0.0, invImageSize)).r;
    float ur = texture2D(inputImageTexture, coord+vec2(invImageSize, invImageSize)).r;

    vec4 color = vec4(ll, coord, 1.0);
    if(lr > color.r)
        color.xyz = vec3(lr, coord+vec2(invImageSize, 0.0));
    if(ul > color.r)
        color.xyz = vec3(ul, coord+vec2(0.0, invImageSize));
    if(ur > color.r)
        color.xyz = vec3(ur, coord+vec2(invImageSize, invImageSize));
    gl_FragColor = color;
}

次に、この出力テクスチャを次のステップで入力テクスチャとして使用し、1x1 テクスチャ (または CPU で処理できる小さなテクスチャ) になるまで、再び半分のサイズのテクスチャにレンダリングします。しかしもちろん、2 回目以降のすべてのパスでは、計算されたものではなく、保存されたテクスチャ座標を出力する必要があります。

vec2 coord = (2.0 * floor(gl_FragCoord.xy) + 0.5) * invImageSize;
vec4 ll = texture2D(inputImageTexture, coord);
vec4 lr = texture2D(inputImageTexture, coord+vec2(invImageSize, 0.0));
vec4 ul = texture2D(inputImageTexture, coord+vec2(0.0, invImageSize));
vec4 ur = texture2D(inputImageTexture, coord+vec2(invImageSize, invImageSize));

ll = (lr.r > ll.r) ? lr : ll;
ll = (ul.r > ll.r) ? ul : ll;
ll = (ur.r > ll.r) ? ur : ll;
gl_FragColor = ll;

最終的に赤の部分が最大のテクセル座標 ([0,1] の正規化されたテクスチャ座標として) が得られたら、完全に白いスクリーン/テクスチャ サイズのクワッドと、この位置に単一の赤い点を描画するだけです。しかし、このマルチパス アルゴリズム (タスクの単純さと比較するとかなり面倒です) が、純粋な CPU ソリューションと比較して本当に何かをもたらすとは約束できません。各出力ピクセルのすべての画像のピクセルを魔法のように読み取り、その色を決定する 1 つのパスだけでそれを行うことはできません。これは、フラグメント シェーダーの使用方法 (または使用すべき方法) ではありません。

編集:ところで。おそらく、すべてのデータを CPU ソリューションの追加の一時バッファーにコピーする必要はありません。少なくとも、単一のメモリ ブロック (またはなし大容量メモリの割り当てについては言うまでもありません。そのため、GPU への移行を考える前に、まず CPU ソリューションを修正してください。

于 2012-09-19T08:20:20.057 に答える