16570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin/* 26570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * Copyright (C) 2011 The Android Open Source Project 36570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * 46570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * Licensed under the Apache License, Version 2.0 (the "License"); 56570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * you may not use this file except in compliance with the License. 66570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * You may obtain a copy of the License at 76570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * 86570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * http://www.apache.org/licenses/LICENSE-2.0 96570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * 106570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * Unless required by applicable law or agreed to in writing, software 116570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * distributed under the License is distributed on an "AS IS" BASIS, 126570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * See the License for the specific language governing permissions and 146570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * limitations under the License. 156570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin */ 166570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 176570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 186570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linpackage android.filterpacks.imageproc; 196570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 206570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.Filter; 216570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.FilterContext; 226570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.Frame; 236570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.FrameFormat; 246570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.GenerateFieldPort; 256570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.KeyValueMap; 266570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.MutableFrameFormat; 276570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.NativeProgram; 286570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.NativeFrame; 296570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.Program; 306570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.core.ShaderProgram; 316570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.format.ImageFormat; 326570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.geometry.Quad; 336570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.filterfw.geometry.Point; 346570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linimport android.util.Log; 356570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 366570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin/** 376570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin * @hide 386570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin */ 396570ec1c3edb8071446791001872d8ba87659200Ruei-sung Linpublic class StraightenFilter extends Filter { 406570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 41ebdfce054988de002387c0bcedde7fda8a4f0eb0Marius Renn @GenerateFieldPort(name = "angle", hasDefault = true) 42ebdfce054988de002387c0bcedde7fda8a4f0eb0Marius Renn private float mAngle = 0f; 436570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 44ebdfce054988de002387c0bcedde7fda8a4f0eb0Marius Renn @GenerateFieldPort(name = "maxAngle", hasDefault = true) 45ebdfce054988de002387c0bcedde7fda8a4f0eb0Marius Renn private float mMaxAngle = 45f; 466570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 476570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin @GenerateFieldPort(name = "tile_size", hasDefault = true) 486570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private int mTileSize = 640; 496570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 506570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private Program mProgram; 516570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 526570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private int mWidth = 0; 536570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private int mHeight = 0; 546570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private int mTarget = FrameFormat.TARGET_UNSPECIFIED; 556570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 566570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private static final float DEGREE_TO_RADIAN = (float) Math.PI / 180.0f; 576570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 586570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin public StraightenFilter(String name) { 596570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin super(name); 606570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 616570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 626570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin @Override 636570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin public void setupPorts() { 646570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); 656570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin addOutputBasedOnInput("image", "image"); 666570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 676570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 686570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin public void initProgram(FilterContext context, int target) { 696570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin switch (target) { 706570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin case FrameFormat.TARGET_GPU: 716570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); 726570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin shaderProgram.setMaximumTileSize(mTileSize); 736570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mProgram = shaderProgram; 746570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin break; 756570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 766570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin default: 776570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin throw new RuntimeException("Filter Sharpen does not support frames of " + 786570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin "target " + target + "!"); 796570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 806570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mTarget = target; 816570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 826570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 836570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin @Override 846570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin public void fieldPortValueUpdated(String name, FilterContext context) { 856570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin if (mProgram != null) { 866570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin updateParameters(); 876570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 886570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 896570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 906570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin @Override 916570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin public void process(FilterContext context) { 926570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin // Get input frame 936570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Frame input = pullInput("image"); 946570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin FrameFormat inputFormat = input.getFormat(); 956570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 966570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin // Create program if not created already 976570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin if (mProgram == null || inputFormat.getTarget() != mTarget) { 986570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin initProgram(context, inputFormat.getTarget()); 996570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 1006570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1016570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin // Create output frame 1026570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { 1036570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mWidth = inputFormat.getWidth(); 1046570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mHeight = inputFormat.getHeight(); 1056570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin updateParameters(); 1066570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 1076570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1086570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Frame output = context.getFrameManager().newFrame(inputFormat); 1096570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1106570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin // Process 1116570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mProgram.process(input, output); 1126570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1136570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin // Push output 1146570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin pushOutput("image", output); 1156570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1166570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin // Release pushed frame 1176570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin output.release(); 1186570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 1196570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1206570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin private void updateParameters() { 1216570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin float cosTheta = (float) Math.cos(mAngle * DEGREE_TO_RADIAN); 1226570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin float sinTheta = (float) Math.sin(mAngle * DEGREE_TO_RADIAN); 1236570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1246570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin if (mMaxAngle <= 0) 1256570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin throw new RuntimeException("Max angle is out of range (0-180)."); 1266570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mMaxAngle = (mMaxAngle > 90) ? 90 : mMaxAngle; 1276570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1286570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Point p0 = new Point(-cosTheta * mWidth + sinTheta * mHeight, 1296570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin -sinTheta * mWidth - cosTheta * mHeight); 1306570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1316570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Point p1 = new Point(cosTheta * mWidth + sinTheta * mHeight, 1326570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin sinTheta * mWidth - cosTheta * mHeight); 1336570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1346570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Point p2 = new Point(-cosTheta * mWidth - sinTheta * mHeight, 1356570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin -sinTheta * mWidth + cosTheta * mHeight); 1366570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1376570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Point p3 = new Point(cosTheta * mWidth - sinTheta * mHeight, 1386570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin sinTheta * mWidth + cosTheta * mHeight); 1396570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1406570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin float maxWidth = (float) Math.max(Math.abs(p0.x), Math.abs(p1.x)); 1416570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin float maxHeight = (float) Math.max(Math.abs(p0.y), Math.abs(p1.y)); 1426570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1436570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin float scale = 0.5f * Math.min( mWidth / maxWidth, 1446570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin mHeight / maxHeight); 1456570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1466570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin p0.set(scale * p0.x / mWidth + 0.5f, scale * p0.y / mHeight + 0.5f); 1476570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin p1.set(scale * p1.x / mWidth + 0.5f, scale * p1.y / mHeight + 0.5f); 1486570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin p2.set(scale * p2.x / mWidth + 0.5f, scale * p2.y / mHeight + 0.5f); 1496570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin p3.set(scale * p3.x / mWidth + 0.5f, scale * p3.y / mHeight + 0.5f); 1506570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin 1516570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin Quad quad = new Quad(p0, p1, p2, p3); 1526570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin ((ShaderProgram) mProgram).setSourceRegion(quad); 1536570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin } 1546570ec1c3edb8071446791001872d8ba87659200Ruei-sung Lin} 155