OpenGLES:glReadPixels()获取相机GLSurfaceView预览数据并保存

这篇具有很好参考价值的文章主要介绍了OpenGLES:glReadPixels()获取相机GLSurfaceView预览数据并保存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android现行的Camera API2机制可以通过onImageAvailable(ImageReader reader)回调从底层获取到Jpeg、YuvRaw三种格式的Image,然后通过保存Image实现拍照功能,但是却并没有Api能直接在上层直接拿到预览Surface上的实显数据。

Android Camera预览的实现是上层下发SurfaceCameraHAL,由CameraHAL也就是android.hardware.camera.provider@2.4-service进程往Surface对应的Buffer中填充预览数据,然后再copySurfaceFling中由OpenGL进行渲染显示。

glsurfaceview获取相机预览,Camera,OpenGL/OpenGLES,图像处理,图形渲染,android,计算机视觉,算法

实际相机开发中,不仅仅只是要实现预览,还经常需要拿到预览数据做一些特效处理,那么问题来了,怎么在相机App获取到预览Surface实显数据呢?

这跟上层Camera App用于显示SurfaceView控件有关:

  • 如果上层使用的是GLSurfaceView,可以直接通过OpenGLESglReadPixels()获取到copy到显存中的预览数据
  • 如果上层使用的不是GLSurfaceView,可以通过自己搭建EGL环境,然后在EGL环境中调用OpenGLESglReadPixels()获取到预览数据。

GLSurfaceView其实就是Android封装好的EGL+SufaceView控件,Android的所有渲染最终都是通过OpenGL来实现的,所以万变不离其宗,本质上上层Camera App都只能通过OpenGLESglReadPixels()实现预览数据的获取。

glsurfaceview获取相机预览,Camera,OpenGL/OpenGLES,图像处理,图形渲染,android,计算机视觉,算法

glsurfaceview获取相机预览,Camera,OpenGL/OpenGLES,图像处理,图形渲染,android,计算机视觉,算法

一个SurfaceAndroid EGL中对应一个FrameBuffer,学习过OpenGL的应该都知道,一个FrameBuffer会有多个附着(attachment),其中必须且只能有一个ColorBuffer附着,有一个或多个StencilBufferDepthBuffer附着

glsurfaceview获取相机预览,Camera,OpenGL/OpenGLES,图像处理,图形渲染,android,计算机视觉,算法

glReadPixels()仅限于读取ColorBuffer,无法读取DepthBufferStencilBuffer,它可以将图像内容从显存读取到内存中,将ColorBuffer中的像素值保存到预分配的内存缓冲区。

前面关于OpenGLES的博文中,有两篇是使用OpenGLES实现相机的相关功能,一篇是《OpenGLES:GLSurfaceView实现Android Camera预览》,一篇是《OpenGLES:相机实时滤镜四宫格、九宫格》,今天就在这两篇博文基础上实现相机预览数据的获取和保存。

相机实现部分在此不做过多讲解,有兴趣的可以参看前面两篇博文,有详细的讲解
本文主要展示glReadPixels()对相机预览数据获取的实现

代码实现其实很简单
GLSurfaceView.Renderer实现类的onDrawFrame(GL10 gl)函数中新增如下代码段:

if (shouldTakePic) {
    //预览尺寸
	int w = 1080;int h = 1440;
    //预览数据保存成照片的目录
	String savePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/MyCamera/";

	int[] iat = new int[w * h];
	IntBuffer ib = IntBuffer.allocate(w * h);
    //(0,580)距离屏幕左下角的距离,与glViewport(0, 580,...)保持一致
	glReadPixels(0, 580, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ib);

	int[] ia = ib.array();
	//glReadPixels 读取的内容是上下翻转的,要处理一下
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < w; j++) {
			iat[(h - i - 1) * w + j] = ia[i * w + j];
		}
	}

	Bitmap inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
	inBitmap.copyPixelsFromBuffer(IntBuffer.wrap(iat));

	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	inBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bos);
	byte[] bitmapData = bos.toByteArray();

	File tempDir = new File(savePath);
	tempDir.mkdirs();
	String fileName = "temp_" + System.currentTimeMillis() + ".jpeg";
	File imgFile = new File(savePath, fileName);

	try {
		FileOutputStream output = new FileOutputStream(imgFile);
		output.write(bitmapData);
		output.flush();
		output.close();
		Log.v(TAG, "ImageReader X");
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		inBitmap.recycle();
	}
}

glReadPixels读取的内容上下翻转处理还有另外一种实现,
原理都是一样的,实现起来大同小异

