zoukankan      html  css  js  c++  java
  • Android Camera2 Opengles2.0 实时滤镜(冷暖色/放大镜/模糊/美颜)

    https://blog.csdn.net/keen_zuxwang/article/details/78363464

    demo:
    http://download.csdn.net/download/keen_zuxwang/10041423

    1、创建顶点位置、纹理数组
    2、创建、编译、加载shader程序,获得shader中各变量的句柄(如获取纹理采样sampler2D变量的句柄)
    3、程序通过program给shader传递各参量,如:顶点位置、纹理坐标,激活、绑定纹理,传递模型/视图/投影矩阵等, 然后通过glDrawArrays()/glDrawElements()绘制图元(片元着色器通过这些参量计算出每个像素的值、然后通过底层EGL 渲染到相应的ANativeWindow)

    camera2 摄像头图像opengles渲染显示:
    1、生成纹理
    GLES20.glGenTextures(1, textures, 0); // 产生纹理id
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);//绑定 纹理id
    2、创建SurfaceTexture
    SurfaceTexture videoTexture = new SurfaceTexture(textures[0]); //通过创建的纹理id,生成SurfaceTexture
    3、生成Surface
    Surface surface0 = new Surface(videoTexture); // 通过创建的SurfaceTexture,生成Surface
    4、添加camera2预览输出Surface,从而实现camera图像 -> Surface
    mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // 创建camera2 捕获请求,预览模式
    //添加预览输出的Surface, 从而实现camera图像 -> Surface
    mPreviewBuilder.addTarget(surface);
    mPreviewBuilder.addTarget(surface0);
    camera.createCaptureSession(Arrays.asList(surface, surface0), mSessionStateCallback, null); // 创建捕获会话

    所以整个摄像头图像渲染流程:
    camera图像 -> Surface -> videoTexture/videoTexture.updateTexImage() -> GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]) ->
    GLES20.glDrawElements()

    1、vertex shader

    attribute vec4 vPosition;
    attribute vec4 vTexCoordinate;
    uniform mat4 textureTransform;
    uniform mat4 uProjMatrix;
    uniform mat4 uProjMatrix0;
    uniform int xyFlag; // 镜像选择

    //参量传递->fragment shader
    varying vec2 v_TexCoordinate;
    varying vec4 gPosition;
    varying vec2 varyPostion;

    void main () {
    v_TexCoordinate = (textureTransform * vTexCoordinate).xy;
    //gl_Position = vPosition;
    if(xyFlag==0){
    gl_Position = vPosition;
    }else if(xyFlag==1){
    gl_Position = uProjMatrix*vPosition; //变换矩左乘
    }else if(xyFlag==2){
    gl_Position = uProjMatrix0*vPosition;
    }
    gPosition = gl_Position;
    varyPostion = vPosition.xy;
    }
    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
    2、fragment shader

    #extension GL_OES_EGL_image_external : require // 外部扩展图像纹理
    precision mediump float;
    uniform samplerExternalOES texture; //外部扩展纹理采样器变量
    uniform sampler2D texture0; //贴图纹理采样器变量
    uniform int colorFlag; // 滤镜类型
    uniform float mratio; // 纹理融合因子
    const highp float mWidth=640.0;
    const highp float mHeight=480.0;
    const highp vec3 W = vec3(0.299,0.587,0.114);
    const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721); //光亮度里三个值相加要为1,各个值代表着颜色的百分比,中间是绿色的值,70%的比重会让效果更好点。
    const lowp float saturation=0.5;
    const highp float radius = 1.41;
    const highp vec2 center = vec2(0.5, 0.5);
    const highp float refractiveIndex=0.5;
    //矩形融合区域
    const vec2 leftBottom = vec2(-1.0, 0.40);
    const vec2 rightTop = vec2(-0.40, 1.0);
    //模拟坐标数组
    vec2 blurCoordinates[24];

    //从vertex shader传入的参量
    varying vec4 gPosition;
    varying vec2 v_TexCoordinate;
    varying vec2 varyPostion;

    float hardLight(float color)
    {
    if(color <= 0.5)
    color = color * color * 2.0;
    else
    color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
    return color;
    }

    void modifyColor(vec4 color){
    color.r=max(min(color.r,1.0),0.0);
    color.g=max(min(color.g,1.0),0.0);
    color.b=max(min(color.b,1.0),0.0);
    color.a=max(min(color.a,1.0),0.0);
    }

    void main(){
    if(colorFlag==0){
    //矩形区域融合
    if (varyPostion.x >= leftBottom.x && varyPostion.x <= rightTop.x
    && varyPostion.y >= leftBottom.y && varyPostion.y <= rightTop.y) {
    if(mratio < 0.0000001){ //暖色效果
    vec4 color = texture2D(texture, v_TexCoordinate);
    vec4 deltaColor = color + vec4(0.1, 0.1, 0.0, 0.0); // 暖色
    modifyColor(deltaColor);
    gl_FragColor=deltaColor;
    }else if(mratio > 0.99){ //放大镜效果
    gl_FragColor= texture2D(texture, vec2(v_TexCoordinate.x/2.0+0.25, v_TexCoordinate.y/2.0+0.25)); //nColor;
    }else{
    vec2 tex0 = vec2((varyPostion.x-leftBottom.x)/(rightTop.x-leftBottom.x),
    1.0-(varyPostion.y-leftBottom.y)/(rightTop.y-leftBottom.y));
    vec4 color = texture2D(texture0, tex0);
    gl_FragColor = color*mratio + texture2D(texture,v_TexCoordinate)*(1.0-mratio); //1.0-v_TexCoordinate
    //gl_FragColor = texture2D(texture, 1.0-v_TexCoordinate);
    }
    }else{
    //vec4 color1 = texture2D(texture, v_TexCoordinate);
    //vec4 color2 = texture2D(texture0, v_TexCoordinate);//vec2(v_TexCoordinate.s/10, v_TexCoordinate.t/10));
    // gl_FragColor = mix(color1, color2, mratio);
    gl_FragColor = texture2D(texture, v_TexCoordinate);
    }
    }
    else if(colorFlag==7){
    //光亮度里三个值相加要为1,各个值代表着颜色的百分比,中间是绿色的值,70%的比重会让效果更好点。
    vec4 textureColor = texture2D(texture, v_TexCoordinate);
    float luminance = dot(textureColor.rgb, luminanceWeighting); //GLSL中的点乘运算,线性代数的点运算符相乘两个数字。点乘计算需要将纹理颜色信息和相对应的亮度权重相乘。然后取出所有的三个值相加到一起计算得到这个像素的中和亮度值。
    vec3 greyScaleColor = vec3(luminance);
    gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w); //用mix函数把计算的灰度值,初识的纹理颜色和得到的饱和度信息结合起来。
    }
    else if(colorFlag==8){
    float aspectRatio = mWidth/mHeight;
    vec2 textureCoordinateToUse = vec2(v_TexCoordinate.x, (v_TexCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
    //归一化坐标空间需要考虑屏幕是一个单位宽和一个单位长。
    float distanceFromCenter = distance(center, textureCoordinateToUse); //center
    //计算特定像素点距离球形的中心有多远。使用GLSL内建的distance()函数,用勾股定律计算出中心坐标和长宽比矫正过的纹理坐标的距离
    float checkForPresenceWithinSphere = step(distanceFromCenter, radius); //计算片段是否在球体内。
    distanceFromCenter = distanceFromCenter / radius; //标准化到球心的距离,重新设置distanceFromCenter
    float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter); //模拟一个玻璃球,需要计算球的“深度”是多少。
    vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth)); //归一化
    vec3 refractedVector = refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);
    //GLSL的refract()函数以刚才创建的球法线和折射率来计算当光线通过球时从任意一个点看起来如何。

    gl_FragColor = texture2D(texture, (refractedVector.xy + 1.0) * 0.5) * checkForPresenceWithinSphere; //最后凑齐所有计算需要的颜色信息。
    }
    else if(colorFlag==1){ //将此灰度值作为输出颜色的RGB值,这样就会变成黑白滤镜
    vec4 color = texture2D(texture, v_TexCoordinate);
    float fGrayColor = (0.3*color.r + 0.59*color.g + 0.11*color.b); // 求灰度值
    gl_FragColor = vec4(fGrayColor, fGrayColor, fGrayColor, 1.0);
    }
    else if(colorFlag==2){ //冷暖色调
    vec4 color = texture2D(texture, v_TexCoordinate);
    vec4 deltaColor = color + vec4(0.1, 0.1, 0.0, 0.0); // 暖色
    modifyColor(deltaColor);
    gl_FragColor=deltaColor;
    }
    else if(colorFlag==3){ //增加亮度、降低亮度等
    vec4 color = texture2D(texture, v_TexCoordinate);
    vec4 deltaColor = color + vec4(0.0, 0.0, 0.1, 0.0); //vec4(0.006, 0.004, 0.002, 0.0); // blue色
    modifyColor(deltaColor);
    gl_FragColor=deltaColor;
    }
    else if(colorFlag==4){ //放大镜效果
    vec4 nColor=texture2D(texture, v_TexCoordinate);
    float uXY = mWidth/mHeight;
    vec2 vChange = vec2(0.0, 0.0);
    float dis = distance(vec2(gPosition.x, gPosition.y/uXY), vChange);
    if(dis < 0.5){ //圆形放大区域
    nColor=texture2D(texture,vec2(v_TexCoordinate.x/2.0+0.25, v_TexCoordinate.y/2.0+0.25));
    }
    gl_FragColor=nColor;
    }
    else if(colorFlag==5){ //类似高斯模糊、径向模糊
    vec4 nColor=texture2D(texture, v_TexCoordinate);
    vec3 vChangeColor = vec3(0.025, 0.025, 0.025); // 定义边距

    //取周边纹理像素值求平均
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x-vChangeColor.r,v_TexCoordinate.y-vChangeColor.r));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x-vChangeColor.r,v_TexCoordinate.y+vChangeColor.r));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x+vChangeColor.r,v_TexCoordinate.y-vChangeColor.r));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x+vChangeColor.r,v_TexCoordinate.y+vChangeColor.r));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x-vChangeColor.g,v_TexCoordinate.y-vChangeColor.g));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x-vChangeColor.g,v_TexCoordinate.y+vChangeColor.g));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x+vChangeColor.g,v_TexCoordinate.y-vChangeColor.g));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x+vChangeColor.g,v_TexCoordinate.y+vChangeColor.g));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x-vChangeColor.b,v_TexCoordinate.y-vChangeColor.b));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x-vChangeColor.b,v_TexCoordinate.y+vChangeColor.b));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x+vChangeColor.b,v_TexCoordinate.y-vChangeColor.b));
    nColor+=texture2D(texture,vec2(v_TexCoordinate.x+vChangeColor.b,v_TexCoordinate.y+vChangeColor.b));
    nColor/=13.0;
    gl_FragColor=nColor;
    }
    else if(colorFlag==6)
    {
    float mul_x = 2.0 / mWidth;
    float mul_y = 2.0 / mHeight;
    float pParams = 0.0;
    vec2 pStepOffset = vec2(mul_x, mul_y);
    vec3 centralColor = texture2D(texture, v_TexCoordinate).rgb;

    blurCoordinates[0] = v_TexCoordinate.xy + pStepOffset * vec2(0.0, -10.0);
    blurCoordinates[1] = v_TexCoordinate.xy + pStepOffset * vec2(0.0, 10.0);
    blurCoordinates[2] = v_TexCoordinate.xy + pStepOffset * vec2(-10.0, 0.0);
    blurCoordinates[3] = v_TexCoordinate.xy + pStepOffset * vec2(10.0, 0.0);
    blurCoordinates[4] = v_TexCoordinate.xy + pStepOffset * vec2(5.0, -8.0);
    blurCoordinates[5] = v_TexCoordinate.xy + pStepOffset * vec2(5.0, 8.0);
    blurCoordinates[6] = v_TexCoordinate.xy + pStepOffset * vec2(-5.0, 8.0);
    blurCoordinates[7] = v_TexCoordinate.xy + pStepOffset * vec2(-5.0, -8.0);
    blurCoordinates[8] = v_TexCoordinate.xy + pStepOffset * vec2(8.0, -5.0);
    blurCoordinates[9] = v_TexCoordinate.xy + pStepOffset * vec2(8.0, 5.0);
    blurCoordinates[10] = v_TexCoordinate.xy + pStepOffset * vec2(-8.0, 5.0);
    blurCoordinates[11] = v_TexCoordinate.xy + pStepOffset * vec2(-8.0, -5.0);
    blurCoordinates[12] = v_TexCoordinate.xy + pStepOffset * vec2(0.0, -6.0);
    blurCoordinates[13] = v_TexCoordinate.xy + pStepOffset * vec2(0.0, 6.0);
    blurCoordinates[14] = v_TexCoordinate.xy + pStepOffset * vec2(6.0, 0.0);
    blurCoordinates[15] = v_TexCoordinate.xy + pStepOffset * vec2(-6.0, 0.0);
    blurCoordinates[16] = v_TexCoordinate.xy + pStepOffset * vec2(-4.0, -4.0);
    blurCoordinates[17] = v_TexCoordinate.xy + pStepOffset * vec2(-4.0, 4.0);
    blurCoordinates[18] = v_TexCoordinate.xy + pStepOffset * vec2(4.0, -4.0);
    blurCoordinates[19] = v_TexCoordinate.xy + pStepOffset * vec2(4.0, 4.0);
    blurCoordinates[20] = v_TexCoordinate.xy + pStepOffset * vec2(-2.0, -2.0);
    blurCoordinates[21] = v_TexCoordinate.xy + pStepOffset * vec2(-2.0, 2.0);
    blurCoordinates[22] = v_TexCoordinate.xy + pStepOffset * vec2(2.0, -2.0);
    blurCoordinates[23] = v_TexCoordinate.xy + pStepOffset * vec2(2.0, 2.0);

    float sampleColor = centralColor.g * 22.0;
    sampleColor += texture2D(texture, blurCoordinates[0]).g;
    sampleColor += texture2D(texture, blurCoordinates[1]).g;
    sampleColor += texture2D(texture, blurCoordinates[2]).g;
    sampleColor += texture2D(texture, blurCoordinates[3]).g;
    sampleColor += texture2D(texture, blurCoordinates[4]).g;
    sampleColor += texture2D(texture, blurCoordinates[5]).g;
    sampleColor += texture2D(texture, blurCoordinates[6]).g;
    sampleColor += texture2D(texture, blurCoordinates[7]).g;
    sampleColor += texture2D(texture, blurCoordinates[8]).g;
    sampleColor += texture2D(texture, blurCoordinates[9]).g;
    sampleColor += texture2D(texture, blurCoordinates[10]).g;
    sampleColor += texture2D(texture, blurCoordinates[11]).g;
    sampleColor += texture2D(texture, blurCoordinates[12]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[13]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[14]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[15]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[16]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[17]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[18]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[19]).g * 2.0;
    sampleColor += texture2D(texture, blurCoordinates[20]).g * 3.0;
    sampleColor += texture2D(texture, blurCoordinates[21]).g * 3.0;
    sampleColor += texture2D(texture, blurCoordinates[22]).g * 3.0;
    sampleColor += texture2D(texture, blurCoordinates[23]).g * 3.0;

    sampleColor = sampleColor / 62.0;

    float highPass = centralColor.g - sampleColor + 0.5;

    for(int i = 0; i < 5;i++)
    {
    highPass = hardLight(highPass);
    }
    float luminance = dot(centralColor, W);

    float alpha = pow(luminance, pParams);

    vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;

    gl_FragColor = vec4(mix(smoothColor.rgb, max(smoothColor, centralColor), alpha), 1.0);
    }
    }
    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
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    3、shader工具类

    public class HelpUtils
    {
    private static final String TAG = "ShaderHelper";
    public static int compileShader(final int shaderType, final String shaderSource)
    {
    int shaderHandle = GLES20.glCreateShader(shaderType);
    if (shaderHandle != 0)
    {
    // Pass in the shader source.
    GLES20.glShaderSource(shaderHandle, shaderSource);
    // Compile the shader.
    GLES20.glCompileShader(shaderHandle);
    // Get the compilation status.
    final int[] compileStatus = new int[1];
    GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
    // If the compilation failed, delete the shader.
    if (compileStatus[0] == 0)
    {
    Log.e(TAG, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shaderHandle));
    GLES20.glDeleteShader(shaderHandle);
    shaderHandle = 0;
    }
    }
    if (shaderHandle == 0){
    throw new RuntimeException("Error creating shader.");
    }
    return shaderHandle;
    }

    public static int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes)
    {
    int programHandle = GLES20.glCreateProgram();
    if (programHandle != 0)
    {
    // Bind the vertex shader to the program.
    GLES20.glAttachShader(programHandle, vertexShaderHandle);
    // Bind the fragment shader to the program.
    GLES20.glAttachShader(programHandle, fragmentShaderHandle);
    // Bind attributes
    if (attributes != null){
    final int size = attributes.length;
    for (int i = 0; i < size; i++){
    GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
    }
    }
    // Link the two shaders together into a program.
    GLES20.glLinkProgram(programHandle);
    // Get the link status.
    final int[] linkStatus = new int[1];
    GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);

    // If the link failed, delete the program.
    if (linkStatus[0] == 0) {
    Log.e(TAG, "Error compiling program: " + GLES20.glGetProgramInfoLog(programHandle));
    GLES20.glDeleteProgram(programHandle);
    programHandle = 0;
    }
    }
    if (programHandle == 0){
    throw new RuntimeException("Error creating program.");
    }
    return programHandle;
    }

    public static int loadTexture(final Context context, final int resourceId) {
    final int[] textureHandle = new int[1];
    GLES20.glGenTextures(1, textureHandle, 0);
    if (textureHandle[0] != 0) {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false; // No pre-scaling

    // Read in the resource
    final Bitmap bitmap = BitmapFactory.decodeResource(
    context.getResources(), resourceId, options);

    // Bind to the texture in OpenGL
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
    // Set filtering
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
    GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
    GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

    // Load the bitmap into the bound texture.
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    // Recycle the bitmap, since its data has been loaded into OpenGL.
    bitmap.recycle();
    }

    if (textureHandle[0] == 0) {
    throw new RuntimeException("Error loading texture.");
    }
    return textureHandle[0];
    }

    public static String readTextFileFromRawResource(final Context context,
    final int resourceId)
    {
    final InputStream inputStream = context.getResources().openRawResource(
    resourceId);
    final InputStreamReader inputStreamReader = new InputStreamReader(
    inputStream);
    final BufferedReader bufferedReader = new BufferedReader(
    inputStreamReader);

    String nextLine;
    final StringBuilder body = new StringBuilder();

    try{
    while ((nextLine = bufferedReader.readLine()) != null){
    body.append(nextLine);
    body.append(' ');
    }
    }
    catch (IOException e){
    return null;
    }

    return body.toString();
    }

    //从sh脚本中加载shader内容的方法
    public static String loadFromAssetsFile(String fname,Resources r)
    {
    String result=null;
    try {
    InputStream in=r.getAssets().open(fname);
    int ch=0;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    while((ch=in.read())!=-1) {
    baos.write(ch);
    }
    byte[] buff=baos.toByteArray();
    baos.close();
    in.close();
    result=new String(buff,"UTF-8");
    result=result.replaceAll("\r\n"," ");
    }
    catch(Exception e){
    e.printStackTrace();
    }
    return result;
    }
    }
    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
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    4、GLViewMediaActivity类, shader操作类,实现GLSurfaceView.Renderer接口
    通过创建的SurfaceTexture videoTexture(textures[0]生成的),生成Surface,所以整个摄像头图像渲染流程:
    camera图像 -> Surface -> videoTexture/videoTexture.updateTexImage() -> GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]) ->
    GLES20.glDrawElements()

    public class GLViewMediaActivity extends Activity implements TextureView.SurfaceTextureListener, GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
    public static final String videoPath = Environment.getExternalStorageDirectory()+"/live.mp4";
    public static final String TAG = "GLViewMediaActivity";
    private static float squareCoords[] = {
    -1.0f, 1.0f, // top left
    -1.0f, -1.0f, // bottom left
    1.0f, -1.0f, // bottom right
    1.0f, 1.0f // top right
    };
    private static short drawOrder[] = {0, 1, 2, 0, 2, 3}; // Texture to be shown in backgrund
    private float textureCoords[] = {
    0.0f, 1.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 0.0f, 1.0f,
    1.0f, 1.0f, 0.0f, 1.0f
    };

    private int[] textures = new int[1];
    private int width, height;
    private int shaderProgram;
    private FloatBuffer vertexBuffer;
    private FloatBuffer textureBuffer;
    private ShortBuffer drawListBuffer;
    private float[] videoTextureTransform = new float[16];
    private SurfaceTexture videoTexture;
    private GLSurfaceView glView;

    private Context context;
    private RelativeLayout previewLayout = null;

    private boolean frameAvailable = false;
    int textureParamHandle;
    int textureCoordinateHandle;
    int positionHandle;
    int textureTranformHandle;

    public int mRatio;
    public float ratio=0.5f;
    public int mColorFlag=0;
    public int xyFlag=0;
    TextureView mPreviewView;
    CameraCaptureSession mSession;
    CaptureRequest.Builder mPreviewBuilder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_1);
    context = this;
    glView = new GLSurfaceView(this);

    previewLayout = (RelativeLayout)findViewById(R.id.previewLayout);
    //RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(640,480 );
    previewLayout.addView(glView);//, layoutParams);
    mPreviewView = (TextureView) findViewById(R.id.id_textureview);
    mPreviewView.setSurfaceTextureListener(this);

    glView.setEGLContextClientVersion(2);
    glView.setRenderer(this);
    //glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

    SeekBar seekBar = (SeekBar) findViewById(R.id.id_seekBar);
    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    // TODO Auto-generated method stub
    ratio = progress/100.0f; // 贴图纹理 & 摄像头图像外部扩展纹理的融合因子
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    // TODO Auto-generated method stub

    }
    });

    Button btn_color = (Button)findViewById(R.id.btn_color);
    Button btn_mirror = (Button)findViewById(R.id.btn_mirror);

    btn_color.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
    // 滤镜类型选择
    if(mColorFlag == 0) {
    mColorFlag = 7;
    Toast.makeText(GLViewMediaActivity.this, "Saturation adjust!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag == 7) {
    mColorFlag = 1;
    Toast.makeText(GLViewMediaActivity.this, "Gray Color!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag == 1) {
    mColorFlag = 2;
    Toast.makeText(GLViewMediaActivity.this, "Warm Color!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag == 2){
    mColorFlag = 3;
    Toast.makeText(GLViewMediaActivity.this, "Cool Color!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag == 3){
    mColorFlag = 4;
    Toast.makeText(GLViewMediaActivity.this, "Amplify!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag == 4){
    mColorFlag = 5;
    Toast.makeText(GLViewMediaActivity.this, "Vague!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag == 5){
    mColorFlag = 6;
    Toast.makeText(GLViewMediaActivity.this, "Beauty!", Toast.LENGTH_SHORT).show();
    }else if(mColorFlag ==6){
    mColorFlag = 0;
    Toast.makeText(GLViewMediaActivity.this, "Orignal Color!", Toast.LENGTH_SHORT).show();
    }
    }
    });

    btn_mirror.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
    //X 、Y轴镜像选择
    if(xyFlag == 0) {
    Toast.makeText(GLViewMediaActivity.this, "X Mirror!", Toast.LENGTH_SHORT).show();
    xyFlag = 1;
    }else if(xyFlag == 1){
    xyFlag = 2;
    Toast.makeText(GLViewMediaActivity.this, "Y Mirror!", Toast.LENGTH_SHORT).show();
    }else if(xyFlag == 2) {
    xyFlag = 0;
    Toast.makeText(GLViewMediaActivity.this, "Normal!", Toast.LENGTH_SHORT).show();
    }
    }
    });
    }

    @Override
    protected void onPause() {
    super.onPause();
    }
    @Override
    protected void onDestroy() {
    super.onDestroy();
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
    try {
    Log.i(TAG, "onSurfaceTextureAvailable: width = " + width + ", height = " + height);
    String[] CameraIdList = cameraManager.getCameraIdList();
    CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(CameraIdList[0]);
    characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
    // 6.0 动态获取权限
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    return;
    }
    //startCodec();
    cameraManager.openCamera(CameraIdList[0], mCameraDeviceStateCallback, null);
    } catch (CameraAccessException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
    return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
    CameraDevice mCameraDevice;
    private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice camera) {
    Log.i(TAG, " CameraDevice.StateCallback onOpened ");
    try {
    mCameraDevice = camera;
    startPreview(camera);
    } catch (CameraAccessException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    @Override
    public void onDisconnected(CameraDevice camera) {
    if (null != mCameraDevice) {
    mCameraDevice.close();
    GLViewMediaActivity.this.mCameraDevice = null;
    }
    }

    @Override
    public void onError(CameraDevice camera, int error) {}
    };

    private void startPreview(CameraDevice camera) throws CameraAccessException {
    SurfaceTexture texture = mPreviewView.getSurfaceTexture();
    texture.setDefaultBufferSize(mPreviewView.getWidth(), mPreviewView.getHeight());
    Surface surface = new Surface(texture); // TextureView -> SurfaceTexture -> Surface

    Surface surface0 = new Surface(videoTexture); // 通过创建的SurfaceTexture,生成Surface,videoTexture 由textures[0]生成的,所以整个摄像头图像渲染流程:camera图像 -> Surface -> videoTexture/ videoTexture.updateTexImage() -> GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);

    Log.i(TAG, " startPreview ");
    try {
    mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //CameraDevice.TEMPLATE_STILL_CAPTURE
    } catch (CameraAccessException e) {
    e.printStackTrace();
    }
    //添加预览输出的Surface: camera图像 -> Surface
    mPreviewBuilder.addTarget(surface);
    mPreviewBuilder.addTarget(surface0);
    camera.createCaptureSession(Arrays.asList(surface, surface0), mSessionStateCallback, null);
    }

    //1、CameraCaptureSession.StateCallback
    private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(CameraCaptureSession session) {
    try {
    Log.i(TAG, " onConfigured ");
    //session.capture(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
    mSession = session;
    //自动聚焦
    mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
    //自动曝光
    mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
    //int rotation = getWindowManager().getDefaultDisplay().getRotation();
    //mPreviewBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
    session.setRepeatingRequest(mPreviewBuilder.build(), null, null); //null
    } catch (CameraAccessException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onConfigureFailed(CameraCaptureSession session) {}
    };

    int callback_time;
    //2、 CameraCaptureSession.CaptureCallback()
    private CameraCaptureSession.CaptureCallback mSessionCaptureCallback =new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
    //Toast.makeText(GLViewMediaActivity.this, "picture success!", Toast.LENGTH_SHORT).show();
    callback_time++;
    Log.i(TAG, " CaptureCallback = "+callback_time);
    }

    @Override
    public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {
    Toast.makeText(GLViewMediaActivity.this, "picture failed!", Toast.LENGTH_SHORT).show();
    }
    };

    public int initTexture(int drawableId)
    {
    //生成纹理ID
    int[] textures = new int[1];
    GLES20.glGenTextures
    (
    1, //产生的纹理id的数量
    textures, //纹理id的数组
    0 //偏移量
    );
    int textureId = textures[0];
    Log.i(TAG, " initTexture textureId = " + textureId);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);

    //加载图片
    InputStream is = this.getResources().openRawResource(drawableId);
    Bitmap bitmapTmp;
    try {
    bitmapTmp = BitmapFactory.decodeStream(is);
    } finally {
    try {
    is.close();
    }
    catch(IOException e) {
    e.printStackTrace();
    }
    }
    //加载纹理
    GLUtils.texImage2D
    (
    GLES20.GL_TEXTURE_2D, //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D
    0, //纹理的层次,0表示基本图像层,直接贴图,多重纹理mipmap,可选其它level层
    bitmapTmp, //纹理图像
    0 //纹理边框尺寸
    );
    bitmapTmp.recycle(); //纹理加载成功后释放图片
    return textureId;
    }

    int textureIdOne;
    int textureHandle;

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    setupGraphics();
    setupVertexBuffer();
    setupTexture();
    textureIdOne= initTexture(R.drawable.bg); // 生成贴图纹理
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
    this.width = width;
    this.height = height;
    GLES20.glViewport(0, 0, width, height);
    setSize(width, height); //根据高、宽设置模型/视图/投影矩阵
    }

    @Override
    public void onDrawFrame(GL10 gl) {
    synchronized (this) {
    if (frameAvailable) {
    videoTexture.updateTexImage(); // 更新SurfaceTexture纹理图像信息,然后绑定的GLES11Ext.GL_TEXTURE_EXTERNAL_OES纹理才能渲染
    videoTexture.getTransformMatrix(videoTextureTransform); // 获取SurfaceTexture纹理变换矩
    frameAvailable = false;
    }
    }
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //设置清除颜色
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    //GL_COLOR_BUFFER_BIT 设置窗口颜色
    //GL_DEPTH_BUFFER_BIT 设置深度缓存--把所有像素的深度值设置为最大值(一般为远裁剪面)
    drawTexture();
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
    synchronized (this) {
    frameAvailable = true;
    }
    }

    private float[] mViewMatrix=new float[16];
    private float[] mProjectMatrix=new float[16];
    private float[] mModelMatrix=new float[16];
    private float[] mModelMatrix0=new float[16];
    private float[] matrix=new float[16];
    private float[] matrix0=new float[16];
    private int gHWidth;
    private int gHHeight;

    public void setSize(int width,int height){
    float ratio=(float)width/height;
    //投影矩 -- 视窗显示
    Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 1, 3);
    //视图矩 -- 相机位置/相机目标位置/相机各朝向
    Matrix.setLookAtM(mViewMatrix, 0,
    0.0f, 0.0f, 1.0f, //0f, 0.0f, 0.0f,
    0.0f, 0.0f, 0.0f, //0.0f, 0.0f,-1.0f,
    0f, 1.0f, 0.0f);
    //模型矩 -- 物体本身的位置、朝向
    Matrix.setIdentityM(mModelMatrix,0);
    Matrix.setIdentityM(mModelMatrix0,0);
    //Matrix.scaleM(mModelMatrix,0,2,2,2);

    Matrix.multiplyMM(matrix,0,mProjectMatrix,0,mViewMatrix,0); //矩阵乘法
    Matrix.multiplyMM(matrix0,0,mProjectMatrix,0,mViewMatrix,0);

    matrix = flip(mModelMatrix, true, false);
    matrix0 = flip(mModelMatrix0, false, true);
    }

    public static float[] rotate(float[] m,float angle){
    Matrix.rotateM(m,0,angle,0,0,1);
    return m;
    }

    //镜像
    public float[] flip(float[] m,boolean x,boolean y){
    if(x||y){
    Matrix.scaleM(m,0,x?-1:1,y?-1:1,1);
    }
    return m;
    }

    private void setupGraphics() {
    final String vertexShader = HelpUtils.readTextFileFromRawResource(context, R.raw.vetext_sharder);
    final String fragmentShader = HelpUtils.readTextFileFromRawResource(context, R.raw.fragment_sharder);

    final int vertexShaderHandle = HelpUtils.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
    final int fragmentShaderHandle = HelpUtils.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
    shaderProgram = HelpUtils.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
    new String[]{"texture", "vPosition", "vTexCoordinate", "textureTransform"});

    GLES20.glUseProgram(shaderProgram);
    textureParamHandle = GLES20.glGetUniformLocation(shaderProgram, "texture"); // 摄像头图像外部扩展纹理
    textureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "vTexCoordinate"); // 顶点纹理坐标
    positionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition"); // 顶点坐标
    textureTranformHandle = GLES20.glGetUniformLocation(shaderProgram, "textureTransform");

    textureHandle = GLES20.glGetUniformLocation(shaderProgram, "texture0"); // 获得贴图对应的纹理采样器句柄(索引)
    mRatio = GLES20.glGetUniformLocation(shaderProgram, "mratio"); // 融合因子
    gHWidth=GLES20.glGetUniformLocation(shaderProgram,"mWidth"); // 视窗宽、高
    gHHeight=GLES20.glGetUniformLocation(shaderProgram,"mHeight");

    GLES20.glUniform1i(gHWidth,width);
    GLES20.glUniform1i(gHHeight,height);
    }

    private void setupVertexBuffer() {
    // Draw list buffer
    ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
    dlb.order(ByteOrder.nativeOrder()); // 转换成本地字节序
    drawListBuffer = dlb.asShortBuffer();
    drawListBuffer.put(drawOrder);
    drawListBuffer.position(0);

    // Initialize the texture holder
    //顶点位置
    ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
    bb.order(ByteOrder.nativeOrder()); // 转换成本地字节序
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(squareCoords);
    vertexBuffer.position(0);

    //纹理坐标
    ByteBuffer texturebb = ByteBuffer.allocateDirect(textureCoords.length * 4);
    texturebb.order(ByteOrder.nativeOrder()); // 转换成本地字节序
    textureBuffer = texturebb.asFloatBuffer();
    textureBuffer.put(textureCoords);
    textureBuffer.position(0);
    }

    private void setupTexture() {
    // Generate the actual texture
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0); // 激活(使能)相应的纹理单元
    GLES20.glGenTextures(1, textures, 0); // 产生纹理id
    checkGlError("Texture generate");

    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
    //通过纹理id,绑定到相应的纹理单元,纹理单元内存放的类型可以很多种,比如GLES20.GL_TEXTURE_1D、GLES20.GL_TEXTURE_2D、GLES20.GL_TEXTURE_3D、GLES11Ext.GL_TEXTURE_EXTERNAL_OES等
    checkGlError("Texture bind");

    videoTexture = new SurfaceTexture(textures[0]); // 通过创建的纹理id,生成SurfaceTexture
    videoTexture.setOnFrameAvailableListener(this);
    }

    private void drawTexture() {
    int mHProjMatrix=GLES20.glGetUniformLocation(shaderProgram,"uProjMatrix");
    GLES20.glUniformMatrix4fv(mHProjMatrix,1,false,matrix,0);

    int mHProjMatrix0=GLES20.glGetUniformLocation(shaderProgram,"uProjMatrix0");
    GLES20.glUniformMatrix4fv(mHProjMatrix0,1,false,matrix0,0);

    int mXyFlag = GLES20.glGetUniformLocation(shaderProgram, "xyFlag"); //镜像类型: x镜像,y镜像---通过不同的变化矩阵与顶点位置向量进行左乘,如:uProjMatrix*vPosition;
    GLES20.glUniform1i(mXyFlag, xyFlag);

    int mColorFlagHandle = GLES20.glGetUniformLocation(shaderProgram, "colorFlag"); // 纹理操作类型(滤镜处理):饱和度/灰度/冷暖色/放大镜/模糊/美颜/纹理融合
    GLES20.glUniform1i(mColorFlagHandle, mColorFlag);

    //顶点属性一般包括位置、颜色、法线、纹理坐标属性
    GLES20.glEnableVertexAttribArray(positionHandle); // 使能相应的顶点位置属性的顶点属性数组
    GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); // 指定(绑定)该相应的顶点位置属性的顶点属性数组

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]); // 摄像头图像纹理
    GLES20.glUniform1i(textureParamHandle, 0);

    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIdOne); // 贴图的图像纹理
    GLES20.glUniform1i(textureHandle, 1);

    GLES20.glEnableVertexAttribArray(textureCoordinateHandle);
    GLES20.glVertexAttribPointer(textureCoordinateHandle, 4, GLES20.GL_FLOAT, false, 0, textureBuffer);

    GLES20.glUniformMatrix4fv(textureTranformHandle, 1, false, videoTextureTransform, 0); // GL_TEXTURE_EXTERNAL_OES纹理的变化矩
    GLES20.glUniform1f(mRatio, ratio); // 纹理融合因子

    GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); // 根据顶点位置索引进行绘制片元
    GLES20.glDisableVertexAttribArray(positionHandle);
    GLES20.glDisableVertexAttribArray(textureCoordinateHandle);
    }

    public void checkGlError(String op) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
    Log.e("SurfaceTest", op + ": glError " + GLUtils.getEGLErrorString(error));
    }
    }

    }
    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
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    demo效果:
    纹理融合

    放大镜;

    模糊:

    暖色:

    冷色:

    美颜:

    镜像:

    ---------------------
    作者:keen_zuxwang
    来源:CSDN
    原文:https://blog.csdn.net/keen_zuxwang/article/details/78363464
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    halcon 如何把一个region截取出来保存为图像
    Halcon学习(三)赋值与数组操作
    sort_region——对区域进行排序
    Halcon函数【转】
    Halcon算子之shape_trans,用于变换区域的形状
    Halcon学习之八:图像区域叠加与绘制
    Halcon学习之七:改变图像的现实方式和大小
    Halcon学习之六:获取Image图像中Region区域的特征参数
    Halcon学习之五:有关图像的定义域的函数
    Docker Swarm redis 集群搭建
  • 原文地址:https://www.cnblogs.com/jukan/p/9909789.html
Copyright © 2011-2022 走看看