A RxJava based library using native code to convert images to Lowpoly
RxLowpoly
An Android library to bring your ordinary photos to life with an awesome crystallized effect.
Introduction
RxLowpoly serves as an improvement over XLowPoly by
- fixing out of memory crashes by scaling down the image in a
loss-less manner before processing. - providing better quality results by using
4000
as the point count
by default which provides a good trade-off between speed and time. - the higher point count leads to a longer execution period, but it is
significantly reduced by scaling down the image before processing. - provides wider choice of input sources like
Bitmap
,File
,Uri
orDrawable resource
. - natively using
RxJava
for background processing thereby reducing
boilerplate code on the developer's end.
Lowpoly Samples
Original Image | Lowpoly Image |
---|---|
Installation
Add the dependency in your app module's build.gradle file
dependencies {
...
implementation "com.zebrostudio.rxlowpoly:rxlowpoly:{latest_version}"
}
That's it!
Library Details
- RxLowpoly uses JNI with 64 bit support to meet google
specified requirement for all apps to be 64 bit enabled by August
2019. - Use of JNI enables much faster execution than other similar libraries.
- Use of Sobel Operator for edge detection.
- Use of Delaunay Triangulation on the
result from the sobel operator to construct the final crystallized
lowpoly effect on the image.
JNI
RxLowpoly uses the Java Native Interface to run native code written in C
which provides much faster processing for edge detection using the Sobel Operator and then implementing the Delaunay Triangulation algorithm.
Sobel Operator
The Sobel Edge Detector is a gradient based edge detection algorithm which provides us with separate planes on which the Delaunay Triangulation can be applied.
Delaunay Triangulation
We take a set P of discrete points on an image plane and apply Delaunay
Triangulation DT(P) to produce triangles connecting 3 points at
a time such that no point in **P **is inside the circum-circle of any
triangle in DT(P). These separate triangles taken together in-turn
provide us with the image having a crystallized effect.
Which leads to the resultant crystallized image as :-
Usage Examples
Asynchronous call
-
The most simple use case is :-
RxLowpoly.with(context) .input(bitmap) .generateAsync()
Along with
Bitmaps
we can also useDrawables
orFiles
orUri
as input. -
When we need to downscale the image :-
RxLowpoly.with(context) .input(bitmap) .overrideScaling(downScalingFactor) .generateAsync()
-
When we need to set a maximum width for the image :-
RxLowpoly.with(context) .input(bitmap) .overrideScaling(maxWidth) .generateAsync()
-
We can also set a quality for the lowpoly image :-
RxLowpoly.with(context) .input(inputUri) .overrideScaling(downScalingFactor) .quality(Quality.HIGH) .generateAsync()
VERY_HIGH
,MEDIUM
,LOW
andVERY_LOW
are also available as
Quality configurations -
To save the lowpoly image to a file :-
RxLowpoly.with(context) .input(inputUri) .overrideScaling(downScalingFactor) .quality(Quality.HIGH) .output(outputFile) // An Uri of a File is also supported as an output destination .generateAsync()
All asynchronous operation is done on the IO scheduler
.
Synchronous call
Replacing generateAsync()
with generate()
in each of the Asynchronous call examples leads to a synchronous call with a lowpoly Bitmap
as a result.
A Bitmap
of the generated lowpoly image is always returned irrespective of synchronous or asynchronous calls and whether an output File
or Uri
is supplied using the output
method.
Note : A full implementation can be found in the app module of this repository or in the open sourced WallR app.
Critical Analysis
The following tests have been performed on a Xiaomi Redmi Note 5 Pro with 6 gb Ram.
Original Image | Lowpoly Image | Input Source | Quality | Execution Time (ms) |
---|---|---|---|---|
Bitmap | Very High | 15813 | ||
Drawable | Very High | 16275 | ||
File | Very High | 15987 | ||
Uri | Very High | 15931 | ||
Bitmap | High | 4547 | ||
Drawable | High | 5088 | ||
File | High | 4734 | ||
Uri | High | 4612 | ||
Bitmap | Medium | 1113 | ||
Drawable | Medium | 1672 | ||
File | Medium | 1297 | ||
Uri | Medium | 1152 | ||
Bitmap | Low | 918 | ||
Drawable | Low | 1496 | ||
File | Low | 1091 | ||
Uri | Low | 996 | ||
Bitmap | Very Low | 850 | ||
Drawable | Very Low | 1024 | ||
File | Very Low | 923 | ||
Uri | Very Low | 876 |
Thus it is evident that when quality is set to High
, a good trade-off between speed and texture is obtained, hence the default value of Quality
is set to HIGH
.
Also, we can see that Bitmap
is the input format of choice as it is processed the fastest, followed by Uri
, File
and Drawable
respectively.
Sample App
The sample app provides an implementation of various configurations of RxLowpoly
which one can experience and assess first hand before using the library.
Screenshots