Swift 3:如何访问48字节CFData中的matrix_float3x3值?
提取相机内参矩阵数值的两种方法
嘿,这个问题我之前做AR项目的时候刚好碰到过!既然你已经拿到了对应matrix_float3x3的CFData,而且知道它是列主序存储的,那有两种简单的方式来提取里面的数值:
方法一:直接绑定到matrix_float3x3结构体
这是最简洁的方式,利用Swift的内存绑定直接把数据映射成系统定义的矩阵结构体:
if let camData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil) as? CFData { // 将CFData转为Swift的Data类型,方便内存操作 let data = Data(camData) // 绑定内存到matrix_float3x3结构体 data.withUnsafeBytes { buffer in guard let baseAddr = buffer.baseAddress else { return } let intrinsicMatrix = baseAddr.assumingMemoryBound(to: matrix_float3x3.self).pointee // 注意:matrix_float3x3是列主序存储,columns数组的每个元素代表一列 let fx = intrinsicMatrix.columns.0.x // 焦距x(第一列第一行) let fy = intrinsicMatrix.columns.1.y // 焦距y(第二列第二行) let cx = intrinsicMatrix.columns.2.x // 光心x(第三列第一行) let cy = intrinsicMatrix.columns.2.y // 光心y(第三列第二行) print("相机内参:fx=\(fx), fy=\(fy), cx=\(cx), cy=\(cy)") } }
matrix_float3x3的columns属性是三个SIMD3<Float>实例,每个实例对应矩阵的一列。比如columns.0是第一列,它的x、y、z分别对应矩阵第1、2、3行的元素。
方法二:手动解析字节提取Float数组
如果你更习惯直接操作原始数据,可以把CFData里的字节拷贝到Float数组中,再按列主序的规则提取元素:
if let camData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil) as? CFData { let data = Data(camData) // 初始化一个能容纳9个Float的数组(3x3矩阵共9个元素) var floatArray = [Float](repeating: 0.0, count: 9) // 把Data中的字节拷贝到Float数组 data.copyBytes(to: &floatArray, count: MemoryLayout<Float>.stride * 9) // 列主序的数组顺序是:[m11, m21, m31, m12, m22, m32, m13, m23, m33] // 对应行主序矩阵: // [m11, m12, m13] // [m21, m22, m23] // [m31, m32, m33] let fx = floatArray[0] // m11 let fy = floatArray[4] // m22 let cx = floatArray[6] // m13 let cy = floatArray[7] // m23 // 也可以转成行主序的二维数组方便查看 let rowMajorMatrix = [ [floatArray[0], floatArray[3], floatArray[6]], [floatArray[1], floatArray[4], floatArray[7]], [floatArray[2], floatArray[5], floatArray[8]] ] print("行主序矩阵:\(rowMajorMatrix)") }
重要提醒
一定要记住这个矩阵是列主序存储的,和我们日常写矩阵的行主序习惯不一样。如果需要转换成行主序(比如传给Core ML模型或者其他用行主序的库),要注意元素的顺序转换。
内容的提问来源于stack exchange,提问作者leiatlarge
相关产品推荐
相关产品推荐

