您的位置:首页 > 移动开发 > Android开发

Android Camera 实时滤镜

2016-05-19 18:33 686 查看
版权声明:转载自/article/2402845.html

一、Android系统将内置滤镜功能

滤镜功能有二十余种不同效果,不逊色于极受欢迎的智能手机应用Instagram所产生的效果。



1、颜色矩阵 ColorMatrix
android中可以通过颜色矩阵(ColorMatrix类)方面的操作颜色,颜色矩阵是一个5x4 的矩阵。可以用来方面的修改图片中RGBA各分量的值,颜色矩阵以一维数组的方式存储如下:

[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]

他通过RGBA四个通道来直接操作对应颜色,如果会使用Photoshop就会知道有时处理图片通过控制RGBA各颜色通道来做出特殊的效果。
这个矩阵对颜色的作用计算方式如示:



矩阵的运算规则是矩阵A的一行乘以矩阵C的一列作为矩阵R的一行,
C矩阵是图片中包含的ARGB信息,R矩阵是用颜色矩阵应用于C之后的新的颜色分量,运算结果如下:
R’ = aR + bG + cB + dA + e;

G’ = fR + gG + hB + iA + j;

B’ = kR + lG + mB + nA + o;

A’ = pR + qG + rB + sA + t;
Ps:第1~3列是控制色相的,第4列是控制透明度的,第5列是分量的增加值。
2、基本滤镜效果的实现:
如果我们用ColorMatrix调整RGB三种颜色的比重,就可以实现诸如单色、黑白的效果。
3、Lomo滤镜效果的实现:
改变图像数值+遮罩

二、Android平台滤镜

滤镜这个功能在目前的市场上应用很广泛,发展也非常快,总结起来,基本上有以下三种应用会包含滤镜功能,都各有所长。



#

二、相机滤镜介绍

1、相机360镜介绍
相机360的滤镜特效类别比较多,每一类别又分为不同的特效。
其最主要的特点是它具有实时拍照滤镜功能,且在关闭重新进入后可记忆之前选择的滤镜。
缺点是滤镜效果一般,而且选择滤镜的交互比较复杂,不好操作。





2、魔幻时刻相机滤镜介绍(静态滤镜)
魔幻时刻相机Magic Hour是一款从ios移植过来的优秀拍照软件。
从其滤镜管理和滤镜库的丰富程度就可以看出这款相机的偏重点了!具有大量的滤镜效果且支持下载。滤镜管理页面很“整洁”,易操作。





三、图片美化滤镜

在图片美化界,美图秀秀是当之无愧的NO.1,其滤镜效果按照tab页的方式分为几类供选择,操作非常直观,且每一种特效都会有非常漂亮的效果。



Pixlr-0-matic,这款图片处理工具的滤镜不管从UI设计来讲还是从交互来讲都非常赞,而且它的滤镜还有增加光影效果、色相效果等功能,美化照片能力超强。



四、社交分享滤镜

社交应用也越来越注重图片分享时的滤镜功能。

腾讯微博的滤镜效果如图,交互简洁,清爽,滤镜效果很佳,一推出便得到广泛应用和赞扬。



Path是得到普遍认可的优秀产品,包括其滤镜效果。

简洁是社交分享滤镜的最主要特点,path的滤镜也承袭了这一风格,且滤镜效果很佳。



五、总结



1、采用实时拍照滤镜,在成相的同时可以使用户看到自己想要的照片效果。
2、滤镜种类不宜过多,把握关键的最受用户喜欢的滤镜效果,比如:素描、油画、炫彩、老照片等经典效果。
3、追求高质量滤镜效果,我们要让每一个滤镜都能够使照片变得更加漂亮,而不是鸡肋效果。
4、交互上尽量简洁,一目了然,避免多重选择和切换。

七、基于Android平台基本滤镜算法的实现

