HarmonyOS 鸿蒙Next 相机拍照获取YUV数据

发布于 1周前 作者 ionicwang 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 相机拍照获取YUV数据

const Camera_Profile *profile = cameraOutputCapability_->photoProfiles[i];获取到的配置文件只有jpeg。是否有什么其他方法可以获取到相机拍照后的yuv数据?

6 回复

获取预览数据参考相机双路预览官方文档,官方示例代码中的bytebuffer就是Yuv数据

参考:双路预览(ArkTS)-相机最佳实践(ArkTS)-Camera Kit(相机服务)-媒体 - 华为HarmonyOS开发者

参考以下代码:

import { camera } from '[@kit](/user/kit).CameraKit';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
import { image } from '[@kit](/user/kit).ImageKit';
import { photoAccessHelper } from '[@kit](/user/kit).MediaLibraryKit';
import { abilityAccessCtrl, PermissionRequestResult, Permissions } from '[@kit](/user/kit).AbilityKit';
import { promptAction, router } from '[@kit](/user/kit).ArkUI';
import { fileIo } from '[@kit](/user/kit).CoreFileKit';
const TAG = '[CameraDemo]';

struct CameraDemo {
 context: Context = getContext(this) as Context;
 [@State](/user/State) pixelMap: image.PixelMap | undefined = undefined;
 [@State](/user/State) finalPixelMap: image.PixelMap | undefined = undefined;
 [@State](/user/State) buffer: ArrayBuffer | undefined = undefined;
 [@State](/user/State) surfaceId: string = '';
 [@State](/user/State) hasPicture: boolean = false;
 [@State](/user/State) fileNames: string[] = [];
 [@State](/user/State) imageSize: image.Size = { width: 1920, height: 1080 };
 [@State](/user/State) saveButtonOptions: SaveButtonOptions = {
   icon: SaveIconStyle.FULL_FILLED,
   text: SaveDescription.SAVE_IMAGE,
   buttonType: ButtonType.Capsule
 }
 //设置安全控件按钮属性
 private mXComponentController: XComponentController = new XComponentController;
 private cameraManager: camera.CameraManager | undefined = undefined;
 private cameraSession: camera.PhotoSession | undefined = undefined;
 private photoOutput: camera.PhotoOutput | undefined = undefined;
 private cameraInput: camera.CameraInput | undefined = undefined;
 private previewOutput: camera.PreviewOutput | undefined = undefined;
 private imageReceiver: image.ImageReceiver | undefined = undefined;

aboutToAppear(): void {
   let permissions: Array<Permissions> = [
     'ohos.permission.CAMERA',
     'ohos.permission.WRITE_MEDIA',
     'ohos.permission.READ_MEDIA',
     'ohos.permission.MEDIA_LOCATION',
   ];
   let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
   //requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
   atManager.requestPermissionsFromUser(this.context, permissions).then((data: PermissionRequestResult) => {
     let grantStatus: Array<number> = data.authResults;
     let length: number = grantStatus.length;
     for (let i = 0; i < length; i++) {
       if (grantStatus[i] != 0) {
         //用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
         return;
       }
     }
     console.info(`${TAG} Success to request permissions from user. authResults is ${grantStatus}.`);
   }).catch((err: BusinessError) => {
     console.error(`${TAG} Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
   })
 }

createCameraManager() {
   //创建CameraManager对象
   let cameraManager: camera.CameraManager = camera.getCameraManager(this.context);
   if (!cameraManager) {
     console.error('CameraDemo camera.getCameraManager error');
     return;
   }
   this.cameraManager = cameraManager
   //监听相机状态变化
   this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
     console.info(`CameraDemo camera: ${cameraStatusInfo.camera.cameraId}, status: ${cameraStatusInfo.status}`);
   });
 }

build() {
   Column() {
     Column({ space: 20 }) {
       if (this.hasPicture) {
         Image(this.finalPixelMap)
           .objectFit(ImageFit.Fill)
           .width('100%')
           .height(300)
         //创建安全控件按钮
         SaveButton(this.saveButtonOptions)
           .onClick(async (event, result: SaveButtonOnClickResult) => {
             if (result == SaveButtonOnClickResult.SUCCESS) {
               if (this.finalPixelMap) {
                 try {
                   //1、使用安全控件创建文件
                   let phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
                   let options: photoAccessHelper.CreateOptions = {
                     title: Date.now().toString()
                   };
                   //createAsset的调用需要ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO的权限
                   let photoUri: string = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png', options);
                   console.info('CameraDemo createAsset successfully, photoUri: ' + photoUri);
                   let file: fileIo.File = fileIo.openSync(photoUri, fileIo.OpenMode.WRITE_ONLY);
                   fileIo.writeSync(file.fd, this.buffer);
                   fileIo.closeSync(file);
                   promptAction.showToast({message:`保存成功`})
                 } catch (error) {
                   let err = error as BusinessError;
                   console.error(`CameraDemo savePicture error: ${JSON.stringify(err)}`);
                   promptAction.showToast({ message:`保存失败` })
                 }
               }
             } else {
               console.error('CameraDemo SaveButtonOnClickResult createAsset failed.');
               promptAction.showToast({ message:`保存失败` })
             }
             setTimeout(() => {
               this.hasPicture = false;
               this.finalPixelMap = undefined;
             }, 1000)
           })
       } else {
         XComponent({
           id: '',
           type: 'surface',
           libraryname: '',
           controller: this.mXComponentController
         })
           .onLoad(() => {
             //设置Surface宽高(1920*1080),预览尺寸设置参考前面 previewProfilesArray 获取的当前设备所支持的预览分辨率大小去设置
             //预览流与录像输出流的分辨率的宽高比要保持一致
             this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 1920, surfaceHeight: 1080 });
             //获取Surface ID
             this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
             setTimeout(async () => {
               await this.prepareCamera();
             }, 500);
           })
           .width('100%')
           .height(600)
         Button('拍照')
           .width(200)
           .height(30)
           .onClick(async () => {
             let photoCaptureSetting: camera.PhotoCaptureSetting = {
               quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
               rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0
             }
             // 1、通过拍照流实现:点击拍照
             await this.photoOutput?.capture(photoCaptureSetting).catch((error: BusinessError) => {
               console.error(`CameraDemo Failed to capture the photo ${error.message}`); //不符合条件则进入
             })
             this.hasPicture = true;
           })
       }
     }
     .width('100%')
     .height('100%')
     .padding(15)
     .borderRadius(8)
   }
   .width('100%')
   .height('100%')
   .backgroundColor('#FFFFFF')
 }

async prepareCamera() {
   this.createCameraManager();
   if (!this.cameraManager) {
     console.error('CameraDemo cameraManager is undefined.')
     return;
   }
   //获取支持指定的相机设备对象
   let cameraDevices: Array<camera.CameraDevice> = [];
   try {
     cameraDevices = this.cameraManager.getSupportedCameras();
   } catch (error) {
     let err = error as BusinessError;
     console.error(`CameraDemo The getSupportedCameras call failed. error: ${JSON.stringify(err)}`)
   }
   cameraDevices.forEach((cameraDevice: camera.CameraDevice) => {
     console.info(`CameraDemo cameraId: ${cameraDevice.cameraId}, cameraPosition: ${cameraDevice.cameraPosition.toString()}, cameraType: ${cameraDevice.cameraType.toString()}, connectionType: ${

更多关于HarmonyOS 鸿蒙Next 相机拍照获取YUV数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


预览我能拿到,但是拍照不行吧

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

试一下呢~

我试过啊,不是一开始就写了么,创建PhotoOutput 的时候传入获取到的系统的拍照photoProfiles里面就没有yuv。但是这个东西华为肯定是支持的,就是没开放给三方或者有一些其他骚操作、

在HarmonyOS鸿蒙Next系统中,相机拍照并获取YUV数据的过程主要涉及到相机API的使用和图像处理。以下是一个简要的步骤概述:

  1. 权限申请:首先,确保你的应用已申请并获得了相机和存储权限。

  2. 相机初始化:使用CameraKit进行相机的初始化,包括设置预览和拍照的回调。

  3. 设置预览回调:通过CameraCaptureCallback设置预览回调,虽然这一步不是直接获取YUV数据,但它是相机功能的基础。

  4. 配置拍照参数:在拍照前,通过CameraCaptureConfig配置拍照参数,包括图像格式。为了获取YUV数据,需要指定图像格式为ImageFormat.YUV_420_888

  5. 拍照并获取数据:调用capturePhoto方法进行拍照,并在回调中处理数据。在回调的onCaptureCompleted方法中,你可以获取到拍照的CaptureResult,其中包含图像的ByteBuffer数据。

  6. 处理YUV数据:从ByteBuffer中提取YUV数据,进行后续处理或保存。

注意,处理YUV数据需要一定的图像处理知识,因为它包含亮度(Y)和色度(U/V)分量,需要正确解析和处理。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部