HarmonyOS鸿蒙Next中如何调用系统相机并获取原始图像数据
HarmonyOS鸿蒙Next中如何调用系统相机并获取原始图像数据
需要做医学图像分析,要求无损原始数据。但 @ohos:camera 拍照返回的是 JPEG URI。有没有办法拿到 YUV 或 RAW 数据流?
鸿蒙提供 Camera 高级 API 支持原始数据捕获:
- 使用
cameraManager.createCaptureSession()创建会话; - 配置
PhotoCaptureSettings的outputFormat为YUV_420_888或RAW_SENSOR; - 通过
on('photoTaken')回调获取PixelMap对象,可直接访问 buffer;
更多关于HarmonyOS鸿蒙Next中如何调用系统相机并获取原始图像数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
你看看这个会不会对你有帮助:Interface (Image)
- Image类,供ImageReceiver和ImageCreator使用,用于传输图片对象,它的实际内容由生产者决定。如相机预览流提供的Image对象存储了YUV数据,相机拍照提供的Image对象存储了JPEG文件。
在HarmonyOS Next中,调用系统相机并获取原始图像数据需要使用@ohos.multimedia.camera和@ohos.multimedia.image模块。通过getCameraManager获取相机管理器,创建相机输入流和输出流。设置输出流为imageReceiver类型以获取图像。在imageReceiver的on('imageArrival')回调中,使用readNextImage()获取Image对象。调用Image.getComponent()获取图像组件,通过ImageComponent.byteArray访问原始图像数据数组。
在HarmonyOS Next中,要获取相机的原始图像数据(如YUV或RAW),确实不能直接依赖返回JPEG URI的默认拍照接口。你需要使用@ohos.multimedia.camera API进行更底层的相机操作。核心思路是:通过相机输出流(CameraOutput)来直接获取未经压缩的图像数据。
以下是关键步骤和代码要点:
- 创建并配置相机输入流(CameraInput):获取相机设备列表,并选择后置摄像头作为输入。
- 创建并配置预览输出流(PreviewOutput):用于取景预览。
- 创建并配置照片输出流(PhotoOutput):这是获取原始数据的关键。你需要为其设置
photoProfile,指定所需的图像格式。- 对于YUV数据:使用
camera.createPhotoOutput(profile),其中profile可以通过CameraManager.getSupportedPhotoOutputCapability()获取,并选择PhotoFormat.PHOTO_FORMAT_YCBCR_420_SP(即NV21格式)等支持的YUV格式。 - 对于RAW数据:同样,你需要查询相机设备是否支持
PhotoFormat.PHOTO_FORMAT_RAW。如果支持,则创建对应的profile。
- 对于YUV数据:使用
- 捕获图像并监听回调:调用
photoOutput.capture()方法,并通过监听onPhotoOutputAvailable回调来获取图像数据。- 在回调中,你会得到一个
Photo对象。通过photo.main可以获取到image对象。 - 对于YUV格式,
image对象包含pixelMap,你可以通过pixelMap.getImageInfo()和pixelMap.readPixelsToBuffer()方法读取到YUV数据缓冲区(ArrayBuffer)。 - 对于RAW格式,流程类似,
image对象中会包含RAW格式的图像数据。
- 在回调中,你会得到一个
示例代码片段(获取YUV数据流):
import camera from '@ohos.multimedia.camera';
import image from '@ohos.multimedia.image';
import { BusinessError } from '@ohos.base';
// 1. 获取CameraManager实例
let cameraManager = camera.getCameraManager(context);
// 2. 获取相机设备并创建输入流
let cameras: camera.CameraDevice[] = cameraManager.getSupportedCameras();
let cameraInput: camera.CameraInput | undefined = undefined;
// ... 选择后置摄像头逻辑
cameraInput = cameraManager.createCameraInput(cameras[0]);
// 3. 创建预览输出流(略)
// let previewOutput = ...
// 4. 创建照片输出流(配置为YUV格式)
let photoProfiles: camera.Profile[] = cameraManager.getSupportedPhotoOutputCapability(cameras[0]).photoProfiles;
let yuvProfile: camera.Profile | undefined = photoProfiles.find((profile: camera.Profile) => {
return profile.photoFormat === camera.PhotoFormat.PHOTO_FORMAT_YCBCR_420_SP;
});
if (!yuvProfile) {
// 设备不支持YUV输出
return;
}
let photoOutput: camera.PhotoOutput = cameraManager.createPhotoOutput(yuvProfile);
// 5. 创建会话并添加输入输出流
let session: camera.PhotoSession = cameraManager.createSession(camera.SessionType.NORMAL) as camera.PhotoSession;
session.beginConfig();
session.addInput(cameraInput);
session.addOutput(previewOutput);
session.addOutput(photoOutput);
await session.commitConfig();
await session.start();
// 6. 捕获照片并监听数据回调
photoOutput.on('photoOutputAvailable', (err: BusinessError, photo: camera.Photo) => {
if (err || !photo) {
console.error(`photoOutputAvailable error: ${JSON.stringify(err)}`);
return;
}
let imageObj: image.Image = photo.main;
let pixelMap: image.PixelMap | undefined = imageObj.pixelMap;
if (pixelMap) {
let imageInfo: image.ImageInfo = pixelMap.getImageInfo();
let buffer: ArrayBuffer = new ArrayBuffer(imageInfo.size.width * imageInfo.size.height * 1.5); // NV21大小估算
pixelMap.readPixelsToBuffer(buffer).then(() => {
// 此时buffer中即为YUV (NV21) 原始数据,可用于后续医学分析
console.info('YUV data buffer obtained');
}).catch((error: BusinessError) => {
console.error(`readPixelsToBuffer error: ${JSON.stringify(error)}`);
});
}
});
// 触发拍照
photoOutput.capture();
注意事项:
- 权限:需要在
module.json5中声明ohos.permission.CAMERA权限,并动态申请。 - 格式支持:务必在代码中检查设备对
PHOTO_FORMAT_YCBCR_420_SP或PHOTO_FORMAT_RAW的支持性。 - 性能与内存:原始数据(尤其是RAW)体积巨大,处理时需注意内存管理和性能优化,避免阻塞主线程。
- 文档参考:详细API请查阅官方开发文档的
相机管理章节。
通过上述方式,你可以绕过JPEG压缩,直接获取到相机传感器产生的原始图像数据流,满足医学图像分析对无损数据的要求。

