diff --git a/gradle.properties b/gradle.properties index a62b69f2f..d7da100b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ VERSION_NAME=1.2.3 VERSION_CODE=8 GROUP=jp.co.cyberagent.android.gpuimage -COMPILE_SDK_VERSION=21 -BUILD_TOOLS_VERSION=21.1.2 -TARGET_SDK_VERSION=21 +COMPILE_SDK_VERSION=22 +BUILD_TOOLS_VERSION=22.0.1 +TARGET_SDK_VERSION=22 MIN_SDK_VERSION=8 POM_DESCRIPTION=Image filters for Android with OpenGL (based on GPUImage for iOS) diff --git a/library/src/jp/co/cyberagent/android/gpuimage/GPUImageBilateralFilter.java b/library/src/jp/co/cyberagent/android/gpuimage/GPUImageBilateralFilter.java new file mode 100644 index 000000000..275253abc --- /dev/null +++ b/library/src/jp/co/cyberagent/android/gpuimage/GPUImageBilateralFilter.java @@ -0,0 +1,155 @@ +/** + * @author wysaid + * @mail admin@wysaid.org + * +*/ + +package jp.co.cyberagent.android.gpuimage; + +import android.opengl.GLES20; + + +public class GPUImageBilateralFilter extends GPUImageFilter { + public static final String BILATERAL_VERTEX_SHADER = "" + + "attribute vec4 position;\n" + + "attribute vec4 inputTextureCoordinate;\n" + + + "const int GAUSSIAN_SAMPLES = 9;\n" + + + "uniform vec2 singleStepOffset;\n" + + + "varying vec2 textureCoordinate;\n" + + "varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];\n" + + + "void main()\n" + + "{\n" + + " gl_Position = position;\n" + + " textureCoordinate = inputTextureCoordinate.xy;\n" + + + " int multiplier = 0;\n" + + " vec2 blurStep;\n" + + + " for (int i = 0; i < GAUSSIAN_SAMPLES; i++)\n" + + " {\n" + + " multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));\n" + + + " blurStep = float(multiplier) * singleStepOffset;\n" + + " blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;\n" + + " }\n" + + "}"; + + public static final String BILATERAL_FRAGMENT_SHADER = "" + + "uniform sampler2D inputImageTexture;\n" + + + " const lowp int GAUSSIAN_SAMPLES = 9;\n" + + + " varying highp vec2 textureCoordinate;\n" + + " varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];\n" + + + " uniform mediump float distanceNormalizationFactor;\n" + + + " void main()\n" + + " {\n" + + " lowp vec4 centralColor;\n" + + " lowp float gaussianWeightTotal;\n" + + " lowp vec4 sum;\n" + + " lowp vec4 sampleColor;\n" + + " lowp float distanceFromCentralColor;\n" + + " lowp float gaussianWeight;\n" + + " \n" + + " centralColor = texture2D(inputImageTexture, blurCoordinates[4]);\n" + + " gaussianWeightTotal = 0.18;\n" + + " sum = centralColor * 0.18;\n" + + " \n" + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[0]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[1]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[2]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[3]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[5]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[6]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[7]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + + " sampleColor = texture2D(inputImageTexture, blurCoordinates[8]);\n" + + " distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\n" + + " gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);\n" + + " gaussianWeightTotal += gaussianWeight;\n" + + " sum += sampleColor * gaussianWeight;\n" + + " gl_FragColor = sum / gaussianWeightTotal;\n" + +// " gl_FragColor.r = distanceNormalizationFactor / 20.0;" + + " }"; + + private float mDistanceNormalizationFactor; + private int mDisFactorLocation; + private int mSingleStepOffsetLocation; + + public GPUImageBilateralFilter() { + this(8.0f); + } + + public GPUImageBilateralFilter(final float distanceNormalizationFactor) { + super(BILATERAL_VERTEX_SHADER, BILATERAL_FRAGMENT_SHADER); + mDistanceNormalizationFactor = distanceNormalizationFactor; + } + + @Override + public void onInit() { + super.onInit(); + mDisFactorLocation = GLES20.glGetUniformLocation(getProgram(), "distanceNormalizationFactor"); + mSingleStepOffsetLocation = GLES20.glGetUniformLocation(getProgram(), "singleStepOffset"); + } + + @Override + public void onInitialized() { + super.onInitialized(); + setDistanceNormalizationFactor(mDistanceNormalizationFactor); + } + + public void setDistanceNormalizationFactor(final float newValue) { + mDistanceNormalizationFactor = newValue; + setFloat(mDisFactorLocation, newValue); + } + + private void setTexelSize(final float w, final float h) { + setFloatVec2(mSingleStepOffsetLocation, new float[] {1.0f / w, 1.0f / h}); + } + + @Override + public void onOutputSizeChanged(final int width, final int height) { + super.onOutputSizeChanged(width, height); + setTexelSize(width, height); + } +} diff --git a/library/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java b/library/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java index 45317a138..ac23f5990 100644 --- a/library/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java +++ b/library/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java @@ -194,6 +194,7 @@ private void convertToBitmap() { mGL.glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, ib); int[] ia = ib.array(); + //Stupid ! // Convert upside down mirror-reversed image to right-side up normal // image. for (int i = 0; i < mHeight; i++) { diff --git a/sample/src/jp/co/cyberagent/android/gpuimage/sample/GPUImageFilterTools.java b/sample/src/jp/co/cyberagent/android/gpuimage/sample/GPUImageFilterTools.java index e344fd238..db691c7f8 100644 --- a/sample/src/jp/co/cyberagent/android/gpuimage/sample/GPUImageFilterTools.java +++ b/sample/src/jp/co/cyberagent/android/gpuimage/sample/GPUImageFilterTools.java @@ -106,6 +106,9 @@ public static void showDialog(final Context context, filters.addFilter("Levels Min (Mid Adjust)", FilterType.LEVELS_FILTER_MIN); + filters. addFilter("Bilateral Blur", FilterType.BILATERAL_BLUR); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("Choose a filter"); builder.setItems(filters.names.toArray(new String[filters.names.size()]), @@ -287,6 +290,9 @@ private static GPUImageFilter createFilterForType(final Context context, final F levelsFilter.setMin(0.0f, 3.0f, 1.0f); return levelsFilter; + case BILATERAL_BLUR: + return new GPUImageBilateralFilter(); + default: throw new IllegalStateException("No filter of that type!"); } @@ -314,7 +320,7 @@ private enum FilterType { BLEND_DISSOLVE, BLEND_EXCLUSION, BLEND_SOURCE_OVER, BLEND_HARD_LIGHT, BLEND_LIGHTEN, BLEND_ADD, BLEND_DIVIDE, BLEND_MULTIPLY, BLEND_OVERLAY, BLEND_SCREEN, BLEND_ALPHA, BLEND_COLOR, BLEND_HUE, BLEND_SATURATION, BLEND_LUMINOSITY, BLEND_LINEAR_BURN, BLEND_SOFT_LIGHT, BLEND_SUBTRACT, BLEND_CHROMA_KEY, BLEND_NORMAL, LOOKUP_AMATORKA, GAUSSIAN_BLUR, CROSSHATCH, BOX_BLUR, CGA_COLORSPACE, DILATION, KUWAHARA, RGB_DILATION, SKETCH, TOON, SMOOTH_TOON, BULGE_DISTORTION, GLASS_SPHERE, HAZE, LAPLACIAN, NON_MAXIMUM_SUPPRESSION, - SPHERE_REFRACTION, SWIRL, WEAK_PIXEL_INCLUSION, FALSE_COLOR, COLOR_BALANCE, LEVELS_FILTER_MIN + SPHERE_REFRACTION, SWIRL, WEAK_PIXEL_INCLUSION, FALSE_COLOR, COLOR_BALANCE, LEVELS_FILTER_MIN, BILATERAL_BLUR } private static class FilterList { @@ -389,7 +395,11 @@ public FilterAdjuster(final GPUImageFilter filter) { adjuster = new ColorBalanceAdjuster().filter(filter); } else if (filter instanceof GPUImageLevelsFilter) { adjuster = new LevelsMinMidAdjuster().filter(filter); - } else { + } else if (filter instanceof GPUImageBilateralFilter) { + adjuster = new BilateralAdjuster().filter(filter); + } + else { + adjuster = null; } } @@ -643,5 +653,13 @@ public void adjust(int percentage) { getFilter().setMin(0.0f, range(percentage, 0.0f, 1.0f) , 1.0f); } } + + private class BilateralAdjuster extends Adjuster { + @Override + public void adjust(final int percentage) { + getFilter().setDistanceNormalizationFactor(range(percentage, 0.0f, 15.0f)); + } + } + } }