1、Android提供了改变图像数值的方法ColorMatrix,通过ColorMatrix方法可以实现基本滤镜,如黑白、灰色、泛黄等效果。
2、通过ColorMatrix改变图像数值,生成变换矩阵,利用矩阵相乘,来改变每个点的像素值。
Matrix =>
r1 r2 r3 r4
g1 g2 g3 g4
b1 b2 b3 b4
a1 a2 a3 a4

变化以后
R’ = R r1 + G r2 + B r3 + A r4 + r5;
G’ = R g1 + G g2 + B g3 + A g4 + g5;
B’ = R b1 + G b2 + B b3 + A b4 + b5;
A’ = R a1 + G a2 + B a3 + A a4 + a5;
第1~3列是控制色相的,第4列是控制透明度的,第5列是分量的增加值
3、R、G、B、A系数值变化会修改图像的效果
(1)对角线值为1.0,其他为0时,图像保证的是原图像





(2)对角线值若大于1.0,其他为0时,图像偏亮





(3)对角线值若小于1.0,其他为0时,图像偏暗





(4)设定图像为灰色,通过查资料 R 0.3 G0.59 B 0.11





4、根据以上的实现,实现基本滤镜的算法是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public Bitmap getBlackStyle(Bitmap src){

Bitmap dst = Bitmap.createBitmap(src.getWidth(),src.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(dst);
ColorMatrix cm = new ColorMatrix();
//设定图像为灰色,通过查资料 R 0.3 G0.59 B 0.11
cm.set(new float[] {
0.3f, 0.59f, 0.11f, 0, 0,
0.3f, 0.59f, 0.11f, 0, 0,
0.3f, 0.59f, 0.11f, 0, 0,
0, 0, 0, 1, 0 });
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(src, 0, 0, paint);
// 保存图像
canvas.save(Canvas.ALL_SAVE_FLAG);
// 存储
canvas.restore();
return dst;
}

八、后滤镜时代

在网上看到一些信息和相机应用,很多相机玩家对手机相机的使用是越来越多,作为手机相机的开发者需要有更多的创意和特性为手机相机添彩!如下几点相机的发展方向供大家参考:



(1)实时滤镜
VIDA 是一款来自国内团队的照相应用,它的一大特色就是实时滤镜,在拍摄的同时你已经可以

预览到最终的成品。这是一个强化滤镜功能的方向。和单纯的加入新滤镜不同,实时滤镜把握住了

所见即所得的精髓。
(2)GIF 动画
GIFshop 是 一款快速制作定格动画的应用。它结合了动态画面的叙事能力,保留了图片的小体积特点。但 GIFshop 的问题也非常突出,比起记录生活,它更适合于创作一些幽默的动态小品。一旦涉及到 “创作” ,用户的门槛就被无情地提高了。但让画面动起来的想法要比单纯的强化滤镜要走的更远一些。
(3)动态图片

Cinemagram 制 作出来的图片可以只在某一特定区域中出现动态效果。你可以那它创建那种网

上流行的“会动的海报”。比起 GIFshop ,它能够让普通的记事照片变得有点魔幻。由于应用的

构思巧妙,因此适合套用在不同的场合中。用户的门槛相对较小,但收获却是挺大的。我将其看作是 GIFshop 的改进版本。
(4)声音+图片
Picle 是 一款让你在拍摄相片的同时也记录下一段音频的应用。它的好处是让 “画外音” 这一有趣的角色参与照片的叙事。相比上述应用,Picle 进入了另个维度,它考虑到图片的叙事瓶颈,并试图通过加入音频来突破。Picle 所面临的问题是,它建立了一种新的格式,而这种格式目前还只能在 Picle 体系内分享。
后滤镜时代里各支团队在不同方向上设定了不同的瓶颈,并通过一定的方法来突破。思考的起点无一例外的定在了增强图片叙事能力之上。从目前的情况来看,有一些事项值得注意:
· 体积:不能因为增强了效果而变得臃肿。
· 题材:不能因为特别适合某种题材而狭隘了用户的使用场景。
· 格式:在现有流行的格式上入手,避免使用新格式。
· 门槛:在用户利益和使用复杂度上寻求平衡。
· 多媒体:在图片上做加法,但不能演变成拍摄视频。
相信随着硬件技术的增强,手机将成为一类新的照相设备。它也许替代不了传统的相机,但
它却能因为应用而变得不可替代。而可以预见的是,滤镜不会是手机照相的最后一站。

九,基于Android平台PS特效的自定义算法的实现



在ARGB颜色空间,分别使用A(Transparency)、R(Red)、G(Green)、B(Blue)四个值来描述一个像素点,那么对于一个宽w高h的图片来说,共有wh个像素点,可以用一个数组对象int [] pixels来表示相应的图片,pixels = { p1,p2,p3…}。在把各个像素点都用ARGB来表示,那么这张图片就可以用一个[wh,4]的矩阵来描述:

1
2
3
4
5
6

pixels = {
pa1,pr1,pg1,pb1,
pa2,pr2,pg2,pb2,
pa3,pr3,pg3,pb3,
……
}

android平台在获取像素方面提供了 Bitmap.getPixels 方法,我需要做的是遍历图像的像素点,对每一个像素点进行计算。然后将计算完的像素点通过Color.red/green/blue 方法处理后,将像素点填回Bitmap,从而得到滤镜后的图像。这种方式比ColorMatrix 要灵活,可以满足PS特效的实现效果。
1、简单的反色滤镜实现
取出图片的像素点,然后用255减去每个像素点,那么得到的就是一张有反色效果的图片




算法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
22
23
24
25
26
27
28
29
30
31

/**
* @author neil
*/
public class AntiColorFilter implements ImageFilterInterface {

private ImageData image = null; // 图片信息类

public AntiColorFilter(Bitmap bmp) {
image = new ImageData(bmp);
}

public ImageData imageProcess() {
int width = image.getWidth();
int height = image.getHeight();
int R, G, B, pixel;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
R = image.getRComponent(x, y); // 获取RGB三原色
G = image.getGComponent(x, y);
B = image.getBComponent(x, y);

R = 255 - R;
B = 255 - B;
G = 255 - G;

image.setPixelColor(x, y, R, G, B);
} // x
} // y
return image;
}
}

