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 18package android.filterpacks.imageproc; 19 20import android.filterfw.core.Filter; 21import android.filterfw.core.FilterContext; 22import android.filterfw.core.Frame; 23import android.filterfw.core.FrameFormat; 24import android.filterfw.core.GenerateFieldPort; 25import android.filterfw.core.Program; 26import android.filterfw.core.ShaderProgram; 27import android.filterfw.format.ImageFormat; 28import android.filterfw.geometry.Quad; 29import android.filterfw.geometry.Point; 30 31/** 32 * @hide 33 */ 34public class StraightenFilter extends Filter { 35 36 @GenerateFieldPort(name = "angle", hasDefault = true) 37 private float mAngle = 0f; 38 39 @GenerateFieldPort(name = "maxAngle", hasDefault = true) 40 private float mMaxAngle = 45f; 41 42 @GenerateFieldPort(name = "tile_size", hasDefault = true) 43 private int mTileSize = 640; 44 45 private Program mProgram; 46 47 private int mWidth = 0; 48 private int mHeight = 0; 49 private int mTarget = FrameFormat.TARGET_UNSPECIFIED; 50 51 private static final float DEGREE_TO_RADIAN = (float) Math.PI / 180.0f; 52 53 public StraightenFilter(String name) { 54 super(name); 55 } 56 57 @Override 58 public void setupPorts() { 59 addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); 60 addOutputBasedOnInput("image", "image"); 61 } 62 63 public void initProgram(FilterContext context, int target) { 64 switch (target) { 65 case FrameFormat.TARGET_GPU: 66 ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); 67 shaderProgram.setMaximumTileSize(mTileSize); 68 mProgram = shaderProgram; 69 break; 70 71 default: 72 throw new RuntimeException("Filter Sharpen does not support frames of " + 73 "target " + target + "!"); 74 } 75 mTarget = target; 76 } 77 78 @Override 79 public void fieldPortValueUpdated(String name, FilterContext context) { 80 if (mProgram != null) { 81 updateParameters(); 82 } 83 } 84 85 @Override 86 public void process(FilterContext context) { 87 // Get input frame 88 Frame input = pullInput("image"); 89 FrameFormat inputFormat = input.getFormat(); 90 91 // Create program if not created already 92 if (mProgram == null || inputFormat.getTarget() != mTarget) { 93 initProgram(context, inputFormat.getTarget()); 94 } 95 96 // Create output frame 97 if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { 98 mWidth = inputFormat.getWidth(); 99 mHeight = inputFormat.getHeight(); 100 updateParameters(); 101 } 102 103 Frame output = context.getFrameManager().newFrame(inputFormat); 104 105 // Process 106 mProgram.process(input, output); 107 108 // Push output 109 pushOutput("image", output); 110 111 // Release pushed frame 112 output.release(); 113 } 114 115 private void updateParameters() { 116 float cosTheta = (float) Math.cos(mAngle * DEGREE_TO_RADIAN); 117 float sinTheta = (float) Math.sin(mAngle * DEGREE_TO_RADIAN); 118 119 if (mMaxAngle <= 0) 120 throw new RuntimeException("Max angle is out of range (0-180)."); 121 mMaxAngle = (mMaxAngle > 90) ? 90 : mMaxAngle; 122 123 Point p0 = new Point(-cosTheta * mWidth + sinTheta * mHeight, 124 -sinTheta * mWidth - cosTheta * mHeight); 125 126 Point p1 = new Point(cosTheta * mWidth + sinTheta * mHeight, 127 sinTheta * mWidth - cosTheta * mHeight); 128 129 Point p2 = new Point(-cosTheta * mWidth - sinTheta * mHeight, 130 -sinTheta * mWidth + cosTheta * mHeight); 131 132 Point p3 = new Point(cosTheta * mWidth - sinTheta * mHeight, 133 sinTheta * mWidth + cosTheta * mHeight); 134 135 float maxWidth = (float) Math.max(Math.abs(p0.x), Math.abs(p1.x)); 136 float maxHeight = (float) Math.max(Math.abs(p0.y), Math.abs(p1.y)); 137 138 float scale = 0.5f * Math.min( mWidth / maxWidth, 139 mHeight / maxHeight); 140 141 p0.set(scale * p0.x / mWidth + 0.5f, scale * p0.y / mHeight + 0.5f); 142 p1.set(scale * p1.x / mWidth + 0.5f, scale * p1.y / mHeight + 0.5f); 143 p2.set(scale * p2.x / mWidth + 0.5f, scale * p2.y / mHeight + 0.5f); 144 p3.set(scale * p3.x / mWidth + 0.5f, scale * p3.y / mHeight + 0.5f); 145 146 Quad quad = new Quad(p0, p1, p2, p3); 147 ((ShaderProgram) mProgram).setSourceRegion(quad); 148 } 149} 150