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 SharpenFilter 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 mProgram;
     37 
     38     private int mWidth = 0;
     39     private int mHeight = 0;
     40     private int mTarget = FrameFormat.TARGET_UNSPECIFIED;
     41 
     42     private final String mSharpenShader =
     43             "precision mediump float;\n" +
     44             "uniform sampler2D tex_sampler_0;\n" +
     45             "uniform float scale;\n" +
     46             "uniform float stepsizeX;\n" +
     47             "uniform float stepsizeY;\n" +
     48             "varying vec2 v_texcoord;\n" +
     49             "void main() {\n" +
     50             "  vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n" +
     51             "  vec2 coord;\n" +
     52             "  vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" +
     53             "  coord.x = v_texcoord.x - 0.5 * stepsizeX;\n" +
     54             "  coord.y = v_texcoord.y - stepsizeY;\n" +
     55             "  nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" +
     56             "  coord.x = v_texcoord.x - stepsizeX;\n" +
     57             "  coord.y = v_texcoord.y + 0.5 * stepsizeY;\n" +
     58             "  nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" +
     59             "  coord.x = v_texcoord.x + stepsizeX;\n" +
     60             "  coord.y = v_texcoord.y - 0.5 * stepsizeY;\n" +
     61             "  nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" +
     62             "  coord.x = v_texcoord.x + stepsizeX;\n" +
     63             "  coord.y = v_texcoord.y + 0.5 * stepsizeY;\n" +
     64             "  nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" +
     65             "  gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n" +
     66             "}\n";
     67 
     68     public SharpenFilter(String name) {
     69         super(name);
     70     }
     71 
     72     @Override
     73     public void setupPorts() {
     74         addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
     75         addOutputBasedOnInput("image", "image");
     76     }
     77 
     78     @Override
     79     public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
     80         return inputFormat;
     81     }
     82 
     83     public void initProgram(FilterContext context, int target) {
     84         switch (target) {
     85             case FrameFormat.TARGET_GPU:
     86                 ShaderProgram shaderProgram = new ShaderProgram(context, mSharpenShader);
     87                 shaderProgram.setMaximumTileSize(mTileSize);
     88                 mProgram = shaderProgram;
     89                 break;
     90 
     91             default:
     92                 throw new RuntimeException("Filter Sharpen does not support frames of " +
     93                     "target " + target + "!");
     94         }
     95         mTarget = target;
     96     }
     97 
     98     @Override
     99     public void process(FilterContext context) {
    100         // Get input frame
    101         Frame input = pullInput("image");
    102         FrameFormat inputFormat = input.getFormat();
    103 
    104         // Create output frame
    105         Frame output = context.getFrameManager().newFrame(inputFormat);
    106 
    107         // Create program if not created already
    108         if (mProgram == null || inputFormat.getTarget() != mTarget) {
    109             initProgram(context, inputFormat.getTarget());
    110         }
    111 
    112         // Check if the frame size has changed
    113         if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) {
    114             updateFrameSize(inputFormat.getWidth(), inputFormat.getHeight());
    115         }
    116 
    117         // Process
    118         mProgram.process(input, output);
    119 
    120         // Push output
    121         pushOutput("image", output);
    122 
    123         // Release pushed frame
    124         output.release();
    125     }
    126 
    127     private void updateFrameSize(int width, int height) {
    128         mWidth = width;
    129         mHeight = height;
    130 
    131         if (mProgram != null) {
    132             mProgram.setHostValue("stepsizeX", 1.0f / mWidth);
    133             mProgram.setHostValue("stepsizeY", 1.0f / mHeight);
    134             updateParameters();
    135         }
    136     }
    137 
    138     private void updateParameters() {
    139         mProgram.setHostValue("scale", mScale);
    140     }
    141 
    142     @Override
    143     public void fieldPortValueUpdated(String name, FilterContext context) {
    144         if (mProgram != null) {
    145             updateParameters();
    146         }
    147     }
    148 }
    149