2、油画滤镜的实现
通过查资料了解到油画滤镜的算法是”用当前点四周一定范围内任意一点的颜色来替代当前点颜色,最常用的是随机的采用相邻点进行替代”



算法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
22
23
24
25
26

public ImageData imageProcess() {
int width = image.getWidth();
int height = image.getHeight();
int R, G, B, pixel,xx = 0,yy = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pos = getRandomInt(1, 10000) % Model;
xx = (x + pos) < width ? (x + pos) : (x - pos) >= 0 ? (x - pos) : x;
yy = (y + pos) < height ? (y + pos) : (y - pos) >= 0 ? (y - pos) : y;

R = image.getRComponent(xx, yy); // 获取RGB三原色
G = image.getGComponent(xx, yy);
B = image.getBComponent(xx, yy);

image.setPixelColor(x, y, R, G, B);
} // x
} // y

return image;
}

public static int getRandomInt(int a, int b) {
int min = Math.min(a, b);
int max = Math.max(a, b);
return min + (int)(Math.random() * (max - min + 1));
}

3、冰冻滤镜的实现
冰冻滤镜的算法是将像素点颜色加深,每个象素都用RGB三原色来表示,(0,0,0)就是纯黑,而(255,255,255)就是纯白,因此将没个像素点的RGB指变小,颜色就会加深



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

int width = image.getWidth();
int height = image.getHeight();
int R, G, B, pixel;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
R = image.getRComponent(x, y); // 获取RGB三原色
G = image.getGComponent(x, y);
B = image.getBComponent(x, y);

pixel = R - G - B;
pixel = pixel * 3 / 2;
if (pixel < 0)
pixel = -pixel;
if (pixel > 255)
pixel = 255;
R = pixel;

