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:(待续)

全部评论

相关推荐

02-14 12:40
门头沟学院 Java
程序员花海:1.面试要求必须Java笔试不一定 2.难度对等秋招 远超于日常实习是因为同一批次且转正很多 竞争压力大 3.第一个加点指标,上线了就把接口性能加上去 使用本地缓存这个不算亮点 只是技术选型,要把为什么采用这个和背后的思考写出来而不是单纯堆叠技术没意义 4.八股要一直看 很容易忘记 5.拼团交易这个老问题 堆积技术 另外建议你把奖项合并到教育背景 没必要拆出来放最后
我的简历长这样
点赞 评论 收藏
分享
2025-12-25 10:16
已编辑
合肥工业大学 后端工程师
如题,在历经了长达多月的焦急等待,楼主也算是如愿以偿收到了梦中情司的意向了,秋招也终于是落下了帷幕,虽然手中的offer不够打牌,但已经满足了。华为时间线:9.3&nbsp;笔试环节,惊险通过10.15&nbsp;线下面试,前两轮技术面手撕都比较轻松,面试官态度也很好,最后一轮主管面,向主管表达了强烈的意愿,主管很和蔼,面试体验非常棒,1125定律后入池成功11.19&nbsp;收到接口人的保温电话12.9&nbsp;接到部门hr的保温电话,介绍了一下部门负责的工作12.23&nbsp;收到华为的意向书,成为华孝子一枚~期间收到了之前实习过的公司的offer,害怕华子泡不出来就先签三方了,这下不得不毁约了,在此向前司道个歉,也感谢前司对我的认可和托举,祝业务蒸蒸日上~感谢从今年三月开始找暑期实习以来,所有朋友和家人的鼓励,我们宿舍的就业氛围相当好,大家会分享各种有用的信息以及面试中遇到刁钻的面试题,在有人收到offer的时候我们都会发自内心的高兴和祝福,在我去线下面的时候也借我穿过西服.....能在大学四年分入这么好的宿舍拥有这么这么好的舍友除了幸运我找不出其他的形容词。还要感谢我的父母,在我每一次面试前都给予鼓励,也在失败的时候安慰我,他们的托底是我前进的基石,以后有工资了要给父母买很多东西最感谢的是我的女朋友,我们从大一相识,一直坚持到大四,她是一个非常优秀也异常坚定的女生,也正是因为她的实力出众早再年初就定好了要去上海的一家外企。我为了也去上海,从暑期实习开始投了不少上海的岗位但无一例外的都被拒之门外,但这期间她从来没有嫌弃过我,反而一直鼓励我相信我,如果说父母的托底是我前进的基石,那女朋友的鼓励和信任则是我前进的动力和方向。在如今这个充满戾气和对立的社会,能找到一个一心一意彼此喜欢的人实在是很难得,我深知这种珍贵所以更会加倍珍惜也感谢自己吧,在经历了无数个失眠的夜晚和面试失败的打击下,最终还是迎来了最好的结果,记得在华为线下面的前几周我几乎回到了高三时期的作息,那真是一段充实美好的时光,好在最后的结果也没有辜负这份努力也想跟所有的牛友说:不要因为一时的失败而自怨自艾,妄自菲薄,只要坚持下去,总会有柳暗花明又一村的惊喜在等待着你,机会总是垂青于有准备的人,要相信否极泰来,相信自己。朋友,坚定地相信未来吧,相信不屈不挠的努力,相信战胜死亡的年轻,相信未来、热爱生命。
小肥罗:有这样的女朋友真是幸福
秋招白月光
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务