OpenGL.Shader:志兄はあなたにフィルターの生放送クライアント(5)フィルターの紹介を書くことを教えます:コントラスト、露出、モザイク

11982 ワード

OpenGL.Shader:志兄はあなたにフィルターを書いてクライアントを生中継することを教えます(5)
前章では、nv 21ストリームをレンダリングするときにフィルタのシームレスな切り替えを行う方法について説明しました.この章の内容は前章に続き、コントラスト、露光、モザイクの3つのフィルタの特効を紹介し、フィルタ効果を動的に調整する方法について説明します.くだらないことは言わないで、show the code!
フィルター1:コントラスト
#include "GpuBaseFilter.hpp"
/**
 *         。
 *      0.0 4.0  ,    1.0
 */
class GpuContrastFilter : public GpuBaseFilter {
public:
    int getTypeId() { return FILTER_TYPE_CONTRAST; }

    GpuContrastFilter()
    {
        CONTRAST_FRAGMENT_SHADER  ="precision mediump float;
\ varying highp vec2 textureCoordinate;
\ uniform sampler2D SamplerRGB;
\ uniform sampler2D SamplerY;
\ uniform sampler2D SamplerU;
\ uniform sampler2D SamplerV;
\ uniform lowp float contrast;
\ mat3 colorConversionMatrix = mat3(
\ 1.0, 1.0, 1.0,
\ 0.0, -0.39465, 2.03211,
\ 1.13983, -0.58060, 0.0);
\ vec3 yuv2rgb(vec2 pos)
\ {
\ vec3 yuv;
\ yuv.x = texture2D(SamplerY, pos).r;
\ yuv.y = texture2D(SamplerU, pos).r - 0.5;
\ yuv.z = texture2D(SamplerV, pos).r - 0.5;
\ return colorConversionMatrix * yuv;
\ }
\ void main()
\ {
\ vec4 textureColor = vec4(yuv2rgb(textureCoordinate), 1.0);
\ gl_FragColor = vec4((contrast*(textureColor.rgb - vec3(0.5)) + vec3(0.5)), textureColor.w);
\ }"; } ~GpuContrastFilter() { if(!CONTRAST_FRAGMENT_SHADER.empty()) CONTRAST_FRAGMENT_SHADER.clear(); } void init() { GpuBaseFilter::init(NO_FILTER_VERTEX_SHADER.c_str(), CONTRAST_FRAGMENT_SHADER.c_str()); mContrastLocation = glGetUniformLocation(mGLProgId, "contrast"); mContrastValue = 1.0f; } void setAdjustEffect(float percent) { mContrastValue = percent * 4.0f; } // ( 0~4) void onDraw(GLuint SamplerY_texId, GLuint SamplerU_texId, GLuint SamplerV_texId, void* positionCords, void* textureCords) { // ...} private: std::string CONTRAST_FRAGMENT_SHADER; GLint mContrastLocation; float mContrastValue; };

頂点シェーダはベースクラスGpuBaseFilterを使用します.NO_FILTER_VERTEX_SHADER、1波のメタシェーダを分析して、コントラストの原理を発見するのは難しくありません:
gl_FragColor = vec4((contrast*(textureColor.rgb - vec3(0.5)) + vec3(0.5)), textureColor.w);

textureColor.rgb−vec 3(0.5)は二分整列に用いられ、量子化と理解される.contrastはコントラスト因子である.コントラストを乗算して、異なる色の値のレベル範囲を拡大します.(経験範囲は0~4に抑える)
明らかにこのcontrastは動的に調整できるので、前章の内容の設計方法を思い出して、GpuFilterRenderでsetAdjustEffect(float percent)を追跡しても、renderOnDrawで呼び出されていることを発見するのは難しくありません.一部のコードは以下の通りです.
void GpuFilterRender::renderOnDraw(double elpasedInMilliSec)
{
        //     
        mWindowSurface->makeCurrent();
        yTextureId = updateTexture(dst_y, yTextureId, mFrameWidth, mFrameHeight);
        uTextureId = updateTexture(dst_u, uTextureId, mFrameWidth/2, mFrameHeight/2);
        vTextureId = updateTexture(dst_v, vTextureId, mFrameWidth/2, mFrameHeight/2);
        //     Filter
        checkFilterChange();
        if( mFilter!=NULL) {
            mFilter->setAdjustEffect(mFilterEffectPercent);
            mFilter->onDraw(yTextureId, uTextureId, vTextureId, positionCords, textureCords);
        }
        // ...    
}
void GpuFilterRender::adjustFilterValue(int value, int max) {
    mFilterEffectPercent = (float)value / (float)max;
    //LOGD("GpuFilterRender adjust %f", mFilterEffectPercent);
}
///////////////gpu_filter_jni//////////////////////////////////
JNIEXPORT void JNICALL
Java_org_zzrblog_gpufilter_GpuFilterRender_adjustFilterValue(JNIEnv *env, jobject instance, jint value, jint max) {
    if (render == NULL)
        render = new GpuFilterRender();
    render->adjustFilterValue(value, max);
}

トレースを続けると、ActivityによってSeekbarが呼び出され、CfeSchedulerが呼び出されることがわかります.adjustFilterValue(value,max)は、最後にコントラスト係数contrastを動的に調整し、以下の効果を得た.
 
フィルタ2:露出(白黒反転)
#include "GpuBaseFilter.hpp"
/**
 *           。
 */
class GpuColorInvertFilter : public GpuBaseFilter {
public:
    int getTypeId() { return FILTER_TYPE_COLOR_INVERT; }

    GpuColorInvertFilter()
    {
        COLOR_INVERT_FRAGMENT_SHADER="precision mediump float;
\ varying highp vec2 textureCoordinate;
\ uniform sampler2D SamplerRGB;
\ uniform sampler2D SamplerY;
\ uniform sampler2D SamplerU;
\ uniform sampler2D SamplerV;
\ mat3 colorConversionMatrix = mat3(
\ 1.0, 1.0, 1.0,
\ 0.0, -0.39465, 2.03211,
\ 1.13983, -0.58060, 0.0);
\ vec3 yuv2rgb(vec2 pos)
\ {
\ vec3 yuv;
\ yuv.x = texture2D(SamplerY, pos).r;
\ yuv.y = texture2D(SamplerU, pos).r - 0.5;
\ yuv.z = texture2D(SamplerV, pos).r - 0.5;
\ return colorConversionMatrix * yuv;
\ }
\ void main()
\ {
\ vec4 textureColor = vec4(yuv2rgb(textureCoordinate), 1.0);
\ gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
\ }"; } ~GpuColorInvertFilter() { if(!COLOR_INVERT_FRAGMENT_SHADER.empty()) COLOR_INVERT_FRAGMENT_SHADER.clear(); } void init() { GpuBaseFilter::init(NO_FILTER_VERTEX_SHADER.c_str(), COLOR_INVERT_FRAGMENT_SHADER.c_str()); } private: std::string COLOR_INVERT_FRAGMENT_SHADER; };

頂点シェーダはベースクラスGpuBaseFilterのままです.NO_FILTER_VERTEX_SHADER、1波のメタシェーダを分析して、露光の原理を発見するのは難しくありません:
gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w); 

実は反逆ですね.しかもダイナミック調整は不要、so easy(個_個)
前の効果図の意味:
 
 
フィルター3:モザイク
最后の1つも最も面白い1つのフィルターの効果で、各位の古い运転手は最も嫌いな1つかもしれません(斜め目笑.jpg)
#include "GpuBaseFilter.hpp"
/**
 *           。
 */
class GpuPixelationFilter : public GpuBaseFilter {
public:
    int getTypeId() { return FILTER_TYPE_PIXELATION; }

    GpuPixelationFilter()
    {
        PIXELATION_FRAGMENT_SHADER="precision highp float;
\ varying highp vec2 textureCoordinate;
\ uniform sampler2D SamplerRGB;
\ uniform sampler2D SamplerY;
\ uniform sampler2D SamplerU;
\ uniform sampler2D SamplerV;
\ mat3 colorConversionMatrix = mat3(
\ 1.0, 1.0, 1.0,
\ 0.0, -0.39465, 2.03211,
\ 1.13983, -0.58060, 0.0);
\ uniform float imageWidthFactor;
\ uniform float imageHeightFactor;
\ uniform float pixel;
\ vec3 yuv2rgb(vec2 pos)
\ {
\ vec3 yuv;
\ yuv.x = texture2D(SamplerY, pos).r;
\ yuv.y = texture2D(SamplerU, pos).r-0.5;
\ yuv.z = texture2D(SamplerV, pos).r-0.5;
\ return colorConversionMatrix * yuv;
\ }
\ void main()
\ {
\ vec2 uv = textureCoordinate.xy;
\ float dx = pixel * imageWidthFactor;
\ float dy = pixel * imageHeightFactor;
\ vec2 coord = vec2(dx*floor(uv.x / dx), dy*floor(uv.y / dy));
\ gl_FragColor = vec4(yuv2rgb(coord), 1.0);
\ }"; } ~GpuPixelationFilter() { if(!PIXELATION_FRAGMENT_SHADER.empty()) PIXELATION_FRAGMENT_SHADER.clear(); } void init() { GpuBaseFilter::init(NO_FILTER_VERTEX_SHADER.c_str(), PIXELATION_FRAGMENT_SHADER.c_str()); mPixelLocation = glGetUniformLocation(mGLProgId, "pixel"); mImageWidthFactorLocation = glGetUniformLocation(mGLProgId, "imageWidthFactor"); mImageHeightFactorLocation = glGetUniformLocation(mGLProgId, "imageHeightFactor"); mPixelValue = 1.0f; } void setAdjustEffect(float percent) { if(percent==0.0f) percent=0.01f; mPixelValue = percent * 100.0f; } void onOutputSizeChanged(int width, int height) { GpuBaseFilter::onOutputSizeChanged(width, height); glUniform1f(mImageWidthFactorLocation, 1.0f / width); glUniform1f(mImageHeightFactorLocation, 1.0f / height); } // ... void onDraw(GLuint SamplerY_texId, GLuint SamplerU_texId, GLuint SamplerV_texId, void* positionCords, void* textureCords) { if (!mIsInitialized) return; glUseProgram(mGLProgId); glUniform1f(mPixelLocation, mPixelValue); glUniform1f(mImageWidthFactorLocation, 1.0f / mOutputWidth); glUniform1f(mImageHeightFactorLocation, 1.0f / mOutputHeight); // , } };

内容が少し多いので、一緒に分析してみましょう.
uniform float imageWidthFactor; //         ,        1/10
uniform float imageHeightFactor; 
uniform float pixel; //     

void main()
{
    vec2 uv  = textureCoordinate.xy; //       
    float dx = pixel * imageWidthFactor;  //       ,    
    float dy = pixel * imageHeightFactor;
    // floor(uv.x / dx)“    ”,       ,  720*1280,widthFacetor=72
    // uv.x = 1,pixel = 1,     72*(floor(1/72)) = 0
    // uv.x = 2,pixel = 1,     72*(floor(2/72)) = 0
    // uv.x = 71,pixel = 1,     72*(floor(71/72)) = 0
    // uv.x = 72,pixel = 1,     72*(floor(72/72)) = 72
    //      ,    ,               ,                      。
    vec2 coord = vec2(dx*floor(uv.x / dx), dy*floor(uv.y / dy));
    gl_FragColor = vec4(yuv2rgb(coord), 1.0);
}";

分析が終わったら、効果図を見てみましょう.
       
プロジェクトのアドレス:https://github.com/MrZhaozhirong/NativeCppAppshaderセットはsrcmaincppgpufilterfilterに配置