pixel = G - B - R;
pixel = pixel * 3 / 2;
if (pixel < 0)
pixel = -pixel;
if (pixel > 255)
pixel = 255;
G = pixel;

pixel = B - R - G;
pixel = pixel * 3 / 2;
if (pixel < 0)
pixel = -pixel;
if (pixel > 255)
pixel = 255;
B = pixel;

image.setPixelColor(x, y, R, G, B);
} // x
} // y

Android 静态滤镜的实现

一、回顾知识点
1、基本滤镜效果的实现(黑白滤镜)

用到的技术是ColorMatrix。通过改变RGBA的系数,从而改变图像的成像效果。



2、PS滤镜效果的实现(反色效果、冰冻效果、油画效果)

用到的技术是通过遍历图像的像素点,设置图像的像素点的RGB三原色来实现PS效果。



二、静态滤镜的实现

基于之前积累下来的知识点,在对静态滤镜的实现方面做一下提升,还是从两方面进行实现。
1、基本滤镜效果升级版 –> 伪lomo滤镜的实现



step1:原始图片



step2:ColorMatrix处理



step3:在处理后的图片上覆盖一层彩色lomo图片



step4:覆盖上彩色lomo后的效果



step5:伪lomo滤镜效果



2、PS滤镜效果升级版 –> 老照片滤镜的实现
(1)HSL颜色标准

HSL色彩模式是工业界的一种颜色标准,是通过对色调(H)、饱和度(S)、亮度(L)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜 色的,HSL即是代表色调,饱和度,亮度三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。   
HSL色彩模式使用HSL模型为图像中每一个像素的HSL分量分配一个0~255范围内的强度值。HSL图像只使用三种通道,就可以使它们按照不同的比例混合,在屏幕上重现16777216种颜色。   
在 HSL 模式下,每种 HSL 成分都可使用从 0到 255的值。(其中L是从黑(0)到白(255)渐变) 。

老照片效果的总体思路是,对色调、饱和度、亮度进行处理,而非之前的红绿蓝色调处理。

(2)算法实现



效果图



HSL色彩模式

1、颜色HSL
H: hue 色调  
: saturation 饱和度   
L: lum 亮度

2、概述

HSL色彩模式是工业界的一种颜色标准,是通过对色调(H)、饱和度(S)、亮度(L)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,HSL即是代表色调,饱和度,亮度三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。   
HSL色彩模式使用HSL模型为图像中每一个像素的HSL分量分配一个0~255范围内的强度值。HSL图像只使用三种通道,就可以使它们按照不同的比例混合,在屏幕上重现16777216种颜色。   
在 HSL 模式下,每种 HSL 成分都可使用从 0到 255的值。(其中L是从黑(0)到白(255)渐变) 。



3、HSL与RGB转换
a. RGB→HSL的算法描述

步骤1:把RGB值转成【0,1】中数值。

步骤2:找出R,G和B中的最大值。

步骤3:设L=(maxcolor + mincolor)/2

步骤4:如果最大和最小的颜色值相同,即表示灰色,那么S定义为0,而H未定义并在程序中通常写成0。

步骤5:否则,测试L:

  If L<0.5, s="(maxcolor-mincolor)/(maxcolor" +="" mincolor)="" <="" br="">

  If L>=0.5, S=(maxcolor-mincolor)/(2.0-maxcolor-mincolor)

步骤6: If R=maxcolor, H=(G-B)/(maxcolor-mincolor)

  If G=maxcolor, H=2.0+(B-R)/(maxcolor-mincolor)

  If B=maxcolor, H=4.0+(R-G)/(maxcolor-mincolor)

步骤7:从第6步的计算看,H分成0~6区域。RGB颜色空间是一个立方体而HSL颜色空间是两个六角形 锥体,其中的L是RGB立方体的主对角线。因此,RGB立方体的顶点:红、黄、绿、青、蓝和品红就成为HSL六角形的顶点,而数值0~6就告诉我们H在哪个部分。H=H*60.0,如果H为负值,则加360。