if (shouldTakePic) {
	//预览尺寸
	int w = 1080;
	int h = 1440;
	//预览数据保存成照片的目录
	String savePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/MyCamera/";
	
	int b[] = new int[(int) (w * h)];
	int bt[] = new int[(int) (w * h)];
	IntBuffer buffer = IntBuffer.wrap(b);
	buffer.position(0);
    //(0,580)距离屏幕左下角的距离,与glViewport(0, 580,...)保持一致
	glReadPixels(0, 580, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < w; j++) {
			int pix = b[i * w + j];
			int pb = (pix >> 16) & 0xff;
			int pr = (pix << 16) & 0x00ff0000;
			int pix1 = (pix & 0xff00ff00) | pr | pb;
			bt[(h - i - 1) * w + j] = pix1;
		}
	}
	Bitmap inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
	inBitmap.copyPixelsFromBuffer(buffer);
	inBitmap = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);

	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	inBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bos);
	byte[] bitmapData = bos.toByteArray();
	ByteArrayInputStream fis = new ByteArrayInputStream(bitmapData);

	String tempPicFile = "temp_" + System.currentTimeMillis() + ".jpeg";
	File tempDir = new File(savePath);
	tempDir.mkdirs();
	try {
		File tmpFile = new File(tempDir, tempPicFile);
		FileOutputStream fos = new FileOutputStream(tmpFile);
		byte[] buf = new byte[1024];
		int len;
		while ((len = fis.read(buf)) > 0) {
			fos.write(buf, 0, len);
		}
		fis.close();
		fos.close();
		inBitmap.recycle();
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

验证下效果,抓两张预览照试试:

抓一张普通预览:

glsurfaceview获取相机预览,Camera,OpenGL/OpenGLES,图像处理,图形渲染,android,计算机视觉,算法

抓一张四宫格滤镜预览:

glsurfaceview获取相机预览,Camera,OpenGL/OpenGLES,图像处理,图形渲染,android,计算机视觉,算法文章来源地址https://www.toymoban.com/news/detail-777516.html

到了这里,关于OpenGLES:glReadPixels()获取相机GLSurfaceView预览数据并保存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenGL-入门-BMP像素图glReadPixels(1)实现读取屏幕中间的颜色和获取屏幕上鼠标点击位置的颜色

    glReadPixels函数用于从帧缓冲区中读取像素数据。它可以用来获取屏幕上特定位置的像素颜色值或者获取一块区域内的像素数据。下面是该函数的基本语法: x 和 y:读取区域左下角的像素坐标。 width 和 height:读取区域的宽度和高度。 format:像素数据的格式,可以是 GL_RGBA、

    2024年02月10日
    浏览(48)
  • Baumer工业相机堡盟工业相机如何通过BGAPISDK获取相机接口数据吞吐量(C++)

    ​ Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度

    2024年02月14日
    浏览(52)
  • Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取相机当前数据吞吐量(C#)

    ​ Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度

    2024年02月14日
    浏览(58)
  • Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取相机当前数据吞吐量(C#)

    ​ Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度

    2024年02月03日
    浏览(48)
  • Android 实现相机(CameraX)预览

    CameraX 是一个 Jetpack 库,旨在帮助您更轻松地开发相机应用。 对于新应用,我们建议从 CameraX 开始。它提供一致且易于使用的 API,适用于绝大多数 Android 设备,并向后兼容 Android 5.0(API 级别 21)。 CameraX 支持大多数常见的相机用例: 预览 :在屏幕上查看图片。 图片分析 :

    2024年02月15日
    浏览(41)
  • 基于视觉重定位的室内AR导航APP的大创项目思路(3)手机相机内参数据获取和相机标定

    前情提要: 是第一次做项目的小白,文章内的资料介绍如有错误,请多包含! 相机内参是本身的物理数据,包括焦距f和缩放c,一般以矩阵K的形式存放和使用 1.相机的内参数据在建图的时候就需要使用,SLAM中需要根据相机内参数据结合传入的图像数据等进行建图,不然无法

    2024年02月09日
    浏览(50)
  • 一行代码解决Android相机预览镜像的问题

    开发Camare相关应用的时候, 预览图像是发现,使用前置摄像头的时候,预览出来的图像是左右相反, 并没有像照镜子一样的镜像效果. 为了解决这一问题,可是一番煞费苦心啊! 最终黄天不负有心人, 找到了解决方案. 废话不多说,直接上代码: 重点重点重点!!! parameters.set(“preview-fli

    2024年02月13日
    浏览(43)
  • Android OpenGL 渲染相机预览画面显示体系

    OpenGL能进行高效得渲染图形图像,并支持各种复杂的特效和动画。 而在 Android 当中,运用的是 OpenGL ES ,它是OpenGL的一个 轻量级版本 ,专门用于在移动设备、游戏控制台、嵌入式系统等嵌入式环境中使用。 它可以做相机滤镜或者图片滤镜的效果,以相机滤镜为例: 首先 C

    2023年04月24日
    浏览(44)
  • Android 使用Camera1实现相机预览、拍照、录像

    本文介绍如何从零开始,在 Android 中实现 Camera1 的接入,并在文末提供 Camera1Manager 工具类,可以用于快速接入 Camera1 。 Android Camera1 API 虽然已经被 Google 废弃,但有些场景下不得不使用。 并且 Camera1 返回的帧数据是 NV21 ,不像 Camera2 、 CameraX 那样,需要自己再转一层,才能得

    2024年02月08日
    浏览(45)
  • 十分钟实现 Android Camera2 相机预览

    因为工作中要使用 Android Camera2 API ,但因为 Camera2 比较复杂,网上资料也比较乱,有一定入门门槛,所以花了几天时间系统研究了下,并在 CSDN 上记录了下,希望能帮助到更多的小伙伴。 Camera2 API 的包名是 android.hardware.camera2 ,是 Android 5.0 后推出的一套调用摄像头设备的接口

    2024年02月13日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包