chrisbatt / AndroidFastImageProcessing

A framework for speeding up image processing on android devices by taking advantage of shaders on the GPU.
MIT License
285 stars 118 forks source link

Can I apply filter from a curve file(.acv) #16

Closed Amlana closed 10 years ago

Amlana commented 10 years ago

Hi Chrisbatt, I want to apply filter from a .acv file. How can i do that?

ghost commented 10 years ago

Hi Amlana, I write class using .acv.

public class GPUImageToneCurveFilter extends MultiInputFilter { private int[] redPart; private int[] greenPart; private int[] bluePart; private int[] splineTexture;

public GPUImageToneCurveFilter() {
    super(2);

}

private void createSplineTexture() {        
    int[] data = new int[256];
    for(int i = 0; i < 256; i++) {
        data[i] = (redPart[i] & 0x000000FF) | ((greenPart[i] << 8) & 0x0000FF00) | ((bluePart[i] << 16) & 0x00FF0000) | 0xFF000000;
    }

    splineTexture = new int[1];
    GLES20.glGenTextures(1, splineTexture, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, splineTexture[0]);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, IntBuffer.wrap(data));
}

@Override
public void destroy() {
    super.destroy();
    if(splineTexture != null && splineTexture[0] != 0) {
        GLES20.glDeleteTextures(1, splineTexture, 0);
        splineTexture = null;
    }
}

@Override
protected String getFragmentShader() {
    return str;
}

String str =  " varying highp vec2 "+VARYING_TEXCOORD+";\n" +
        " uniform sampler2D "+UNIFORM_TEXTURE0+";\n" +
        " uniform sampler2D "+UNIFORM_TEXTUREBASE+1+";\n" +
        "\n" +
        " void main()\n" +
        " {\n" +
        "     lowp vec4 textureColor = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+");\n" +
        "     lowp float redCurveValue = texture2D("+UNIFORM_TEXTUREBASE+1+", vec2(textureColor.r, 0.0)).r;\n" +
        "     lowp float greenCurveValue = texture2D("+UNIFORM_TEXTUREBASE+1+", vec2(textureColor.g, 0.0)).g;\n" +
        "     lowp float blueCurveValue = texture2D("+UNIFORM_TEXTUREBASE+1+", vec2(textureColor.b, 0.0)).b;\n" +
        "\n" +
        "     gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);\n" +
        " }";

private float[] getPreparedSpline(Point[] points) {
    Arrays.sort(points, new Comparator<Point>() {
        @Override
        public int compare(Point lhs, Point rhs) {
            return lhs.x - rhs.x;
        }
    });

    List<Point> spline = getSplineCurve(points);
    // If we have a first point like (0.3, 0) we'll be missing some points at the beginning
    // that should be 0.        
    if(spline.get(0).x > 0) {
        for(int i = spline.get(0).x; i >= 0; i--) {
            spline.add(0, new Point(i,0));
        }
    }

    // Insert points similarly at the end, if necessary.
    if(spline.get(spline.size()-1).x < 255) {
        for(int i = spline.get(spline.size()-1).x; i < 256; i++) {
            spline.add(new Point(i,255));
        }
    }

    // Prepare the spline points.
    float[] preparedSplinePoints = new float[spline.size()];
    for (int i=0; i<spline.size(); i++) 
    {
        Point newPoint = spline.get(i);
        Point origPoint = new Point(newPoint.x, newPoint.x);

        float distance = (float) Math.sqrt(Math.pow((origPoint.x - newPoint.x), 2.0) + Math.pow((origPoint.y - newPoint.y), 2.0));

        if (origPoint.y > newPoint.y) 
        {
            distance = -distance;
        }

        preparedSplinePoints[i] = distance;
    }

    return preparedSplinePoints;
}

private List<Point> getSplineCurve(Point[] points) {
    double[] sdA = secondDerivative(points);

    int n = sdA.length;
    if (n < 1) {
        return null;
    }

    List<Point> output = new ArrayList<Point>(n+1);

    for(int i=0; i<n-1 ; i++) {
        Point cur = points[i];
        Point next = points[(i+1)];

        for(int x=cur.x;x<(int)next.x;x++) {
            double t = (double)(x-cur.x)/(next.x-cur.x);

            double a = 1-t;
            double b = t;
            double h = next.x-cur.x;

            double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sdA[i]+ (b*b*b-b)*sdA[i+1] );

            if (y > 255.0) {
                y = 255.0;   
            } else if (y < 0.0) {
                y = 0.0;   
            }

           output.add(new Point(x,(int)y));
        }
    }

    if(output.size() == 255) {
        output.add(points[points.length-1]);
    }

    return output;
}

@Override
public void newTextureReady(int texture, GLTextureOutputRenderer source, boolean newData) {
    if(filterLocations.size() < 2 || !source.equals(filterLocations.get(0))) {
        clearRegisteredFilterLocations();
        registerFilterLocation(source, 0);
        registerFilterLocation(this, 1);
    }
    if(splineTexture == null || splineTexture[0] == 0) {
        createSplineTexture();
    }
    super.newTextureReady(splineTexture[0], this, newData);
    super.newTextureReady(texture, source, newData);
}