b. HSL→RGB的算法描述

步骤1:If S=0,表示灰色,定义R,G和B都为L.

步骤2:否则,测试L:

   If L<0.5,temp2=l*(1.0+s) <="" br="">

   If L>=0.5,temp2=L+S-LS

步骤3:temp1=2.0-temp2

步骤4:把H转换到0~1。

步骤5:对于R,G,B,计算另外的临时值temp3。方法如下:

   for R, temp3=H+1.0/3.0

   for G, temp3=H

   for B, temp3=H-1.0/3.0

   if temp3<0, temp3="temp3+1.0" <="" br="">

   if temp3>1, temp3=temp3-1.0

步骤6:对于R,G,B做如下测试:

   If 6.0temp3<1,color=temp1+(temp2-temp1)6.0temp3

   Else if 2.0temp3<1,color=temp2 <="" br="">

   Else if 3.0temp3<2, <="" br="">

   color=temp1+(temp2-temp1)((2.0/3.0)-temp3)*6.0

   Else color=temp1

实例





HSL色彩模式与RGB色彩模式转换代码实现

RGB色彩模式




HSL色彩模式




HSL色彩模式与RGB色彩模式转换算法

HSL与RGB转换

RGB类
1
2
3
4
5
67

public class ColorRGB {

public int r;
public int g;
public int b;

}

HSL类
1
2
3
4
5
67

public class ColorHSL {

public int h;
public float s;
public float l;

}

a) RGB→HSL的算法描述。

步骤1:把RGB值转成【0,1】中数值。

步骤2:找出R,G和B中的最大值。

步骤3:设L=(maxcolor + mincolor)/2

步骤4:如果最大和最小的颜色值相同,即表示灰色,那么S定义为0,而H未定义并在程 序中通常写成 0。

步骤5:否则,测试L:

  If L<0.5, s="(maxcolor-mincolor)/(maxcolor" +="" mincolor)=""

  If L>=0.5, S=(maxcolor-mincolor)/(2.0-maxcolor-mincolor)

步骤6: If R=maxcolor, H=(G-B)/(maxcolor-mincolor)

  If G=maxcolor, H=2.0+(B-R)/(maxcolor-mincolor)

  If B=maxcolor, H=4.0+(R-G)/(maxcolor-mincolor)

步骤7:从第6步的计算看,H分成0~6区域。RGB颜色空间是一个立方体而HSL颜色空间是两个六角形锥体,其中的L是RGB立方体的主对角线。因此,RGB立方体的顶点:红、黄、绿、青、蓝和品红就成为HSL六角形的顶点,而数值0~6就告诉我们H在哪个部分。H=H*60.0,如果H为负值,则加360。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

private static ColorHSL colorRGBToHSL(ColorRGB rgb) {

ColorHSL hsl = new ColorHSL();

float r, g, b, h, s, l;
r = rgb.r / 255.0f;
g = rgb.g / 255.0f;
b = rgb.b / 255.0f;

float maxColor = Math.max(r, Math.max(g, b));
float minColor = Math.min(r, Math.min(g, b));

if (maxColor == minColor) {
h = 0.0f;
s = 0.0f;
l = r;
} else {
l = (minColor + maxColor) / 2;

if (l < 0.5)
s = (maxColor - minColor) / (maxColor + minColor);
else
s = (float) ((maxColor - minColor) / (2.0 - maxColor -
minColor));

if (r == maxColor)
h = (g - b) / (maxColor - minColor);
else if (g == maxColor)
h = (float) (2.0 + (b - r) / (maxColor - minColor));
else
h = (float) (4.0 + (r - g) / (maxColor - minColor));

h /= 6;
if (h < 0)
h++;
}

hsl.h = (int) Math.round(h * 360.0);
hsl.s = s;
hsl.l = l;

return hsl;
}

b) HSL→RGB的算法描述

