Hi I successfully saved the depth map to 32-bit binary file. Then I can read the file and convert it to png using python opencv.
| func convertDepthData(depthMap: CVPixelBuffer) -> [[Float32]] { |
| let width = CVPixelBufferGetWidth(depthMap) |
| let height = CVPixelBufferGetHeight(depthMap) |
| var convertedDepthMap: [[Float32]] = Array( |
| repeating: Array(repeating: 0, count: width), |
| count: height |
| ) |
| CVPixelBufferLockBaseAddress(depthMap, CVPixelBufferLockFlags(rawValue: 2)) |
| let floatBuffer = unsafeBitCast( |
| CVPixelBufferGetBaseAddress(depthMap), |
| to: UnsafeMutablePointer<Float32>.self |
| ) |
| for row in 0 ..< height { |
| for col in 0 ..< width { |
| convertedDepthMap[row][col] = floatBuffer[width * row + col] |
| } |
| } |
| CVPixelBufferUnlockBaseAddress(depthMap, CVPixelBufferLockFlags(rawValue: 2)) |
| return convertedDepthMap |
| } |
Then save it to app container.
| func saveFloat32ArrayToDocumentsDirectory(array: [[Float32]], fileName: String, folderName: String) -> URL? { |
| let fileManager = FileManager.default |
| let datasetDirectory = getDatasetDirectory() |
| let depthDirectory = datasetDirectory.appendingPathComponent(folderName) |
| if !FileManager.default.fileExists(atPath: depthDirectory.path) { |
| do { |
| try FileManager.default.createDirectory(at: depthDirectory, withIntermediateDirectories: true, attributes: nil) |
| } catch { |
| print("Error creating depth directory: \(error.localizedDescription)") |
| return nil |
| } |
| } |
| let fileURL = depthDirectory.appendingPathComponent(fileName) |
| |
| |
| |
| let rowCount = array.count |
| let colCount = array[0].count |
| var flatArray = array.flatMap { $0 } |
| |
| do { |
| let data = Data(bytes: &flatArray, count: MemoryLayout<Float32>.size * rowCount * colCount) |
| try data.write(to: fileURL, options: .atomic) |
| return fileURL |
| } catch { |
| print("Error saving float32 array: \(error)") |
| return nil |
| } |
| } |
You can call these two function in this way, please note that the frame is ARFrame.
| guard let depthMap = frame.sceneDepth?.depthMap |
| let convertedDepthMap = convertDepthData(depthMap: depthMap) |
| |
| let fileName = String(format: "%06d.bin", frameNumber) |
| if let savedFileURL = saveFloat32ArrayToDocumentsDirectory(array: convertedDepthMap, fileName: fileName, folderName: "depth") { |
| print("Array saved to: \(savedFileURL)") |
| } else { |
| print("Error saving float32 array to the app container.") |
| } |
In openCV, you can get the depth array or convert to png. The depth image is 256*192. Because the original value is in float and we can only save int in png, I times 1000. Meanwhile, I save a .bin file to a 16-bit grayscale png.
| import numpy as np |
| import cv2 |
| import glob |
| import os |
| from PIL import Image |
| |
| |
| row_count = 192 |
| col_count = 256 |
| |
| |
| folder_path = "./depth/" |
| output_path = "./depthImg2/" |
| |
| |
| for bin_file_path in glob.glob(os.path.join(folder_path, "*.bin")): |
| |
| with open(bin_file_path, "rb") as f: |
| float32_array = np.fromfile(f, dtype=np.float32).reshape(row_count, col_count) |
| print(float32_array) |
| |
| float32_array *= 1000 |
| |
| |
| max_depth = np.max(float32_array) |
| min_depth = np.min(float32_array) |
| print(f"Max depth: {max_depth}, Min depth: {min_depth}") |
| |
| uint16_array = float32_array.astype(np.uint16) |
| |
| |
| filename = os.path.splitext(os.path.basename(bin_file_path))[0] |
| |
| |
| depth_image_path = os.path.join(output_path, filename + ".png") |
| cv2.imwrite(depth_image_path, uint16_array) |