GPUImage create a custom Filter that change select

2020-07-23 07:13发布

问题:


Using the amazing GPU image framework, I'm trying to create a custom filter using a custom fragment shader that passed some color vectors as uniforms, elaborate each fragment substituting a choosen color with one in the uniform. I made that using Quartz and it works, but since I'm moving my first step in OpenGL world using this framework, I'd like to give a try to the GPU processing.
The fragment shader I made seems to work fine, but there is a problem in the output. I post just a sample for debugging porpoise

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;


bool compareVectors (lowp vec3 x,lowp vec3 y){
    bool result;
    if (x.r != y.r) {
        return result = false;
    }
    if (x.b != y.b) {
       return result = false;
    }
    if (x.g  != y.g ) {
       return result = false;
    }
    return result = true;
}

void main()
{
    lowp vec3 tc = vec3(0.0, 0.0, 0.0);

    lowp vec4 pixcol = texture2D(inputImageTexture, textureCoordinate).rgba;
    lowp vec3 sampleColors[3];
    lowp vec3 newColors[3];
    sampleColors[0] = vec3(0.2, 0.2, 0.2);
    sampleColors[1] = vec3(0.0, 0.0, 0.0);
    sampleColors[2] = vec3(1.0, 1.0, 1.0);

    newColors[0] = vec3(0.4, 0.4, 1.0);
    newColors[1] = vec3(0.3, 0.4, 1.0);
    newColors[2] = vec3(0.6, 0.7, 0.5);
    if (pixcol.a >= 0.2) {
        if (compareVectors (sampleColors[0],pixcol.rgb))
            tc = newColors[0];
        else if (compareVectors (sampleColors[1],pixcol.rgb))
            tc = newColors[1];
        else if (compareVectors (sampleColors[2],pixcol.rgb))
            tc = newColors[2];
        else
            tc = pixcol.rgb;
    }
    else
        tc = pixcol.rgb;

    gl_FragColor = vec4(tc.rgb, pixcol.a);
}

The resulting image has a lot of artifacts. It seems pixellate on the screen and not well created if written to disk. Here are some screen.

The first image is the starting image, the second is a screenshot of the filtered mage on iphone screen, the third is the filtered image written to disk. Digging into that I remembered that texel and pixel aren't the same thing, so probably I'm not mapping them correctly. I'd like to have a 1:1 position ratio and probably is not happening.
How can I achieve that?
Thanks, Andrea

回答1:

As stated in the comment by Brad, the solution was to simply confront the texel color in a range of values. This is due to the float precision (I'm feeling stupid writing it right now, it was pretty obvious). The starting image was with fixed controlled color, but since the original image is sampled probably the information is not equal from the starting image. Here is the correct fragment shader:

varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;


bool compareVectors (lowp vec3 sample,lowp vec3 texel){
    bool result;
    if ( abs(texel.r-sample.r) > 0.1 ) {
        return result = false;
    }
    if ( abs(texel.g-sample.g) > 0.1 ) {
        return result = false;
    }
    if ( abs(texel.b-sample.b) > 0.1 ) {
        return result = false;
    }

    return result = true;
}

void main()
{
    lowp vec3 tc = vec3(0.0, 0.0, 0.0);

    lowp vec4 pixcol = texture2D(inputImageTexture, textureCoordinate).rgba;
    lowp vec3 sampleColors[3];
    lowp vec3 newColors[3];
    sampleColors[0] = vec3(0.5, 0.5, 0.5);
    sampleColors[1] = vec3(0.0, 0.0, 0.0);
    sampleColors[2] = vec3(1.0, 1.0, 1.0);

    newColors[0] = vec3(0.4, 0.4, 1.0);
    newColors[1] = vec3(0.3, 0.4, 1.0);
    newColors[2] = vec3(0.6, 0.7, 0.5);

    if (pixcol.a >= 0.2) {
        if (compareVectors (sampleColors[0],pixcol.rgb))
            tc = newColors[0];
        else if (compareVectors (sampleColors[1],pixcol.rgb))
            tc = newColors[1];
        else if (compareVectors (sampleColors[2],pixcol.rgb))
            tc = newColors[2];
        else
            tc = pixcol.rgb;
    }
    else
        tc = pixcol.rgb;

    gl_FragColor = vec4(tc.rgb, pixcol.a);
}

I'd like to thanks Brad that found the answer. Hope this helps.