diff options
| author | Alex Sakhartchouk <alexst@google.com> | 2010-05-19 16:28:27 -0700 |
|---|---|---|
| committer | Alex Sakhartchouk <alexst@google.com> | 2010-05-19 16:28:27 -0700 |
| commit | 814326b3b945d61ea48d05e32899fb5a036cc2d3 (patch) | |
| tree | ad9c395d13d4aad145d1470d7fffbaa8e742b912 /libs/rs/java | |
| parent | 468202dd71e375a1f7f2038e094baffe204c4972 (diff) | |
| download | frameworks_base-814326b3b945d61ea48d05e32899fb5a036cc2d3.zip frameworks_base-814326b3b945d61ea48d05e32899fb5a036cc2d3.tar.gz frameworks_base-814326b3b945d61ea48d05e32899fb5a036cc2d3.tar.bz2 | |
Added benchmark mode.
Added some image processing operations.
Change-Id: Ic7ba45fbf57eff6fc7d20377c148d0ba7ac862f7
Diffstat (limited to 'libs/rs/java')
| -rw-r--r-- | libs/rs/java/ImageProcessing/AndroidManifest.xml | 3 | ||||
| -rw-r--r-- | libs/rs/java/ImageProcessing/res/layout/main.xml | 153 | ||||
| -rw-r--r-- | libs/rs/java/ImageProcessing/res/raw/threshold.rs | 335 | ||||
| -rw-r--r-- | libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc | bin | 1528 -> 8400 bytes | |||
| -rw-r--r-- | libs/rs/java/ImageProcessing/res/values/strings.xml | 33 | ||||
| -rw-r--r-- | libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java | 335 | ||||
| -rw-r--r-- | libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java | 56 |
7 files changed, 840 insertions, 75 deletions
diff --git a/libs/rs/java/ImageProcessing/AndroidManifest.xml b/libs/rs/java/ImageProcessing/AndroidManifest.xml index b48d208..d6a2db4 100644 --- a/libs/rs/java/ImageProcessing/AndroidManifest.xml +++ b/libs/rs/java/ImageProcessing/AndroidManifest.xml @@ -6,7 +6,8 @@ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:label="Image Processing"> - <activity android:name="ImageProcessingActivity"> + <activity android:name="ImageProcessingActivity" + android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/libs/rs/java/ImageProcessing/res/layout/main.xml b/libs/rs/java/ImageProcessing/res/layout/main.xml index 6770c18..c6ec729 100644 --- a/libs/rs/java/ImageProcessing/res/layout/main.xml +++ b/libs/rs/java/ImageProcessing/res/layout/main.xml @@ -25,9 +25,147 @@ android:id="@+id/display" android:layout_width="320dip" android:layout_height="266dip" /> - + + <Button + android:layout_marginBottom="170dip" + android:layout_width="wrap_content" + android:layout_height="40dip" + android:text="@string/benchmark" + android:onClick="benchmark" + android:layout_gravity="bottom"/> + + <TextView + android:id="@+id/benchmarkText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="100dip" + android:layout_marginBottom="175dip" + android:layout_gravity="bottom" + android:text="@string/saturation"/> + + <SeekBar + android:id="@+id/inSaturation" + android:layout_marginBottom="140dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inSaturationText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="142dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/saturation"/> + + <SeekBar + android:id="@+id/inGamma" + android:layout_marginBottom="110dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inGammaText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="112dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/gamma"/> + <SeekBar - android:id="@+id/threshold" + android:id="@+id/outWhite" + android:layout_marginBottom="80dip" + android:layout_marginLeft="170dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/outWhiteText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="220dip" + android:layout_marginBottom="82dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/out_white"/> + + <SeekBar + android:id="@+id/inWhite" + android:layout_marginBottom="80dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="170dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inWhiteText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="82dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/in_white"/> + + <SeekBar + android:id="@+id/outBlack" + android:layout_marginBottom="50dip" + android:layout_marginLeft="170dip" + android:layout_marginRight="10dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/outBlackText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="220dip" + android:layout_marginBottom="52dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/out_black"/> + + <SeekBar + android:id="@+id/inBlack" + android:layout_marginBottom="50dip" + android:layout_marginLeft="10dip" + android:layout_marginRight="170dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" /> + + <TextView + android:id="@+id/inBlackText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="52dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/in_black"/> + + <SeekBar + android:id="@+id/radius" android:layout_marginBottom="10dip" android:layout_marginLeft="10dip" android:layout_marginRight="10dip" @@ -35,4 +173,15 @@ android:layout_height="wrap_content" android:layout_gravity="bottom" /> + <TextView + android:id="@+id/blurText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginLeft="50dip" + android:layout_marginBottom="12dip" + android:textColor="#000" + android:layout_gravity="bottom" + android:text="@string/blur_description"/> + </merge>
\ No newline at end of file diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold.rs b/libs/rs/java/ImageProcessing/res/raw/threshold.rs index 8dc614e..0317088 100644 --- a/libs/rs/java/ImageProcessing/res/raw/threshold.rs +++ b/libs/rs/java/ImageProcessing/res/raw/threshold.rs @@ -4,46 +4,331 @@ #include "../../../../scriptc/rs_math.rsh" #include "../../../../scriptc/rs_graphics.rsh" +#define MAX_RADIUS 25 + int height; int width; -float threshold; +int radius; typedef struct c4u_s { - char r, g, b, a; + uint8_t r, g, b, a; } c4u_t; -//rs_color4u * InPixel; -//rs_color4u * OutPixel; c4u_t * InPixel; c4u_t * OutPixel; +c4u_t * ScratchPixel; + +float inBlack; +float outBlack; +float inWhite; +float outWhite; +float gamma; + +float saturation; + +float inWMinInB; +float outWMinOutB; + +#pragma rs export_var(height, width, radius, InPixel, OutPixel, ScratchPixel, inBlack, outBlack, inWhite, outWhite, gamma, saturation) +#pragma rs export_func(filter, processNoBlur, computeColorMatrix, computeGaussianWeights); + +// Store our coefficients here +float gaussian[MAX_RADIUS * 2 + 1]; +float colorMat[4][4]; + +void computeColorMatrix() { + // Saturation + // Linear weights + //float rWeight = 0.3086f; + //float gWeight = 0.6094f; + //float bWeight = 0.0820f; + + // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons) + float rWeight = 0.299f; + float gWeight = 0.587f; + float bWeight = 0.114f; + + float oneMinusS = 1.0f - saturation; + + matrixLoadIdentity(colorMat); + + colorMat[0][0] = oneMinusS * rWeight + saturation; + colorMat[0][1] = oneMinusS * rWeight; + colorMat[0][2] = oneMinusS * rWeight; + colorMat[1][0] = oneMinusS * gWeight; + colorMat[1][1] = oneMinusS * gWeight + saturation; + colorMat[1][2] = oneMinusS * gWeight; + colorMat[2][0] = oneMinusS * bWeight; + colorMat[2][1] = oneMinusS * bWeight; + colorMat[2][2] = oneMinusS * bWeight + saturation; + + inWMinInB = inWhite - inBlack; + outWMinOutB = outWhite - outBlack; +} + +void computeGaussianWeights() { + // Compute gaussian weights for the blur + // e is the euler's number + float e = 2.718281828459045f; + float pi = 3.1415926535897932f; + // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) + // x is of the form [-radius .. 0 .. radius] + // and sigma varies with radius. + // Based on some experimental radius values and sigma's + // we approximately fit sigma = f(radius) as + // sigma = radius * 0.4 + 0.6 + // The larger the radius gets, the more our gaussian blur + // will resemble a box blur since with large sigma + // the gaussian curve begins to lose its shape + float sigma = 0.4f * (float)radius + 0.6f; + + // Now compute the coefficints + // We will store some redundant values to save some math during + // the blur calculations + // precompute some values + float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); + float coeff2 = - 1.0f / (2.0f * sigma * sigma); + + float normalizeFactor = 0.0f; + float floatR = 0.0f; + int r; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); + normalizeFactor += gaussian[r + radius]; + } + + //Now we need to normalize the weights because all our coefficients need to add up to one + normalizeFactor = 1.0f / normalizeFactor; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] *= normalizeFactor; + } +} + +// This needs to be inline +void levelsSaturation(float4 *currentPixel) { + // Color matrix multiply + float tempX = colorMat[0][0] * currentPixel->x + colorMat[1][0] * currentPixel->y + colorMat[2][0] * currentPixel->z; + float tempY = colorMat[0][1] * currentPixel->x + colorMat[1][1] * currentPixel->y + colorMat[2][1] * currentPixel->z; + float tempZ = colorMat[0][2] * currentPixel->x + colorMat[1][2] * currentPixel->y + colorMat[2][2] * currentPixel->z; + + currentPixel->x = tempX; + currentPixel->y = tempY; + currentPixel->z = tempZ; + + // Clamp to 0..255 + // Inline the code here to avoid funciton calls + currentPixel->x = currentPixel->x > 255.0f ? 255.0f : currentPixel->x; + currentPixel->y = currentPixel->y > 255.0f ? 255.0f : currentPixel->y; + currentPixel->z = currentPixel->z > 255.0f ? 255.0f : currentPixel->z; + + currentPixel->x = currentPixel->x <= 0.0f ? 0.1f : currentPixel->x; + currentPixel->y = currentPixel->y <= 0.0f ? 0.1f : currentPixel->y; + currentPixel->z = currentPixel->z <= 0.0f ? 0.1f : currentPixel->z; + + currentPixel->x = pow( (currentPixel->x - inBlack) / (inWMinInB), gamma) * (outWMinOutB) + outBlack; + currentPixel->y = pow( (currentPixel->y - inBlack) / (inWMinInB), gamma) * (outWMinOutB) + outBlack; + currentPixel->z = pow( (currentPixel->z - inBlack) / (inWMinInB), gamma) * (outWMinOutB) + outBlack; + + currentPixel->x = currentPixel->x > 255.0f ? 255.0f : currentPixel->x; + currentPixel->y = currentPixel->y > 255.0f ? 255.0f : currentPixel->y; + currentPixel->z = currentPixel->z > 255.0f ? 255.0f : currentPixel->z; + + currentPixel->x = currentPixel->x <= 0.0f ? 0.1f : currentPixel->x; + currentPixel->y = currentPixel->y <= 0.0f ? 0.1f : currentPixel->y; + currentPixel->z = currentPixel->z <= 0.0f ? 0.1f : currentPixel->z; +} + +void processNoBlur() { + int w, h, r; + int count = 0; + + float inWMinInB = inWhite - inBlack; + float outWMinOutB = outWhite - outBlack; + float4 currentPixel = 0; + + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + c4u_t *input = InPixel + h*width + w; + + currentPixel.x = (float)(input->r); + currentPixel.y = (float)(input->g); + currentPixel.z = (float)(input->b); + + levelsSaturation(¤tPixel); + + c4u_t *output = OutPixel + h*width + w; + output->r = (uint8_t)currentPixel.x; + output->g = (uint8_t)currentPixel.y; + output->b = (uint8_t)currentPixel.z; + output->a = input->a; + } + } + sendToClient(&count, 1, 4, 0); +} + +void horizontalBlur() { + float4 blurredPixel = 0; + float4 currentPixel = 0; + // Horizontal blur + int w, h, r; + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { -#pragma rs export_var(height, width, threshold, InPixel, OutPixel) + blurredPixel = 0; + + for(r = -radius; r <= radius; r ++) { + // Stepping left and right away from the pixel + int validW = w + r; + // Clamp to zero and width max() isn't exposed for ints yet + if(validW < 0) { + validW = 0; + } + if(validW > width - 1) { + validW = width - 1; + } + + c4u_t *input = InPixel + h*width + validW; + + float weight = gaussian[r + radius]; + currentPixel.x = (float)(input->r); + currentPixel.y = (float)(input->g); + currentPixel.z = (float)(input->b); + //currentPixel.w = (float)(input->a); + + blurredPixel += currentPixel*weight; + } + + c4u_t *output = ScratchPixel + h*width + w; + output->r = (uint8_t)blurredPixel.x; + output->g = (uint8_t)blurredPixel.y; + output->b = (uint8_t)blurredPixel.z; + //output->a = (uint8_t)blurredPixel.w; + } + } +} + +void horizontalBlurLevels() { + float4 blurredPixel = 0; + float4 currentPixel = 0; + // Horizontal blur + int w, h, r; + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + + blurredPixel = 0; + + for(r = -radius; r <= radius; r ++) { + // Stepping left and right away from the pixel + int validW = w + r; + // Clamp to zero and width max() isn't exposed for ints yet + if(validW < 0) { + validW = 0; + } + if(validW > width - 1) { + validW = width - 1; + } + + c4u_t *input = InPixel + h*width + validW; + + float weight = gaussian[r + radius]; + currentPixel.x = (float)(input->r); + currentPixel.y = (float)(input->g); + currentPixel.z = (float)(input->b); + //currentPixel.w = (float)(input->a); + + blurredPixel += currentPixel*weight; + } + + levelsSaturation(&blurredPixel); + + c4u_t *output = ScratchPixel + h*width + w; + output->r = (uint8_t)blurredPixel.x; + output->g = (uint8_t)blurredPixel.y; + output->b = (uint8_t)blurredPixel.z; + //output->a = (uint8_t)blurredPixel.w; + } + } +} + +void verticalBlur() { + float4 blurredPixel = 0; + float4 currentPixel = 0; + // Vertical blur + int w, h, r; + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + + blurredPixel = 0; + for(r = -radius; r <= radius; r ++) { + int validH = h + r; + // Clamp to zero and width + if(validH < 0) { + validH = 0; + } + if(validH > height - 1) { + validH = height - 1; + } + + c4u_t *input = ScratchPixel + validH*width + w; + + float weight = gaussian[r + radius]; + + currentPixel.x = (float)(input->r); + currentPixel.y = (float)(input->g); + currentPixel.z = (float)(input->b); + //currentPixel.w = (float)(input->a); + + blurredPixel += currentPixel*weight; + } + + c4u_t *output = OutPixel + h*width + w; + + output->r = (uint8_t)blurredPixel.x; + output->g = (uint8_t)blurredPixel.y; + output->b = (uint8_t)blurredPixel.z; + //output->a = (uint8_t)blurredPixel.w; + } + } +} void filter() { debugP(0, (void *)height); debugP(0, (void *)width); - debugP(0, (void *)((int)threshold)); - debugP(0, (void *)InPixel); - debugP(0, (void *)OutPixel); - - rs_color4u *in = (rs_color4u *)InPixel; - rs_color4u *out = (rs_color4u *)OutPixel; - //const rs_color4u mask = {0,0,0,0xff}; - - int count = width * height; - int tf = threshold * 255 * 255; - int masks[2] = {0xffffffff, 0xff000000}; - - while (count--) { - int luminance = 54 * in->x + - 182 * in->y + - 18 * in->z; - int idx = ((uint32_t)(luminance - tf)) >> 31; - *((int *)out) = *((int *)in) & masks[idx]; - in++; - out++; + debugP(0, (void *)radius); + + debugPf(10, inBlack); + debugPf(11, outBlack); + debugPf(12, inWhite); + debugPf(13, outWhite); + debugPf(14, gamma); + debugPf(15, saturation); + + computeColorMatrix(); + + if(radius == 0) { + processNoBlur(); + return; } + computeGaussianWeights(); + + horizontalBlurLevels(); + verticalBlur(); + + int count = 0; + sendToClient(&count, 1, 4, 0); +} + +void filterBenchmark() { + + computeGaussianWeights(); + + horizontalBlur(); + verticalBlur(); + + int count = 0; sendToClient(&count, 1, 4, 0); } diff --git a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc Binary files differindex 55d514c..58a93e6 100644 --- a/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc +++ b/libs/rs/java/ImageProcessing/res/raw/threshold_bc.bc diff --git a/libs/rs/java/ImageProcessing/res/values/strings.xml b/libs/rs/java/ImageProcessing/res/values/strings.xml new file mode 100644 index 0000000..cc5cc4d --- /dev/null +++ b/libs/rs/java/ImageProcessing/res/values/strings.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright (C) 2008 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- General --> + <skip /> + <!--slider label --> + <string name="blur_description">Blur Radius</string> + <string name="in_white">In White</string> + <string name="out_white">Out White</string> + <string name="in_black">In Black</string> + <string name="out_black">Out Black</string> + <string name="gamma">Gamma</string> + <string name="saturation">Saturation</string> + <string name="benchmark">Benchmark</string> + +</resources> diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java index aec5e23..5e36a78 100644 --- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java @@ -31,13 +31,35 @@ import android.view.SurfaceView; import android.view.SurfaceHolder; import android.widget.ImageView; import android.widget.SeekBar; +import android.widget.TextView; +import android.view.View; import java.lang.Math; -public class ImageProcessingActivity extends Activity implements SurfaceHolder.Callback { +public class ImageProcessingActivity extends Activity + implements SurfaceHolder.Callback, + SeekBar.OnSeekBarChangeListener { private Bitmap mBitmapIn; private Bitmap mBitmapOut; + private Bitmap mBitmapScratch; private ScriptC_Threshold mScript; - private float mThreshold = 0.5f; + private int mRadius = 0; + private SeekBar mRadiusSeekBar; + + private float mInBlack = 0.0f; + private SeekBar mInBlackSeekBar; + private float mOutBlack = 0.0f; + private SeekBar mOutBlackSeekBar; + private float mInWhite = 255.0f; + private SeekBar mInWhiteSeekBar; + private float mOutWhite = 255.0f; + private SeekBar mOutWhiteSeekBar; + private float mGamma = 1.0f; + private SeekBar mGammaSeekBar; + + private float mSaturation = 1.0f; + private SeekBar mSaturationSeekBar; + + private TextView mBenchmarkResult; @SuppressWarnings({"FieldCanBeLocal"}) private RenderScript mRS; @@ -47,6 +69,8 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C private Allocation mInPixelsAllocation; @SuppressWarnings({"FieldCanBeLocal"}) private Allocation mOutPixelsAllocation; + @SuppressWarnings({"FieldCanBeLocal"}) + private Allocation mScratchPixelsAllocation; private SurfaceView mSurfaceView; private ImageView mDisplayView; @@ -66,34 +90,217 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C } int in[]; + int interm[]; int out[]; - private void javaFilter() { - final int w = mBitmapIn.getWidth(); - final int h = mBitmapIn.getHeight(); - final int count = w * h; + int MAX_RADIUS = 25; + // Store our coefficients here + float gaussian[]; + + private long javaFilter() { + final int width = mBitmapIn.getWidth(); + final int height = mBitmapIn.getHeight(); + final int count = width * height; if (in == null) { in = new int[count]; + interm = new int[count]; out = new int[count]; - mBitmapIn.getPixels(in, 0, w, 0, 0, w, h); + gaussian = new float[MAX_RADIUS * 2 + 1]; + mBitmapIn.getPixels(in, 0, width, 0, 0, width, height); + } + + long t = java.lang.System.currentTimeMillis(); + + int w, h, r; + + float fRadius = (float)mRadius; + int radius = (int)mRadius; + + // Compute gaussian weights for the blur + // e is the euler's number + float e = 2.718281828459045f; + float pi = 3.1415926535897932f; + // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) + // x is of the form [-radius .. 0 .. radius] + // and sigma varies with radius. + // Based on some experimental radius values and sigma's + // we approximately fit sigma = f(radius) as + // sigma = radius * 0.4 + 0.6 + // The larger the radius gets, the more our gaussian blur + // will resemble a box blur since with large sigma + // the gaussian curve begins to lose its shape + float sigma = 0.4f * fRadius + 0.6f; + // Now compute the coefficints + // We will store some redundant values to save some math during + // the blur calculations + // precompute some values + float coeff1 = 1.0f / (float)(Math.sqrt( 2.0f * pi ) * sigma); + float coeff2 = - 1.0f / (2.0f * sigma * sigma); + float normalizeFactor = 0.0f; + float floatR = 0.0f; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] = coeff1 * (float)Math.pow(e, floatR * floatR * coeff2); + normalizeFactor += gaussian[r + radius]; } - int threshold = (int)(mThreshold * 255.f) * 255; - //long t = java.lang.System.currentTimeMillis(); + //Now we need to normalize the weights because all our coefficients need to add up to one + normalizeFactor = 1.0f / normalizeFactor; + for(r = -radius; r <= radius; r ++) { + floatR = (float)r; + gaussian[r + radius] *= normalizeFactor; + } + + float blurredPixelR = 0.0f; + float blurredPixelG = 0.0f; + float blurredPixelB = 0.0f; + float blurredPixelA = 0.0f; + + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + + blurredPixelR = 0.0f; + blurredPixelG = 0.0f; + blurredPixelB = 0.0f; + blurredPixelA = 0.0f; + + for(r = -radius; r <= radius; r ++) { + // Stepping left and right away from the pixel + int validW = w + r; + // Clamp to zero and width max() isn't exposed for ints yet + if(validW < 0) { + validW = 0; + } + if(validW > width - 1) { + validW = width - 1; + } + + int input = in[h*width + validW]; + + int R = ((input >> 24) & 0xff); + int G = ((input >> 16) & 0xff); + int B = ((input >> 8) & 0xff); + int A = (input & 0xff); + + float weight = gaussian[r + radius]; + + blurredPixelR += (float)(R)*weight; + blurredPixelG += (float)(G)*weight; + blurredPixelB += (float)(B)*weight; + blurredPixelA += (float)(A)*weight; + } + + int R = (int)blurredPixelR; + int G = (int)blurredPixelG; + int B = (int)blurredPixelB; + int A = (int)blurredPixelA; + + interm[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A); + } + } + + for(h = 0; h < height; h ++) { + for(w = 0; w < width; w ++) { + + blurredPixelR = 0.0f; + blurredPixelG = 0.0f; + blurredPixelB = 0.0f; + blurredPixelA = 0.0f; + for(r = -radius; r <= radius; r ++) { + int validH = h + r; + // Clamp to zero and width + if(validH < 0) { + validH = 0; + } + if(validH > height - 1) { + validH = height - 1; + } + + int input = interm[validH*width + w]; + + int R = ((input >> 24) & 0xff); + int G = ((input >> 16) & 0xff); + int B = ((input >> 8) & 0xff); + int A = (input & 0xff); + + float weight = gaussian[r + radius]; + + blurredPixelR += (float)(R)*weight; + blurredPixelG += (float)(G)*weight; + blurredPixelB += (float)(B)*weight; + blurredPixelA += (float)(A)*weight; + } + + int R = (int)blurredPixelR; + int G = (int)blurredPixelG; + int B = (int)blurredPixelB; + int A = (int)blurredPixelA; + + out[h*width + w] = (R << 24) | (G << 16) | (B << 8) | (A); + } + } - for (int i = 0; i < count; i++) { - final int luminance = 54 * ((in[i] >> 0) & 0xff) + - 182* ((in[i] >> 8) & 0xff) + - 18 * ((in[i] >> 16) & 0xff); - if (luminance > threshold) { - out[i] = in[i]; + t = java.lang.System.currentTimeMillis() - t; + android.util.Log.v("Img", "Java frame time ms " + t); + mBitmapOut.setPixels(out, 0, width, 0, 0, width, height); + return t; + } + + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + + if(seekBar == mRadiusSeekBar) { + float fRadius = progress / 100.0f; + fRadius *= (float)(MAX_RADIUS); + mRadius = (int)fRadius; + + mScript.set_radius(mRadius); + } + else if(seekBar == mInBlackSeekBar) { + mInBlack = (float)progress; + mScript.set_inBlack(mInBlack); + } + else if(seekBar == mOutBlackSeekBar) { + mOutBlack = (float)progress; + mScript.set_outBlack(mOutBlack); + } + else if(seekBar == mInWhiteSeekBar) { + mInWhite = (float)progress + 127.0f; + mScript.set_inWhite(mInWhite); + } + else if(seekBar == mOutWhiteSeekBar) { + mOutWhite = (float)progress + 127.0f; + mScript.set_outWhite(mOutWhite); + } + else if(seekBar == mGammaSeekBar) { + mGamma = (float)progress/100.0f; + mGamma = Math.max(mGamma, 0.1f); + mGamma = 1.0f / mGamma; + mScript.set_gamma(mGamma); + } + else if(seekBar == mSaturationSeekBar) { + mSaturation = (float)progress / 50.0f; + mScript.set_saturation(mSaturation); + } + + long t = java.lang.System.currentTimeMillis(); + if (true) { + mScript.invokable_Filter(); } else { - out[i] = in[i] & 0xff000000; + javaFilter(); } + + t = java.lang.System.currentTimeMillis() - t; + android.util.Log.v("Img", "Renderscript frame time core ms " + t); + + mDisplayView.invalidate(); } - //t = java.lang.System.currentTimeMillis() - t; - //android.util.Log.v("Img", "frame time ms " + t); - mBitmapOut.setPixels(out, 0, w, 0, 0, w, h); + } + + public void onStartTrackingTouch(SeekBar seekBar) { + } + + public void onStopTrackingTouch(SeekBar seekBar) { } @Override @@ -103,6 +310,7 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C mBitmapIn = loadBitmap(R.drawable.data); mBitmapOut = loadBitmap(R.drawable.data); + mBitmapScratch = loadBitmap(R.drawable.data); mSurfaceView = (SurfaceView) findViewById(R.id.surface); mSurfaceView.getHolder().addCallback(this); @@ -110,31 +318,38 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C mDisplayView = (ImageView) findViewById(R.id.display); mDisplayView.setImageBitmap(mBitmapOut); - ((SeekBar) findViewById(R.id.threshold)).setOnSeekBarChangeListener( - new SeekBar.OnSeekBarChangeListener() { - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser) { - mThreshold = progress / 100.0f; - mScript.set_threshold(mThreshold); - - long t = java.lang.System.currentTimeMillis(); - if (true) { - mScript.invokable_Filter(); - } else { - javaFilter(); - mDisplayView.invalidate(); - } - t = java.lang.System.currentTimeMillis() - t; - android.util.Log.v("Img", "frame time core ms " + t); - } - } + mRadiusSeekBar = (SeekBar) findViewById(R.id.radius); + mRadiusSeekBar.setOnSeekBarChangeListener(this); - public void onStartTrackingTouch(SeekBar seekBar) { - } + mInBlackSeekBar = (SeekBar)findViewById(R.id.inBlack); + mInBlackSeekBar.setOnSeekBarChangeListener(this); + mInBlackSeekBar.setMax(128); + mInBlackSeekBar.setProgress(0); + mOutBlackSeekBar = (SeekBar)findViewById(R.id.outBlack); + mOutBlackSeekBar.setOnSeekBarChangeListener(this); + mOutBlackSeekBar.setMax(128); + mOutBlackSeekBar.setProgress(0); - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); + mInWhiteSeekBar = (SeekBar)findViewById(R.id.inWhite); + mInWhiteSeekBar.setOnSeekBarChangeListener(this); + mInWhiteSeekBar.setMax(128); + mInWhiteSeekBar.setProgress(128); + mOutWhiteSeekBar = (SeekBar)findViewById(R.id.outWhite); + mOutWhiteSeekBar.setOnSeekBarChangeListener(this); + mOutWhiteSeekBar.setMax(128); + mOutWhiteSeekBar.setProgress(128); + + mGammaSeekBar = (SeekBar)findViewById(R.id.inGamma); + mGammaSeekBar.setOnSeekBarChangeListener(this); + mGammaSeekBar.setMax(150); + mGammaSeekBar.setProgress(100); + + mSaturationSeekBar = (SeekBar)findViewById(R.id.inSaturation); + mSaturationSeekBar.setOnSeekBarChangeListener(this); + mSaturationSeekBar.setProgress(50); + + mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText); + mBenchmarkResult.setText("Benchmark no yet run"); } public void surfaceCreated(SurfaceHolder holder) { @@ -154,13 +369,23 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C mInPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapIn); mOutPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapOut); + mScratchPixelsAllocation = Allocation.createBitmapRef(mRS, mBitmapScratch); mScript = new ScriptC_Threshold(mRS, getResources(), false); mScript.set_width(mBitmapIn.getWidth()); mScript.set_height(mBitmapIn.getHeight()); - mScript.set_threshold(mThreshold); + mScript.set_radius(mRadius); + + mScript.set_inBlack(mInBlack); + mScript.set_outBlack(mOutBlack); + mScript.set_inWhite(mInWhite); + mScript.set_outWhite(mOutWhite); + mScript.set_gamma(mGamma); + mScript.set_saturation(mSaturation); + mScript.bind_InPixel(mInPixelsAllocation); mScript.bind_OutPixel(mOutPixelsAllocation); + mScript.bind_ScratchPixel(mScratchPixelsAllocation); } private Bitmap loadBitmap(int resource) { @@ -176,4 +401,28 @@ public class ImageProcessingActivity extends Activity implements SurfaceHolder.C source.recycle(); return b; } + + // button hook + public void benchmark(View v) { + android.util.Log.v("Img", "Benchmarking"); + int oldRadius = mRadius; + mRadius = MAX_RADIUS; + mScript.set_radius(mRadius); + + long t = java.lang.System.currentTimeMillis(); + + mScript.invokable_FilterBenchmark(); + + t = java.lang.System.currentTimeMillis() - t; + android.util.Log.v("Img", "Renderscript frame time core ms " + t); + + long javaTime = javaFilter(); + + mBenchmarkResult.setText("RS: " + t + " ms Java: " + javaTime + " ms"); + + mRadius = oldRadius; + mScript.set_radius(mRadius); + + mScript.invokable_Filter(); + } } diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java index dbaa18c..dfed9e5 100644 --- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java +++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ScriptC_Threshold.java @@ -10,12 +10,23 @@ public class ScriptC_Threshold { private final static int mFieldIndex_height = 0; private final static int mFieldIndex_width = 1; - private final static int mFieldIndex_threshold = 2; + private final static int mFieldIndex_radius = 2; private final static int mFieldIndex_InPixel = 3; private final static int mFieldIndex_OutPixel = 4; + private final static int mFieldIndex_ScratchPixel = 5; + + private final static int mFieldIndex_inBlack = 6; + private final static int mFieldIndex_outBlack = 7; + private final static int mFieldIndex_inWhite = 8; + private final static int mFieldIndex_outWhite = 9; + private final static int mFieldIndex_gamma = 10; + + private final static int mFieldIndex_saturation = 11; + private final static int mFieldIndex_hue = 12; private Allocation mField_InPixel; private Allocation mField_OutPixel; + private Allocation mField_ScratchPixel; public ScriptC_Threshold(RenderScript rs, Resources resources, boolean isRoot) { super(rs, resources, R.raw.threshold_bc, isRoot); @@ -43,6 +54,15 @@ public class ScriptC_Threshold bindAllocation(f, mFieldIndex_OutPixel); mField_OutPixel = f; } + public void bind_ScratchPixel(Allocation f) { + if (f != null) { + //if (f.getType().getElement() != Element.ATTRIB_COLOR_U8_4(mRS)) { + //throw new IllegalArgumentException("Element type mismatch."); + //} + } + bindAllocation(f, mFieldIndex_ScratchPixel); + mField_ScratchPixel = f; + } public Allocation get_OutPixel() { return mField_OutPixel; } @@ -55,13 +75,41 @@ public class ScriptC_Threshold setVar(mFieldIndex_width, v); } - public void set_threshold(float v) { - setVar(mFieldIndex_threshold, v); + public void set_radius(int v) { + setVar(mFieldIndex_radius, v); } - private final static int mInvokableIndex_Filter = 0; + public void set_inBlack(float v) { + setVar(mFieldIndex_inBlack, v); + } + public void set_outBlack(float v) { + setVar(mFieldIndex_outBlack, v); + } + public void set_inWhite(float v) { + setVar(mFieldIndex_inWhite, v); + } + public void set_outWhite(float v) { + setVar(mFieldIndex_outWhite, v); + } + public void set_gamma(float v) { + setVar(mFieldIndex_gamma, v); + } + + public void set_saturation(float v) { + setVar(mFieldIndex_saturation, v); + } + public void set_hue(float v) { + setVar(mFieldIndex_hue, v); + } + + private final static int mInvokableIndex_Filter = 2; public void invokable_Filter() { invokeData(mInvokableIndex_Filter); } + + private final static int mInvokableIndex_FilterBenchmark = 3; + public void invokable_FilterBenchmark() { + invokeData(mInvokableIndex_FilterBenchmark); + } } |
