我有一个ImageReader用于获取预览帧的数据(字节数组).它配置了推荐的图像格式,YUV_420_888如下所示:
mPreviewImageReader = ImageReader.newInstance(width,
height, ImageFormat.YUV_420_888, 2);
Run Code Online (Sandbox Code Playgroud)
当我mPreviewImageReader.setOnImageAvailableListener();调用的监听器被调用时,我检索一个图像:
Image image = reader.acquireLatestImage();
Run Code Online (Sandbox Code Playgroud)
在某些手机中,我在日志中看到以下带有ImageReader_JNI标签的打印输出:
ImageReader_imageSetup:覆盖缓冲区格式YUV_420_888到32315659.
我搜索了,似乎格式被覆盖了YV12.我试着查看ImageReader的c ++代码并发现了这种情况:
int bufFmt = buffer->format;
if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
bufFmt = buffer->flexFormat;
}
if (imgReaderFmt != bufFmt) {
if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
// Special casing for when producer switches to a format compatible with flexible YUV
// (HAL_PIXEL_FORMAT_YCbCr_420_888).
ctx->setBufferFormat(bufFmt);
ALOGD("%s: Overriding buffer format YUV_420_888 to …Run Code Online (Sandbox Code Playgroud) 我正在使用OnImageAvailableListener获取预览帧:
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
byte[] data = new byte[buffer.capacity()];
buffer.get(data);
//data.length=332803; width=3264; height=2448
Log.e(TAG, "data.length=" + data.length + "; width=" + image.getWidth() + "; height=" + image.getHeight());
//TODO data processing
} catch (Exception e) {
e.printStackTrace();
}
if (image != null) {
image.close();
}
}
Run Code Online (Sandbox Code Playgroud)
每次数据长度不同但图像宽度和高度相同.
主要问题:data.length对于3264x2448这样的分辨率来说太小了.
数据阵列的大小应为3264*2448 = 7,990,272,而不是300,000 - 600,000.
怎么了?
imageReader = ImageReader.newInstance(3264, …Run Code Online (Sandbox Code Playgroud) 是否可以仅使用带有Google Vision API的Camera2检测脸部?我找不到整合它的方法.
我使用新的camera2 api体验了低FPS率.具体来说,尽管选择了最高的FPS范围(30,30)
characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
Run Code Online (Sandbox Code Playgroud)
并设置它
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestFPSRange);
Run Code Online (Sandbox Code Playgroud)
在我测试过的两款设备(三星S5和Xperia Z3 Compact)上,我获得了高图像分辨率的平均速率.以下是我设置的方法OnImageAvailableListener:
int format = ImageFormat.YUV_420_888;
Size largest = map.getOutputSizes(format)[0];
Log.d("Images", "sizes: " + Arrays.toString(map.getOutputSizes(format)));
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), format,
/* maxImages */50);
mImageReader.setOnImageAvailableListener(new OnImageAvailableListener() {
private int frames = 0;
private long initialTime = SystemClock.elapsedRealtimeNanos();
@Override
public void onImageAvailable(ImageReader reader) {
reader.acquireLatestImage().close();
frames++;
if ((frames % 30) == 0) {
long currentTime = SystemClock.elapsedRealtimeNanos();
long fps = Math.round(frames * 1e9 / (currentTime - initialTime));
Log.d("Image", "frame# : " + frames …Run Code Online (Sandbox Code Playgroud) 我正在开发一个手电筒应用程序,可以打开/关闭系统功能。
我遇到了在Android M(v6.0)上显示的崩溃
速溶药
这是问题详细信息和堆栈跟踪:
Fatal Exception: java.lang.IllegalArgumentException: Receiver not registered: android.hardware.camera2.CameraManager$1@49e5f1b
at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:789)
at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1222)
at android.hardware.camera2.CameraManager$3.run(CameraManager.java:1266)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5728)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Run Code Online (Sandbox Code Playgroud)
我具有以下Manifest权限和硬件功能:
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.flash" />
Run Code Online (Sandbox Code Playgroud)
和
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
Run Code Online (Sandbox Code Playgroud)
****编辑:****
这是我用来访问摄像机的代码:
// Here, I am checking if SDK >= M
if (VersionUtils.isMarshmallowOrGreater()) {
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
if (cameraManager != null) {
try {
cameraId = cameraManager.getCameraIdList()[0];
} catch (CameraAccessException | …Run Code Online (Sandbox Code Playgroud) android illegalargumentexception receiver android-broadcastreceiver android-camera2
我在SO和一些不错的博客文章上挖了很多但似乎我有独特的要求分别阅读视频和音频缓冲区,以便在录制时继续进行处理.
我的用例就像当用户启动视频录制时,我需要使用连续处理视频帧ML-Face-Detection-Kit并连续处理音频帧以确保用户说出某些内容并检测噪声级别.为此,我想我需要一个单独的缓冲区中的视频和音频,并在处理后,我将合并它并保存到MP4文件中作为录制.
我尝试过由伟大的家伙Mattia Iavarone开发的CameraView,但它只提供视频帧.
我愿意接受其他有用的建议/反馈来处理这种情况.
android video-processing audio-processing android-camera2 firebase-mlkit
我正在使用camera2 API通过手动曝光和ISO捕获图像。但是有时拍摄的图像的ISO和曝光值不同于我指定的值。
有什么方法可以将在捕获请求中设置的值的信息传递给图像读取器侦听器,在捕获图像时回调会出现,以查看图像是否实际上具有我指定的值。
我正在捕获许多具有不同ISO值和每张图像曝光值的图像(比如说一个循环)。
这是我捕获图像的代码:
imageReader = ImageReader.newInstance(imageWidth, imageHeight, ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
/// How to check the image is taken with correct values
}
}, backgroundHandler);
captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequest.addTarget(preview);
captureRequest.addTarget(imageReader.getSurface());
captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
captureRequest.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
captureRequest.set(CaptureRequest.SENSOR_SENSITIVITY, <MANUAL_ISO>);
captureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, <MANUAL_EXPOSURE>);
mSession.capture(captureRequest.build(), null, backgroundHandler);
Run Code Online (Sandbox Code Playgroud)
这在大多数情况下都有效,例如,如果我要拍摄100张照片,则使用我指定的值拍摄大约70张照片,其余30张将具有不同的值。
我试过的
我尝试了以下方法,当我捕获图像时,我检查onCaptureCompleted中的值并创建一个队列,该队列指示图像是否使用正确的值拍摄。但是当我在imageReader中获取图像时,我不知道队列中的值是用于当前图像还是其他图像。发生这种情况是因为我不知道什么时候会为图像调用imageReader侦听器:它可以在onCaptureCompleted完成之后或在它之前调用,或者在最坏的情况下,对于2-3张图像,我会被2-3次调用onCaptureCompleted两次循环捕获图像。
基本上,我需要一个标签来标识这种方法中的图像,但是我不知道该怎么做。
这是相同的代码:
class CapturedPicture {
static Queue<Boolean> iso = new LinkedList<>();
}
mSession.capture(captureRequest.build(), new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull …Run Code Online (Sandbox Code Playgroud) 用例:是我必须在没有任何活动或片段的服务中在后台运行相机
拦截器:新的camerax 会话绑定到生命周期所有者,但该服务没有任何。那么如何获取此对象或在没有它的情况下运行?
已经尝试过:我可以用 Camera2 库做同样的事情,但我想知道是否可以用 Camerax 也因为 Camera2 api 将来可能会被弃用。或者谷歌故意阻止用户在没有活动的情况下运行相机?
请建议
首先问一个问题:在ImageReader知道我总是将捕获转换为 的情况下,初始化和使用camera2 api 的最有效方法是什么Bitmap?
我正在尝试 Android Camera2 示例,一切都运行得很好。然而,出于我的目的,我总是需要对捕获的静态图像执行一些后期处理,为此我需要一个Bitmap对象。目前我正在使用来自(我正在解释)的BitmapFactory.decodeByteArray(...)字节。ImageReader.acquireNextImage().getPlanes()[0].getBuffer()虽然这可以接受,但我仍然觉得应该有一种方法可以提高性能。捕获的内容被编码ImageFormat.Jpeg,需要再次解码才能得到Bitmap,这似乎是多余的。理想情况下,我会获取它们PixelFormat.RGB_888并使用将其复制到位图Bitmap.copyPixelsFromBuffer(...),但使用该格式初始化似乎并不ImageReader具有可靠的设备支持。YUV_420_888可能是另一种选择,但环顾四周,似乎需要跳过一些环节才能解码为Bitmap. 有推荐的方法吗?
我正在使用 GLSurfaceView 创建自定义相机预览,使用 OpenGl 渲染相机提供给我的帧。我已经完全实现了相机,并按照我期望的方式工作,没有 fps 损失和正确的纵横比等。但是当我需要捕获来自相机源的帧时,问题出现了,我的第一个想法是使用 glReadPixles ()
使用 GLES20.glReadPixels() 我发现某些设备会出现 fps 损失,主要是屏幕分辨率较高的设备,这是有道理的,因为 glReadPixels 需要以更高分辨率读取更多像素。
我做了一些挖掘,发现其他人对 glReadPixels 也有类似的问题,许多人建议使用 PBO,最好使用其中两个作为双缓冲区,这将允许我读取像素数据,而不会阻塞/停止当前的渲染过程。我完全理解双缓冲的概念,我对 OpenGL 相当陌生,需要一些关于如何让双缓冲 PBO 工作的指导。
我找到了一些 PBO 双缓冲的解决方案,但我永远找不到完整的解决方案来完全理解它如何与 GLES 交互。
我的 GLSurfaceView.Renderer.onDrawFrame() 实现
// mBuffer and mBitmap are declared and allocated outside of the onDrawFrame Method
// Buffer is used to store pixel data from glReadPixels
mBuffer.rewind();
GLES20.glUseProgram(hProgram);
if (tex_matrix != null)
{
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, tex_matrix, 0);
}
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mMvpMatrix, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex_id);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, GLConstants.VERTEX_NUM);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); …Run Code Online (Sandbox Code Playgroud)