private double[] secondDerivative(Point[] points) {
    int n = points.length;
    if (n <= 1) {
        return null;
    }

    double[][] matrix = new double[n][3];
    double[] result = new double[n];
    matrix[0][1]=1;
    // What about matrix[0][1] and matrix[0][0]? Assuming 0 for now (Brad L.)
    matrix[0][0]=0;    
    matrix[0][2]=0;    

    for(int i=1;i<n-1;i++) {
        Point P1 = points[(i-1)];
        Point P2 = points[i];
        Point P3 = points[(i+1)];

        matrix[i][0]=(double)(P2.x-P1.x)/6;
        matrix[i][1]=(double)(P3.x-P1.x)/3;
        matrix[i][2]=(double)(P3.x-P2.x)/6;
        result[i]=(double)(P3.y-P2.y)/(P3.x-P2.x) - (double)(P2.y-P1.y)/(P2.x-P1.x);
    }

    // What about result[0] and result[n-1]? Assuming 0 for now (Brad L.)
    result[0] = 0;
    result[n-1] = 0;

    matrix[n-1][1]=1;
    // What about matrix[n-1][0] and matrix[n-1][2]? For now, assuming they are 0 (Brad L.)
    matrix[n-1][0]=0;
    matrix[n-1][2]=0;

    // solving pass1 (up->down)
    for(int i=1;i<n;i++) 
    {
        double k = matrix[i][0]/matrix[i-1][1];
        matrix[i][1] -= k*matrix[i-1][2];
        matrix[i][0] = 0;
        result[i] -= k*result[i-1];
    }
    // solving pass2 (down->up)
    for(int i=n-2;i>=0;i--) 
    {
        double k = matrix[i][2]/matrix[i+1][1];
        matrix[i][1] -= k*matrix[i+1][0];
        matrix[i][2] = 0;
        result[i] -= k*result[i+1];
    }

    double[] y2 = new double[n];
    for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];

    return y2;
}
private Point[] mRgbCompositeControlPoints;
private Point[] mRedControlPoints;
private Point[] mGreenControlPoints;
private Point[] mBlueControlPoints;

public void setFromCurveFileInputStream(InputStream input) {
    try {
        int version = readShort(input);
        int totalCurves = readShort(input);

        ArrayList<Point[]> curves = new ArrayList<Point[]>(totalCurves);

// float pointRate = 1.0f / 255;

        for (int i = 0; i < totalCurves; i++) {
            // 2 bytes, Count of points in the curve (short integer from 2...19)
            short pointCount = readShort(input);

            Point[] points = new Point[pointCount];

            // point count * 4
            // Curve points. Each curve point is a pair of short integers where
            // the first number is the output value (vertical coordinate on the
            // Curves dialog graph) and the second is the input value. All coordinates have range 0 to 255.
            for (int j = 0; j < pointCount; j++) {
                short y = readShort(input);
                short x = readShort(input);

                points[j] = new Point(x , y );
            }

            curves.add(points);
        }
        input.close();

        mRgbCompositeControlPoints = curves.get(0);
        mRedControlPoints = curves.get(1);
        mGreenControlPoints = curves.get(2);
        mBlueControlPoints = curves.get(3);

        System.out.println(" RGB = "+mRedControlPoints.length + " ");
        for(int i = 0 ; i < mRgbCompositeControlPoints.length; i++){
            System.out.println("XRBG = "+mRgbCompositeControlPoints[i].x+" || YRGB = "+mRgbCompositeControlPoints[i].y);
        }
        for(int i = 0 ; i < mRedControlPoints.length; i++){
            System.out.println("XRED = "+mRedControlPoints[i].x+" || YRED = "+mRedControlPoints[i].y);
        }
        for(int i = 0 ; i < mGreenControlPoints.length; i++){
            System.out.println("XGR = "+mGreenControlPoints[i].x+" || YGR = "+mGreenControlPoints[i].y);
        }
        for(int i = 0 ; i < mBlueControlPoints.length; i++){
            System.out.println("XBLU = "+mBlueControlPoints[i].x+" || YBLU = "+mBlueControlPoints[i].y);
        }

        float[] redCurve = getPreparedSpline(mRedControlPoints);
        float[] blueCurve = getPreparedSpline(mBlueControlPoints);
        float[] greenCurve = getPreparedSpline(mGreenControlPoints);
        float[] rgbCompositeCurve = getPreparedSpline(mRgbCompositeControlPoints);

        redPart = new int[256];
        greenPart = new int[256];
        bluePart = new int[256];

        for (int i = 0; i < 256; i++) {
            redPart[i] = (int) Math.min(Math.max(i + redCurve[i] + rgbCompositeCurve[i], 0), 255);
            greenPart[i] = (int) Math.min(Math.max(i + greenCurve[i] + rgbCompositeCurve[i], 0), 255);
            bluePart[i] = (int) Math.min(Math.max(i + blueCurve[i] + rgbCompositeCurve[i], 0), 255);
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}

private short readShort(InputStream input) throws IOException {
    return (short) (input.read() << 8 | input.read());
}

}

Using:

InputStream in = getResources().openRawResource(R.raw.autumn2); filter = new GPUImageToneCurveFilter(); ((GPUImageToneCurveFilter) filter).setFromCurveFileInputStream(in);

I hope help you!

Amlana commented 10 years ago

Thanks a lot truongnguyenptit