步骤1:If S=0,表示灰色,定义R,G和B都为L.

步骤2:否则,测试L:

   If L<0.5,temp2=l*(1.0+s)

   If L>=0.5,temp2=L+S-LS

步骤3:temp1=2.0-temp2

步骤4:把H转换到0~1。

步骤5:对于R,G,B,计算另外的临时值temp3。方法如下:

   for R, temp3=H+1.0/3.0

   for G, temp3=H

   for B, temp3=H-1.0/3.0

   if temp3<0, temp3="temp3+1.0"

   if temp3>1, temp3=temp3-1.0

步骤6:对于R,G,B做如下测试:

   If 6.0temp3<1,color=temp1+(temp2-temp1)6.0temp3

   Else if 2.0temp3<1,color=temp2

   Else if 3.0temp3<2,

   color=temp1+(temp2-temp1)((2.0/3.0)-temp3)*6.0

   Else color=temp1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2021
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

private static ColorRGB colorHSLToRGB(ColorHSL hsl) {

ColorRGB rgb = new ColorRGB();

float r, g, b, h, s, l;
float temp1, temp2, tempr, tempg, tempb;
h = hsl.h / 360.0f;
s = hsl.s;
l = hsl.l;

if (s == 0) {
r = g = b = l;
} else {
if (l < 0.5)
temp2 = l * (1 + s);
else
temp2 = (l + s) - (l * s);
temp1 = 2 * l - temp2;
tempr = (float) (h + 1.0 / 3.0);
if (tempr > 1)
tempr--;
tempg = h;
tempb = (float) (h - 1.0 / 3.0);
if (tempb < 0)
tempb++;

// Red
if (tempr < 1.0 / 6.0)
r = (float) (temp1 + (temp2 - temp1) * 6.0 * tempr);
else if (tempr < 0.5)
r = temp2;
else if (tempr < 2.0 / 3.0)
r = (float) (temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempr)
* 6.0);
else
r = temp1;

// Green
if (tempg < 1.0 / 6.0)
g = (float) (temp1 + (temp2 - temp1) * 6.0 * tempg);
else if (tempg < 0.5)
g = temp2;
else if (tempg < 2.0 / 3.0)
g = (float) (temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempg)
* 6.0);
else
g = temp1;

// Blue
if (tempb < 1.0 / 6.0)
b = (float) (temp1 + (temp2 - temp1) * 6.0 * tempb);
else if (tempb < 0.5)
b = temp2;
else if (tempb < 2.0 / 3.0)
b = (float) (temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempb)
* 6.0);
else
b = temp1;
}

rgb.r = (int) Math.round(r * 255.0);
rgb.g = (int) Math.round(g * 255.0);
rgb.b = (int) Math.round(b * 255.0);

return rgb;
}

Android Camera可以做哪些?

1、功能

拍摄相片
视频录制
取景器(扫描类应用,如人脸识别,名片识别,条形码识别)

2、根据Camera API实现自己的拍照程序,共7步



Camera Preview是什么?



摄像头返回的RAW数据经过isp处理后形成yuv数据,android系统将该数据绘制到取景区上,不断绘制帧数据形成实时预览数据。

如何获取Camera Preview中的数据?

Camera.PreviewCallback
setPreviewCallback

屏幕上显示一个新的预览帧时调用onPreviewFrame方法(时时获取)
setPreviewCallbackWithBuffer

其与setPreviewCallback的工作方式相同,但要求指定一个字节数

组作为缓冲区,用于预览图像数据(addCallbackBuffer)

Android Camera 实时滤镜怎么做?



YUV转RGB的算法,转换的公式一般如下,也是线性的关系:

R = Y + 1.14V

G = Y - 0.39U - 0.58V

B = Y + 2.03U



问题

1、屏幕卡顿,用户体验低

2、性能低,影响系统性能

如何优化?

提高流程度

图像渲染采用OpenGL ES SurfaceTexture

提高性能

GPU优化
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: