The document discusses efficient image processing techniques for Android, focusing on the RenderScript framework. It provides an overview of RenderScript, how to write kernels in C, and how to call them from Java. Examples are given for common image processing tasks like grayscale conversion, bloom effects, and local adjustments. Caching strategies and handling low-memory devices are also covered to ensure performance across all hardware.
2. EFFICIENT IMAGE PROCESSING
•
Works well on all hardware
•
Fast, ideally realtime interaction
•
Handles complex and flexible processing
•
Handles large images
•
Minimize memory usage
8. 4.2 - NOVEMBER 2012
•
Color FX (9 looks)
•
11 Borders
•
Geometry: Straighten, Rotate, Crop, Mirror
•
Filters & Tools
•
Autocolor, Exposure, Vignette, Contrast, Shadows, Vibrance,
Sharpness (RS-based), Curves, Hue, Saturation, BW Filter
•
Non-destructive edits (in the editor -- save create a copy)
•
Exposed history
9. G+ EDITOR - MAY 2013
•
RenderScript implementations of Snapseed filters
•
Frames, Film, Drama, Retrolux
•
Non-destructive
•
Cloud-based (local processing only used for caching and UI
interactions)
10. 4.3 - JULY 2013
•
Move to RenderScript
•
New 16 image-based borders (ported from Snapseed, RS-based)
•
Filters & Tools
•
•
•
Highlights, Improved Vignette
Local adjustment (ported from Snapseed, RS-based)
New Tablet UI, refined UI, introduction of the state panel instead of
the history panel
11. 4.4 - SEPTEMBER 2013
•
Filters & Tools
•
Custom borders, Drawing tool, negative, posterize
•
RS filters: Graduated filter, Vignette, per channel saturation,
sharpness/structure
•
Refined UI (animations, etc.)
•
Pinch to zoom enabled (full-res zoom)
•
Re-edits enabled
•
Background save service, export, print support
15. SOME ADDITIONAL INFOS
•
Phone and Tablet UI
•
Filters in C & RenderScript
•
Works on Full Size images -- largest tried was a 278MP image on a
Nexus 7 2nd gen. Limited by available RAM.
•
Nearly all of the editor is in AOSP!
22. NATIVE CODE
•
Pass a Bitmap through JNI to C/C++
•
Quite fast & pretty easy to work with (pointer to the bitmap -- and
no GC!)
•
JNI / Native can be fastidious
•
Handling different CPU architectures can be an issue
•
Optimizations can be complicated
•
JNI management
23. OPENGL ES 2.0
•
Fast -- can write interactive processing
•
Hard to ensure the shaders will perform well on all devices
•
Limited in size (max texture size...)
•
Needs adhoc shaders, i.e. fixed pipelines.
•
Expensive to retrieve processed image
25. “RENDERSCRIPT IS A FRAMEWORK FOR RUNNING
COMPUTATIONALLY INTENSIVE TASKS AT HIGH PERFORMANCE ON
ANDROID. RENDERSCRIPT IS PRIMARILY ORIENTED FOR USE WITH
DATA-PARALLEL COMPUTATION, ALTHOUGH SERIAL
COMPUTATIONALLY INTENSIVE WORKLOADS CAN BENEFIT AS WELL.”
26. •
Write “kernels” in a C99-like language with vector
extensions and useful intrinsics
•
RenderScript executes them in parallel, on the GPU or
CPU
•
Java used to manage lifetime of objects/allocations and
control of execution
•
Portability
27. RENDERSCRIPT
•
Fast -- through LLVM optimizations and Parallelization
•
Supports CPU / GPU
•
Compatibility Library
•
Easy to offload to the background
•
Pretty easy to write
28. RENDERSCRIPT
•
Cannot allocate memory from kernels, need to do it from outside
•
RenderScript can be called from Java or from Native
•
Compatibility library!
61. EXAMPLE: BLOOM
•
Select the bright pixels
•
Blur the result
•
Add the blurred bright pixels back to the image
64. WITH JAVA
private void brightPass(int[] pixels, int width, int height) {
int threshold = (int) (brightnessThreshold * 255);
int r;
int g;
int b;
int luminance;
int[] luminanceData = new int[3 * 256];
// pre-computations
for (int i = 0; i <
luminanceData[i
luminanceData[i
luminanceData[i
}
for conversion from RGB to YCC
luminanceData.length; i += 3) {
] = (int) (i * 0.2125f);
+ 1] = (int) (i * 0.7154f);
+ 2] = (int) (i * 0.0721f);
65. int index = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = pixels[index];
// unpack the pixel's components
r = pixel >> 16 & 0xFF;
g = pixel >> 8 & 0xFF;
b = pixel
& 0xFF;
// compute the luminance
luminance = luminanceData[r * 3] + luminanceData[g * 3 + 1] +
luminanceData[b * 3 + 2];
// apply the treshold to select the brightest pixels
luminance = Math.max(0, luminance - threshold);
int sign = (int) Math.signum(luminance);
// pack the components in a single pixel
pixels[index] = 0xFF000000 | (r * sign) < < 16 |
(g * sign) << 8 | (b * sign);
index++;
}
}
}
70. WORKING WELL ON ALL
HARDWARE
•
Architect for the worst
•
Scale with the device capabilities
•
Screen size / dpi
•
Available memory
•
Available CPU / GPU
•
Think about what is a downgraded experience
71. LOADING
•
Load in the background
•
•
AsyncTask, or use a background thread
Bitmaps loading
•
query the size
•
inSampleSize
•
reuseBitmap
•
BitmapRegionDecoder
72. QUERY THE SIZE
BitmapFactory.Options options =
new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(
getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
73. INSAMPLESIZE
•
Only load what you need
•
needs to be a power of two, so for a 2048x2048 image,
•
insamplesize=2
=> 1024x1024 image
•
insamplesize=4 => 512x512 image
74. CALCULATE INSAMPLESIZE
if (bounds.width() > destination.width()) {
int sampleSize = 1;
int w = bounds.width();
while (w > destination.width()) {
sampleSize *= 2;
w /= sampleSize;
}
options.inSampleSize = sampleSize;
}
78. PIPELINE
•
Run in a background service (used when saving too)
•
Mix C, RenderScript, java filtering (canvas draw)
•
multiple pipelines in parallel (direct preview, highres, icons, full res,
geometry, saving)
82. CACHING
•
Cache RS scripts, allocations
•
Cache original bitmaps
•
Aggressively destroy/recycle resources in filters to keep memory low
•
If possible, filters should process the input bitmap directly
•
N-1 cache
83. MEMORY USAGE
•
Bitmap cache heavily reusing bitmaps
•
LruCache class (available in support lib too)
•
Pick image sizes depending on the device resolution / DPI
•
Have a path ready for a downgraded experience
84. DEVICE CAPABILITIES
•
Ask the system
•
Runtime.getRuntime().maxMemory()
•
New isLowRamDevice() API
•
Handles low-memory signals
•
Handles java.lang.OutOfMemory exceptions
97. N-1 CACHING
•
No silver bullet
•
Only really useful when the user manipulates the last filters of the
pipeline...
•
...but this is after all the more common scenario!
104. HOW TO CHEAT
•
The triple-buffer preview can have a low resolution
•
The UI elements and controls are animated and manipulated at 60 fps
on the UI thread
•
The rendering pipeline can (and needs to) be interrupted
109. FULL RESOLUTION
PREVIEW
•
Ideally, we should use a tile-based rendering
•
At the moment, we use BitmapFactory region decoder instead
•
Filters need to be able to handle partial regions
•
future payoff: streaming save
111. FUTURE -- IN THE PHOTO
EDITOR
•
Merging filters
•
•
•
RenderScript
At the pipeline level (color cubes...)
Streaming saving
•
Some code is there (AOSP), but not used
112. FUTURE -- IN ANDROID
FRAMEWORK
•
TileView
•
Adding filtering pipeline in android framework
•
Image loader improvements
•
RAW support? Color correction?
116. TILEVIEW ADAPTER
public interface TileViewAdapter {
public int getTileSize();
public int getContentWidth();
public int getContentHeight();
public void onPaint(float scale,
float dx, float dy, Bitmap bitmap);
public Bitmap getFullImage(int max);
void setDebug(boolean debug);
}