summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java8
2 files changed, 118 insertions, 28 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
index 477e7d7ebf72..24a4b9e3052b 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
@@ -30,13 +30,15 @@ import android.os.Message;
import android.util.Log;
/**
- * A helper class that computes histogram and percentile 85 from a bitmap.
- * Percentile 85 will be computed each time the user picks a new image wallpaper.
+ * A helper class that computes threshold from a bitmap.
+ * Threshold will be computed each time the user picks a new image wallpaper.
*/
class ImageProcessHelper {
private static final String TAG = ImageProcessHelper.class.getSimpleName();
- private static final float DEFAULT_PER85 = 0.8f;
- private static final int MSG_UPDATE_PER85 = 1;
+ private static final float DEFAULT_THRESHOLD = 0.8f;
+ private static final float DEFAULT_OTSU_THRESHOLD = 0f;
+ private static final float MAX_THRESHOLD = 0.89f;
+ private static final int MSG_UPDATE_THRESHOLD = 1;
/**
* This color matrix will be applied to each pixel to get luminance from rgb by below formula:
@@ -53,8 +55,8 @@ class ImageProcessHelper {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
- case MSG_UPDATE_PER85:
- mPer85 = (float) msg.obj;
+ case MSG_UPDATE_THRESHOLD:
+ mThreshold = (float) msg.obj;
return true;
default:
return false;
@@ -62,20 +64,20 @@ class ImageProcessHelper {
}
});
- private float mPer85 = DEFAULT_PER85;
+ private float mThreshold = DEFAULT_THRESHOLD;
- void startComputingPercentile85(Bitmap bitmap) {
- new Per85ComputeTask(mHandler).execute(bitmap);
+ void start(Bitmap bitmap) {
+ new ThresholdComputeTask(mHandler).execute(bitmap);
}
- float getPercentile85() {
- return mPer85;
+ float getThreshold() {
+ return Math.min(mThreshold, MAX_THRESHOLD);
}
- private static class Per85ComputeTask extends AsyncTask<Bitmap, Void, Float> {
+ private static class ThresholdComputeTask extends AsyncTask<Bitmap, Void, Float> {
private Handler mUpdateHandler;
- Per85ComputeTask(Handler handler) {
+ ThresholdComputeTask(Handler handler) {
super(handler);
mUpdateHandler = handler;
}
@@ -84,35 +86,55 @@ class ImageProcessHelper {
protected Float doInBackground(Bitmap... bitmaps) {
Bitmap bitmap = bitmaps[0];
if (bitmap != null) {
- int[] histogram = processHistogram(bitmap);
- return computePercentile85(bitmap, histogram);
+ return new Threshold().compute(bitmap);
}
- Log.e(TAG, "Per85ComputeTask: Can't get bitmap");
- return DEFAULT_PER85;
+ Log.e(TAG, "ThresholdComputeTask: Can't get bitmap");
+ return DEFAULT_THRESHOLD;
}
@Override
protected void onPostExecute(Float result) {
- Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_PER85, result);
+ Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_THRESHOLD, result);
mUpdateHandler.sendMessage(msg);
}
+ }
+
+ private static class Threshold {
+ public float compute(Bitmap bitmap) {
+ Bitmap grayscale = toGrayscale(bitmap);
+ int[] histogram = getHistogram(grayscale);
+ boolean isSolidColor = isSolidColor(grayscale, histogram);
+
+ // We will see gray wallpaper during the transition if solid color wallpaper is set,
+ // please refer to b/130360362#comment16.
+ // As a result, we use Percentile85 rather than Otsus if a solid color wallpaper is set.
+ ThresholdAlgorithm algorithm = isSolidColor ? new Percentile85() : new Otsus();
+ return algorithm.compute(grayscale, histogram);
+ }
- private int[] processHistogram(Bitmap bitmap) {
+ private Bitmap toGrayscale(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
- Bitmap target = Bitmap.createBitmap(width, height, bitmap.getConfig());
- Canvas canvas = new Canvas(target);
+ Bitmap grayscale = Bitmap.createBitmap(width, height, bitmap.getConfig());
+ Canvas canvas = new Canvas(grayscale);
ColorMatrix cm = new ColorMatrix(LUMINOSITY_MATRIX);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(bitmap, new Matrix(), paint);
+ return grayscale;
+ }
+
+ private int[] getHistogram(Bitmap grayscale) {
+ int width = grayscale.getWidth();
+ int height = grayscale.getHeight();
+
// TODO: Fine tune the performance here, tracking on b/123615079.
int[] histogram = new int[256];
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
- int pixel = target.getPixel(col, row);
+ int pixel = grayscale.getPixel(col, row);
int y = Color.red(pixel) + Color.green(pixel) + Color.blue(pixel);
histogram[y]++;
}
@@ -121,8 +143,29 @@ class ImageProcessHelper {
return histogram;
}
- private float computePercentile85(Bitmap bitmap, int[] histogram) {
- float per85 = DEFAULT_PER85;
+ private boolean isSolidColor(Bitmap bitmap, int[] histogram) {
+ boolean solidColor = false;
+ int pixels = bitmap.getWidth() * bitmap.getHeight();
+
+ // In solid color case, only one element of histogram has value,
+ // which is pixel counts and the value of other elements should be 0.
+ for (int value : histogram) {
+ if (value != 0 && value != pixels) {
+ break;
+ }
+ if (value == pixels) {
+ solidColor = true;
+ break;
+ }
+ }
+ return solidColor;
+ }
+ }
+
+ private static class Percentile85 implements ThresholdAlgorithm {
+ @Override
+ public float compute(Bitmap bitmap, int[] histogram) {
+ float per85 = DEFAULT_THRESHOLD;
int pixelCount = bitmap.getWidth() * bitmap.getHeight();
float[] acc = new float[256];
for (int i = 0; i < acc.length; i++) {
@@ -141,4 +184,51 @@ class ImageProcessHelper {
return per85;
}
}
+
+ private static class Otsus implements ThresholdAlgorithm {
+ @Override
+ public float compute(Bitmap bitmap, int[] histogram) {
+ float threshold = DEFAULT_OTSU_THRESHOLD;
+ float maxVariance = 0;
+ float pixelCount = bitmap.getWidth() * bitmap.getHeight();
+ float[] w = new float[2];
+ float[] m = new float[2];
+ float[] u = new float[2];
+
+ for (int i = 0; i < histogram.length; i++) {
+ m[1] += i * histogram[i];
+ }
+
+ w[1] = pixelCount;
+ for (int tonalValue = 0; tonalValue < histogram.length; tonalValue++) {
+ float dU;
+ float variance;
+ float numPixels = histogram[tonalValue];
+ float tmp = numPixels * tonalValue;
+ w[0] += numPixels;
+ w[1] -= numPixels;
+
+ if (w[0] == 0 || w[1] == 0) {
+ continue;
+ }
+
+ m[0] += tmp;
+ m[1] -= tmp;
+ u[0] = m[0] / w[0];
+ u[1] = m[1] / w[1];
+ dU = u[0] - u[1];
+ variance = w[0] * w[1] * dU * dU;
+
+ if (variance > maxVariance) {
+ threshold = (tonalValue + 1f) / histogram.length;
+ maxVariance = variance;
+ }
+ }
+ return threshold;
+ }
+ }
+
+ private interface ThresholdAlgorithm {
+ float compute(Bitmap bitmap, int[] histogram);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 464cbe33c5f0..5bbfe84b6319 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -78,8 +78,8 @@ public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
mBitmap = mWallpaperManager.getBitmap();
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
- // Compute per85 as transition threshold, this is an async work.
- mImageProcessHelper.startComputingPercentile85(mBitmap);
+ // Compute threshold of the image, this is an async work.
+ mImageProcessHelper.start(mBitmap);
mWallpaperManager.forgetLoadedWallpaper();
}
}
@@ -108,13 +108,13 @@ public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
@Override
public void onDrawFrame(GL10 gl) {
- float per85 = mImageProcessHelper.getPercentile85();
+ float threshold = mImageProcessHelper.getThreshold();
float reveal = mImageRevealHelper.getReveal();
glClear(GL_COLOR_BUFFER_BIT);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), 1);
- glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), per85);
+ glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), threshold);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal);
scaleViewport(reveal);