Android使用RenderScript处理图片

RenderScriptAndroid平台上简单快速处理图片效果的脚本工具,Renderscript``基于C99(Ed. C 语言)。使用前需要在Modulebuild.gradle文件中添加两行代码:

1
2
3
4
5
defaultConfig {
//略...
renderscriptTargetApi 24
renderscriptSupportModeEnabled true
}
  • renderscriptTargetApi - Specifies the bytecode version to be generated. We recommend you set this value to the lowest API level able to provide all the functionality you are using and set renderscriptSupportModeEnabled to true. Valid values for this setting are any integer value from 11 to the most recently released API level. If your minimum SDK version specified in your application manifest is set to a different value, that value is ignored and the target value in the build file is used to set the minimum SDK version.

    renderscriptTargetApi- 指定要生成的字节码版本。建议将此值设置为能够提供您正在使用的所有功能的最低API级别,并将renderscriptSupportModeEnabled设置为true。此设置的有效值是从11到最近发布的API级别的任何整数值。如果应用程序清单中指定的最低SDK版本设置为其他值,则忽略该值,并使用构建中的目标值设置最低SDK版本。

  • renderscriptSupportModeEnabled - Specifies that the generated bytecode should fall back to a compatible version if the device it is running on does not support the target version.

    renderscriptSupportModeEnabled - 指定生成的字节码如果运行的设备不支持目标版本,则应回退到兼容版本。

Renderscript将使用C写的脚本并行计算图片的每一个像素。一个脚本就是一个扩展名为'.rs'的文件,必须置于app/src/main/rsAndroid Studio 并不会为你生成这个目录或者任何脚本。

##使用ScriptInstrinsicBlur模糊图片

模糊图片,系统为我们提供了ScriptInstrinsicBlur工具类,不需要使用rs脚本渲染 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   public static Bitmap blurBitmap(Bitmap bitmap, float radius, Context context) {
//Create renderscript
RenderScript rs = RenderScript.create(context);

//Create allocation from Bitmap
Allocation allocation = Allocation.createFromBitmap(rs, bitmap);

Type t = allocation.getType();

//Create allocation with the same type
Allocation blurredAllocation = Allocation.createTyped(rs, t);

//Create script
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

//Set blur radius (maximum 25.0)
blurScript.setRadius(radius);
//Set input for script
blurScript.setInput(allocation);
//Call script for output allocation
blurScript.forEach(blurredAllocation);

//Copy script result into bitmap
blurredAllocation.copyTo(bitmap);

//Destroy everything to free memory
allocation.destroy();
blurredAllocation.destroy();
blurScript.destroy();
t.destroy();
rs.destroy();
return bitmap;

}

Renderscript.jar包中提供了简单的图片渲染工具类,例ScriptIntrinsicBlur,ScriptIntrinsicConvolve5x5,ScriptIntrinsicColorMatrix等。同时可以自定是rs文件,项目编译后会生成对应脚本类。例rs文件夹下有名为hist_Eq.rs文件,编译后会生成对应的ScriptC_histEq类。

直方图均衡化

​ Y 分量上的Histogram Equalization (前后对比)

Y的直方图均衡化算法很简单:

  1. 把RGB颜色空间转换成YUV颜色空间。
  2. 计算Y分量的直方图。
  3. 根据直方图重新映射Y分量。
  4. 重新把YUV转换回RGB颜色空间。

我们现在可以开始创建我们的rs文件了:histEq.rs,位于rs目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#pragma version(1)
#pragma rs_fp_relaxed
#pragma rs java_package_name(com.example.q.renderscriptexample)

#include "rs_debug.rsh"

int32_t histo[256];
float remapArray[256];
int size;

//Method to keep the result between 0 and 1
static float bound (float val) {
float m = fmax(0.0f, val);
return fmin(1.0f, m);
}

uchar4 __attribute__((kernel)) root(uchar4 in, uint32_t x, uint32_t y) {
//Convert input uchar4 to float4
float4 f4 = rsUnpackColor8888(in);

//Get YUV channels values
float Y = 0.299f * f4.r + 0.587f * f4.g + 0.114f * f4.b;
float U = ((0.492f * (f4.b - Y))+1)/2;
float V = ((0.877f * (f4.r - Y))+1)/2;

//Get Y value between 0 and 255 (included)
int32_t val = Y * 255;
//Increment histogram for that value
rsAtomicInc(&histo[val]);

//Put the values in the output uchar4, note that we keep the alpha value
return rsPackColorTo8888(Y, U, V, f4.a);
}

uchar4 __attribute__((kernel)) remaptoRGB(uchar4 in, uint32_t x, uint32_t y) {
//Convert input uchar4 to float4
float4 f4 = rsUnpackColor8888(in);

//Get Y value
float Y = f4.r;
//Get Y value between 0 and 255 (included)
int32_t val = Y * 255;
//Get Y new value in the map array
Y = remapArray[val];

//Get value for U and V channel (back to their original values)
float U = (2*f4.g)-1;
float V = (2*f4.b)-1;

//Compute values for red, green and blue channels
float red = bound(Y + 1.14f * V);
float green = bound(Y - 0.395f * U - 0.581f * V);
float blue = bound(Y + 2.033f * U);

//Put the values in the output uchar4
return rsPackColorTo8888(red, green, blue, f4.a);
}

void init() {
//init the array with zeros
for (int i = 0; i < 256; i++) {
histo[i] = 0;
remapArray[i] = 0.0f;
}
}

void createRemapArray() {
//create map for y
float sum = 0;
for (int i = 0; i < 256; i++) {
sum += histo[i];
remapArray[i] = sum / (size);
}
}

这里有几个方法:

  • bound(float val): 这个方法用于让结果保持在0到1之间。
  • root(): 这个方法是为input Allocation的每一个像素而调用(被叫做一个kernel)。它把像素从RGBA转换成YUVA,它把结果放在 output allocation。它还增加了Y直方图的值。
  • remaptoRGB(): 这个方法也是一个kernel。它重新映射Y值然后从YUVA转换回RGBA。
  • init(): 当在java中创建脚本的时候,这个方法自动被调用。它用0初始化数组。
  • createRemapArray(): 它为Y分量创建remap数组。

你可以像以往在c中那样创建方法。但是这里如果你需要像我在bound()中那样返回什么东西,这个方法必须是静态的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static Bitmap histogramEqualization(Bitmap image, Context context) {
//Get image size
int width = image.getWidth();
int height = image.getHeight();

//Create new bitmap
Bitmap res = image.copy(image.getConfig(), true);

//Create renderscript
RenderScript rs = RenderScript.create(context);

//Create allocation from Bitmap
Allocation allocationA = Allocation.createFromBitmap(rs, res);

//Create allocation with same type
Allocation allocationB = Allocation.createTyped(rs, allocationA.getType());

//Create script from rs file.
ScriptC_histEq histEqScript = new ScriptC_histEq(rs);

//Set size in script
histEqScript.set_size(width*height);

//Call the first kernel.
histEqScript.forEach_root(allocationA, allocationB);

//Call the rs method to compute the remap array
histEqScript.invoke_createRemapArray();

//Call the second kernel
histEqScript.forEach_remaptoRGB(allocationB, allocationA);

//Copy script result into bitmap
allocationA.copyTo(res);

//Destroy everything to free memory
allocationA.destroy();
allocationB.destroy();
histEqScript.destroy();
rs.destroy();

return res;
}

参考文章:

RenderScript :简单而快速的图像处理

RenderScript Overview | Android Developers

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×