使用 GLSurfaceView Android 进行旋转和捏合缩放的图像效果

Posted

技术标签:

【中文标题】使用 GLSurfaceView Android 进行旋转和捏合缩放的图像效果【英文标题】:Image effects with rotation and pinch to zoom using GLSurfaceView Android 【发布时间】:2014-11-03 23:15:24 【问题描述】:

我正在开发一个应用程序来应用效果/旋转/捏合来放大图像的功能。我已经从https://github.com/Grishu/ImageEffects下载了演示应用程序。

效果很好,现在我的问题/问题如下:

    对具有进度变化值的图像应用多种效果(例如,首先应用亮度效果,然后应用另一个效果,例如“对比度”。)

    - 问题: 在代码效果中始终适用于原始图像。因此,更改代码以对最终图像应用效果,例如,

    if(isApplyEffectOnOriginalImage)//call first time only         
        mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]);
    else
        mEffect.apply(mTextures[1], mImageWidth, mImageHeight, mTextures[1]);
    
    

    现在,如果第一次对进度更改应用亮度效果,它可以正常工作。但是,如果我应用相同或其他(对比)效果,现在我认为进度更改效果适用于 mTextures[1] 和 mTextures[1] 中的结果集,因此可以创建临时 mTextures[2] 来存储 mTextures[ 1] 最初,当用户更改进度值时,对 mTextures[2] 应用效果并在 mTextures[1] 上设置结果,就像在 if 条件下发生的那样。

    如何应用捏合缩放图像

    旋转问题:我只是通过设置值(90,180,270 等)将图像顺时针旋转 90 度,但问题是当图像从 90 旋转到 180 时,图像渲染不正确。 见

A) 0 角度图像

B) 90 角图像

C) 180 度角图像

【问题讨论】:

【参考方案1】:

我已经修改了 Grishu 的演示项目:here's a Screen Recording,然后是一些解释:

(图像旋转,应用了三种效果 - 水平翻转、交叉处理、鱼眼)

1) 要将效果应用于结果,您的建议效果很好。我真的不明白你的意思是什么,进度变化效果''。是否要调整效果的参数?

2) 要拥有手势,您应该扩展GLSurfaceView 并根据您的需要实现GestureDetector.OnGestureListener 和/或ScaleGestureDetector.OnScaleGestureListener。请在此处查看 TouchGLView:Source,或下面的 sn-p:

private class TouchGLView extends GLSurfaceView
        implements GestureDetector.OnGestureListener,
        ScaleGestureDetector.OnScaleGestureListener 
    private TextureRenderer mRenderer;
    private GestureDetector mTapDetector;
    private ScaleGestureDetector mScaleDetector;
    private float mLastSpan = 0;

    TouchGLView(Context c) 
        super(c);
        // Use android's built-in gesture detectors to detect
        // which touch event the user is doing.
        mTapDetector = new GestureDetector(c, this);
        mTapDetector.setIsLongpressEnabled(false);
        mScaleDetector = new ScaleGestureDetector(c, this);

        // Create an OpenGL ES 2.0 context.
        setEGLContextClientVersion(2);
        mRenderer = new TextureRenderer(c);
        setRenderer(mRenderer);
    
    @Override
    public boolean onTouchEvent(final MotionEvent e) 
        // Forward touch events to the gesture detectors.
        mScaleDetector.onTouchEvent(e);
        mTapDetector.onTouchEvent(e);
        return true;
    
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2,
                            final float dx, final float dy) 
        // Forward the drag event to the renderer.
        queueEvent(new Runnable() 
            public void run() 
                mRenderer.drag(dx, dy);
            );
        return true;
    
    @Override
    public boolean onScale(ScaleGestureDetector detector) 
        // Forward the scale event to the renderer.
        final float amount = detector.getCurrentSpan() - mLastSpan;
        queueEvent(new Runnable() 
            public void run() 
                mRenderer.zoom(amount);
            );
        mLastSpan = detector.getCurrentSpan();
        return true;
    
    ...

