OpenGL ES:相机预览添加滤镜效果

经过前面图片添加滤镜效果的实践,相机预览无非也就是将每一帧的bitmap放到OpenGL中去渲染。

所以很容易想到如下方案:

  • 方案A 使用TextureView用于相机预览,TextureView表面再盖上一层GLSurfaceView用与OpenGL ES的渲染输出,从TextureView中获取每一帧的Bitmap交给OpenGL ES渲染到GLSurfaceView上。

很容易看出,方案A的性能并不好,甚至可以说很差,不免反思我们是不是可以去掉一层,因此有了方案B。

  • 方案B 从OpenGL ES中生成一个纹理对象,以纹理ID new一个SurfaceTexture回调给外部的相机作为预览的输出,作为OpenGL ES的纹理输入渲染到GLSurfaceView上。

其中方案A使用的Camera2 API,而方案B使用的Camera1 API,整体看来Camera1使用很方便,而Camera2使用起来稍许复杂,但是相对于来说Camera2的实现更规范化。

方案A

public class Camera2Activity extends AppCompatActivity  {

    private String TAG = "Camera2Activity";
    private Button btShow;
    private Button btFilter;
    private Button btStart;

    private TextureView textureView;

    private CameraDevice cameraDevice;
    private CameraManager cameraManager;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest previewRequest;

    private Surface preview;

    private final int REQUEST_CAMERA_CODE=1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera2);
        initView();
    }

    private GLSurfaceView glSurfaceView;
    private FilterRenderer renderer;
    private BaseFilter filter;

    private int surWidth;
    private int surHeight;

    public void initView() {
        textureView = findViewById(R.id.texture_view);
        btFilter = findViewById(R.id.bt_filter);
        btStart = findViewById(R.id.bt_start);

        btFilter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showFilters();
            }
        });

        btShow = findViewById(R.id.bt_show);
        btShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (glSurfaceView.getVisibility()!=View.VISIBLE) {
                    glSurfaceView.setVisibility(View.VISIBLE);
                }else {
                    glSurfaceView.setVisibility(View.INVISIBLE);
                }
            }
        });

        btStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
        glSurfaceView = findViewById(R.id.gl_surface);
        glSurfaceView.setEGLContextClientVersion(3);
        filter = new GrayFilter();
        renderer = new FilterRenderer(filter);
        glSurfaceView.setRenderer(renderer);
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        //相机预览回调
        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                surWidth = width;
                surHeight = height;
                initCamera();
            }

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

            }

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

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {
                //回调给OpenGL es渲染
                filter.apply(textureView.getBitmap());
                glSurfaceView.requestRender();
             }
        });
    }


    private void showFilters() {
        String[] items = new String[]{
                "原图",
                "黑白",
                "4格",
                "放大",
                "重影"
        };
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setTitle("选择滤镜")
                .setItems(items, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        switch (which) {
                            case 0:
                                applyFilter(new BaseFilter());
                                break;
                            case 1:
                                applyFilter(new GrayFilter());
                                break;
                            case 2:
                                applyFilter(new FourViewFilter());
                                break;
                            case 3:
                                applyFilter(new EnlargeFilter());
                                break;
                            case 4:
                                applyFilter(new GhostingFilter());
                                break;
                        }
                        dialog.dismiss();
                    }
                });
        builder.create().show();
    }

    private void applyFilter(BaseFilter filter){
        this.filter = filter;
        renderer.setFilter(filter);
        glSurfaceView.requestRender();
    }

    public void initCamera() {
        cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_CODE);
        }else {
            openCamera();
        }
    }


    //打开相机
    @SuppressLint("MissingPermission")
    private void openCamera(){
        try {
            //获取后置相机id
            String cameraId = getCameraId(CameraCharacteristics.LENS_FACING_BACK,surWidth,surHeight);
            if (cameraId == null) {
                return;
            }
            cameraManager.openCamera(cameraId,cameraCallback,null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_CAMERA_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            openCamera();
        }
    }

    //创建请求发送管道
    private void createCaptureSession(){
        List<Surface> surfaces = new ArrayList<>();
        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
        //根据预览尺寸设置默认的缓冲区大小
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
        preview = new Surface(surfaceTexture);
        surfaces.add(preview);
        try {
            //建造者模式构建预览请求
            final CaptureRequest.Builder previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            previewRequestBuilder.addTarget(preview);
            //surfaces集合作为捕获的图像数据的输出的目标
            cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    //captureSession作为应用层和硬件层之间的管道 用于传输请求
                    cameraCaptureSession = session;
                    try
                    {
                        // 设置自动对焦模式
                        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                        // 设置自动曝光模式
                        previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                                CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                        // 开始显示相机预览
                        previewRequest = previewRequestBuilder.build();
                        // 设置预览时连续捕获图像数据
                        cameraCaptureSession.setRepeatingRequest(previewRequest,
                                captureCallback, null);
                    }
                    catch (CameraAccessException e)
                    {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.e(TAG," onConfigureFailed 开启预览失败");
                }
            }, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
            Log.e(TAG,"开启预览失败:"+ e.toString());
        }
    }

    private Size mPreviewSize;
    private Size mCaptureSize;


    //获取相应相机的id
    private String getCameraId(Integer key,int width,int height){
        String[] cameraIds;
        try {
            cameraIds = cameraManager.getCameraIdList();
            for (String cameraId : cameraIds) {
                CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
                //获取StreamConfigurationMap,它是管理摄像头支持的所有输出格式和尺寸
                StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                assert map != null;
                //根据TextureView的尺寸设置预览尺寸
                mPreviewSize = CameraUtils.getOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);
                //获取相机支持的最大拍照尺寸
                mCaptureSize = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new Comparator<Size>() {
                    @Override
                    public int compare(Size lhs, Size rhs) {
                        return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getHeight() * rhs.getWidth());
                    }
                });

                Integer facing=cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing!=null&& facing.equals(key)) {
                    return cameraId;
                }
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return null;
    }


    //相机捕获回调
    private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
        }
    };

    //打开Camera 状态回调
    private CameraDevice.StateCallback cameraCallback=new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            Log.d(TAG, "onOpened");
            cameraDevice = camera;
            createCaptureSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            Log.d(TAG, "onDisconnected");
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            Log.d(TAG, "onError:"+error);
        }
    };
}

方案B:(待续)

全部评论

相关推荐

大族激光智能控制科技 算法工程师 12K+加班费2.5K,十五薪,一年调一次薪,区间0.1-0.3,写专利,论文一份一万,会系统化培养应届生
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务