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