3) 您可以通过修改顶点坐标并考虑视口来旋转图像。 此外,您可以应用 不同 旋转。您可以旋转(和缩放)视图(顶点坐标)本身(不会影响原始纹理缓冲区),也可以旋转纹理缓冲区中的像素(90°、180° 很容易)等),然后更新您的顶点坐标以匹配新的图像宽度/高度。

这是一个使用顶点坐标进行操作的示例:

private void computeOutputVertices() 
    if (mPosVertices != null) 
        float imgAspectRatio = mTexWidth / (float)mTexHeight;
        float viewAspectRatio = mViewWidth / (float)mViewHeight;
        float x0, y0, x1, y1;
        // Set initial vertex coords based in texture aspect
        if (imgAspectRatio > 1.0f) 
            x0 = -1.0f ;
            y0 = -1.0f / imgAspectRatio;
            x1 = 1.0f ;
            y1 = 1.0f / imgAspectRatio;
         else 
            x0 = -1.0f *imgAspectRatio;
            y0 = -1.0f;
            x1 = 1.0f *imgAspectRatio;
            y1 = 1.0f;
        
        float[] coords = new float[]  x0, y0, x1, y0, x0, y1, x1, y1 ;
        // Scale coordinates with mZoom
        for (int i = 0; i < 8; i++) 
            coords[i] *= mZoom;
        
        // Rotate coordinates with mRot
        float cosa = (float)Math.cos(mRot);
        float sina = (float)Math.sin(mRot);
        float x,y;
        for (int i = 0; i < 8; i+=2) 
            x = coords[i]; y = coords[i+1];
            coords[i]   = cosa*x-sina*y;
            coords[i+1] = sina*x+cosa*y;
        
        // Finally scale again to match screen aspect
        if (viewAspectRatio > 1.0f) 
            for (int i = 0; i < 8; i+=2) 
                coords[i] = coords[i]/viewAspectRatio;
            
         else 
            for (int i = 1; i < 8; i+=2) 
                coords[i] = coords[i]*viewAspectRatio;
            
        
        mPosVertices.put(coords).position(0);
    

我建议您深入研究 OpenGL 矩阵并使用它们进行所有这些转换。

我已修改TextureRenderer 类以实现GLSurfaceView.Renderer,并将renderMode 更改为RENDERMODE_CONTINUOUSLY

最后是source for the modified demo is here。

【讨论】:

首先感谢您的回复 1)是否可以对seekbar的进度更改应用效果?因为当我将效果从“mTextures [0]”应用到“mTextures [1]”和rander textureId“mTextures [1]”时,它第一次工作文件。第一次应用效果后,如果应用第二个效果,在搜索栏的进度更改上说“对比度”,然后效果从“mTextures [1]”应用到“mTextures [1]”并渲染textureId“mTextures [1]”。你会注意到图像会变黑。 我想如果我重用“mTextures[1]”作为新鲜纹理。将解决我的问题,但不知道如何重新使用它。 2)捏缩放:效果很好,但滚动图像的问题。任何想法? 3)旋转:效果很好。是否可以在 (90,180,270,...) 顺时针使用内置旋转效果来应用旋转。 Guys 旋转和缩放效果很好,但拖动不起作用...如何解决。

以上是关于使用 GLSurfaceView Android 进行旋转和捏合缩放的图像效果的主要内容,如果未能解决你的问题,请参考以下文章

android-glsurfaceview Activity框架程序

转玩转Android Camera开发:国内首发---使用GLSurfaceView预览Camera 基础拍照demo

在 android 中使用 opengl 在 glsurfaceview 中显示 3D 模型的问题

玩转Android Camera开发:国内首发---使用GLSurfaceView预览Camera 基础拍照demo

使用 OpenGL 2.0 API 在 GLSurfaceView 上将 Android 相机预览旋转 90 度

我的OpenGL学习进阶之旅关于OpenGL ES 绘制中使用到的 Android中GLSurfaceView的两种渲染模式