Home | History | Annotate | Download | only in imageproc
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.filterpacks.imageproc;
     18 
     19 import android.filterfw.core.Filter;
     20 import android.filterfw.core.FilterContext;
     21 import android.filterfw.core.Frame;
     22 import android.filterfw.core.FrameFormat;
     23 import android.filterfw.core.GenerateFieldPort;
     24 import android.filterfw.core.Program;
     25 import android.filterfw.core.ShaderProgram;
     26 import android.filterfw.format.ImageFormat;
     27 
     28 public class SaturateFilter extends Filter {
     29 
     30     @GenerateFieldPort(name = "scale", hasDefault = true)
     31     private float mScale = 0f;
     32 
     33     @GenerateFieldPort(name = "tile_size", hasDefault = true)
     34     private int mTileSize = 640;
     35 
     36     private Program mBenProgram;
     37     private Program mHerfProgram;
     38     private int mTarget = FrameFormat.TARGET_UNSPECIFIED;
     39 
     40     private final String mBenSaturateShader =
     41             "precision mediump float;\n" +
     42             "uniform sampler2D tex_sampler_0;\n" +
     43             "uniform float scale;\n" +
     44             "uniform float shift;\n" +
     45             "uniform vec3 weights;\n" +
     46             "varying vec2 v_texcoord;\n" +
     47             "void main() {\n" +
     48             "  vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" +
     49             "  float kv = dot(color.rgb, weights) + shift;\n" +
     50             "  vec3 new_color = scale * color.rgb + (1.0 - scale) * kv;\n" +
     51             "  gl_FragColor = vec4(new_color, color.a);\n" +
     52             "}\n";
     53 
     54     private final String mHerfSaturateShader =
     55             "precision mediump float;\n" +
     56             "uniform sampler2D tex_sampler_0;\n" +
     57             "uniform vec3 weights;\n" +
     58             "uniform vec3 exponents;\n" +
     59             "varying vec2 v_texcoord;\n" +
     60             "void main() {\n" +
     61             "  vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" +
     62             "  float de = dot(color.rgb, weights);\n" +
     63             "  float inv_de = 1.0 / de;\n" +
     64             "  vec3 new_color = de * pow(color.rgb * inv_de, exponents);\n" +
     65             "  float max_color = max(max(max(new_color.r, new_color.g), new_color.b), 1.0);\n" +
     66             "  gl_FragColor = vec4(new_color / max_color, color.a);\n" +
     67             "}\n";
     68 
     69 
     70     public SaturateFilter(String name) {
     71         super(name);
     72     }
     73 
     74     @Override
     75     public void setupPorts() {
     76         addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
     77         addOutputBasedOnInput("image", "image");
     78     }
     79 
     80     @Override
     81     public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
     82         return inputFormat;
     83     }
     84 
     85     public void initProgram(FilterContext context, int target) {
     86         switch (target) {
     87             case FrameFormat.TARGET_GPU:
     88                 ShaderProgram shaderProgram = new ShaderProgram(context, mBenSaturateShader);
     89                 shaderProgram.setMaximumTileSize(mTileSize);
     90                 mBenProgram = shaderProgram;
     91 
     92                 shaderProgram = new ShaderProgram(context, mHerfSaturateShader);
     93                 shaderProgram.setMaximumTileSize(mTileSize);
     94                 mHerfProgram = shaderProgram;
     95 
     96                 break;
     97 
     98             default:
     99                 throw new RuntimeException("Filter Sharpen does not support frames of " +
    100                     "target " + target + "!");
    101         }
    102         mTarget = target;
    103     }
    104 
    105     @Override
    106     public void fieldPortValueUpdated(String name, FilterContext context) {
    107         if (mBenProgram != null && mHerfProgram != null) {
    108             updateParameters();
    109         }
    110     }
    111 
    112     @Override
    113     public void process(FilterContext context) {
    114         // Get input frame
    115         Frame input = pullInput("image");
    116         FrameFormat inputFormat = input.getFormat();
    117 
    118         // Create program if not created already
    119         if (mBenProgram == null || inputFormat.getTarget() != mTarget) {
    120             initProgram(context, inputFormat.getTarget());
    121             initParameters();
    122         }
    123 
    124         // Create output frame
    125         Frame output = context.getFrameManager().newFrame(inputFormat);
    126 
    127         // Process
    128         if (mScale > 0.0f) {
    129             mHerfProgram.process(input, output);
    130         } else {
    131             mBenProgram.process(input, output);
    132         }
    133          // Push output
    134         pushOutput("image", output);
    135 
    136         // Release pushed frame
    137         output.release();
    138     }
    139 
    140     private void initParameters() {
    141         float shift = 1.0f / 255.0f;
    142         float weights[] = { 2f/8f, 5f/8f, 1f/8f};
    143 
    144         mBenProgram.setHostValue("weights", weights);
    145         mBenProgram.setHostValue("shift", shift);
    146 
    147         mHerfProgram.setHostValue("weights", weights);
    148 
    149         updateParameters();
    150     }
    151 
    152     private void updateParameters() {
    153 
    154         if (mScale > 0.0f) {
    155             float exponents[] = new float[3];
    156 
    157             exponents[0] = (0.9f * mScale) + 1.0f;
    158             exponents[1] = (2.1f * mScale) + 1.0f;
    159             exponents[2] = (2.7f * mScale) + 1.0f;
    160 
    161             mHerfProgram.setHostValue("exponents", exponents);
    162         } else {
    163             mBenProgram.setHostValue("scale", 1.0f + mScale);
    164         }
    165     }
    166 
    167 }
    168