├── notebooks
├── .gitignore
├── requirements.txt
└── ReadDepth.ipynb
├── README_resources
└── depth.gif
├── DepthApp
├── DepthApp
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── DepthApp.xcdatamodeld
│ │ ├── .xccurrentversion
│ │ └── DepthApp.xcdatamodel
│ │ │ └── contents
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── AppDelegate.swift
│ ├── ViewController.swift
│ └── DepthCapture.swift
├── DepthApp.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
└── .gitignore
└── README.md
/notebooks/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints
2 | depth_video.mp4
--------------------------------------------------------------------------------
/notebooks/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | jupyter
3 | matplotlib
4 | opencv-python
5 |
--------------------------------------------------------------------------------
/README_resources/depth.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mantoone/DepthCapture/HEAD/README_resources/depth.gif
--------------------------------------------------------------------------------
/DepthApp/DepthApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DepthApp/DepthApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/DepthApp.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | DepthApp.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/DepthApp.xcdatamodeld/DepthApp.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DepthCapture
2 |
3 | [](https://developer.apple.com/iphone/index.action)
5 | [](https://developer.apple.com/swift)
7 |
8 | iOS Application for capturing depth data and RGB video to files.
9 | TrueDepth camera only (for now).
10 |
11 | ## Example
12 | 
13 |
14 | ## Credits
15 | DepthCapture.swift written by Eyal Fink (https://stackoverflow.com/a/50265132)
16 |
--------------------------------------------------------------------------------
/DepthApp/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 | To Capture Video Dawg
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/DepthApp/DepthApp/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
34 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // DepthApp
4 | //
5 | // Created by Juha Eskonen on 13/03/2019.
6 | // Copyright © 2019 Juha Eskonen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreData
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 |
18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
19 | // Override point for customization after application launch.
20 | return true
21 | }
22 |
23 | func applicationWillResignActive(_ application: UIApplication) {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
26 | }
27 |
28 | func applicationDidEnterBackground(_ application: UIApplication) {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | func applicationWillEnterForeground(_ application: UIApplication) {
34 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | func applicationDidBecomeActive(_ application: UIApplication) {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | func applicationWillTerminate(_ application: UIApplication) {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | // Saves changes in the application's managed object context before the application terminates.
44 | self.saveContext()
45 | }
46 |
47 | // MARK: - Core Data stack
48 |
49 | lazy var persistentContainer: NSPersistentContainer = {
50 | /*
51 | The persistent container for the application. This implementation
52 | creates and returns a container, having loaded the store for the
53 | application to it. This property is optional since there are legitimate
54 | error conditions that could cause the creation of the store to fail.
55 | */
56 | let container = NSPersistentContainer(name: "DepthApp")
57 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in
58 | if let error = error as NSError? {
59 | // Replace this implementation with code to handle the error appropriately.
60 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
61 |
62 | /*
63 | Typical reasons for an error here include:
64 | * The parent directory does not exist, cannot be created, or disallows writing.
65 | * The persistent store is not accessible, due to permissions or data protection when the device is locked.
66 | * The device is out of space.
67 | * The store could not be migrated to the current model version.
68 | Check the error message to determine what the actual problem was.
69 | */
70 | fatalError("Unresolved error \(error), \(error.userInfo)")
71 | }
72 | })
73 | return container
74 | }()
75 |
76 | // MARK: - Core Data Saving support
77 |
78 | func saveContext () {
79 | let context = persistentContainer.viewContext
80 | if context.hasChanges {
81 | do {
82 | try context.save()
83 | } catch {
84 | // Replace this implementation with code to handle the error appropriately.
85 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
86 | let nserror = error as NSError
87 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
88 | }
89 | }
90 | }
91 |
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // DepthApp
4 | //
5 | // Created by Juha Eskonen on 13/03/2019.
6 | // Copyright © 2019 Juha Eskonen. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AVFoundation
11 |
12 | class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate, AVCaptureDepthDataOutputDelegate {
13 | func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
14 | }
15 |
16 | let captureSession = AVCaptureSession()
17 | let sessionOutput = AVCapturePhotoOutput()
18 | let movieOutput = AVCaptureMovieFileOutput()
19 | var previewLayer = AVCaptureVideoPreviewLayer()
20 |
21 | var isRecording = false
22 |
23 | private let depthDataOutput = AVCaptureDepthDataOutput()
24 | private let dataOutputQueue = DispatchQueue(label: "dataOutputQueue")
25 | private let depthCapture = DepthCapture()
26 |
27 | private var outputSynchronizer: AVCaptureDataOutputSynchronizer?
28 |
29 | @IBOutlet var cameraView: UIView!
30 |
31 | override func viewWillAppear(_ animated: Bool) {
32 | if let device = AVCaptureDevice.default(.builtInTrueDepthCamera,
33 | for: .video, position: .front) {
34 |
35 | do {
36 |
37 | let input = try AVCaptureDeviceInput(device: device )
38 |
39 | if captureSession.canAddInput(input){
40 | captureSession.sessionPreset = AVCaptureSession.Preset.photo
41 | captureSession.addInput(input)
42 |
43 | if captureSession.canAddOutput(sessionOutput){
44 |
45 | captureSession.addOutput(sessionOutput)
46 |
47 | previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
48 | previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
49 | previewLayer.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
50 | cameraView.layer.addSublayer(previewLayer)
51 |
52 | previewLayer.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
53 | previewLayer.bounds = cameraView.frame
54 | }
55 |
56 | // Add depth output
57 | guard captureSession.canAddOutput(depthDataOutput) else { fatalError() }
58 | captureSession.addOutput(depthDataOutput)
59 |
60 | if let connection = depthDataOutput.connection(with: .depthData) {
61 | connection.isEnabled = true
62 | depthDataOutput.isFilteringEnabled = false
63 | depthDataOutput.setDelegate(self, callbackQueue: dataOutputQueue)
64 | } else {
65 | print("No AVCaptureConnection")
66 | }
67 |
68 | depthCapture.prepareForRecording()
69 |
70 | // TODO: Do we need to synchronize the video and depth outputs?
71 | //outputSynchronizer = AVCaptureDataOutputSynchronizer(dataOutputs: [sessionOutput, depthDataOutput])
72 |
73 | captureSession.addOutput(movieOutput)
74 |
75 | captureSession.startRunning()
76 | }
77 |
78 | } catch {
79 | print("Error")
80 | }
81 | }
82 | }
83 |
84 | func startRecording(){
85 | let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
86 | let fileUrl = paths[0].appendingPathComponent("output.mov")
87 | movieOutput.startRecording(to: fileUrl, recordingDelegate: self)
88 | print(fileUrl.absoluteString)
89 | print("Recording started")
90 | self.isRecording = true
91 |
92 | }
93 |
94 | func stopRecording(){
95 | movieOutput.stopRecording()
96 | print("Stopped recording!")
97 | self.isRecording = false
98 | do {
99 | try depthCapture.finishRecording(success: { (url: URL) -> Void in
100 | print(url.absoluteString)
101 | })
102 | } catch {
103 | print("Error while finishing depth capture.")
104 | }
105 |
106 | }
107 |
108 | @IBAction func startPressed(_ sender: Any) {
109 | startRecording()
110 | }
111 |
112 | @IBAction func stopPressed(_ sender: Any) {
113 | stopRecording()
114 | }
115 |
116 | func depthDataOutput(_ output: AVCaptureDepthDataOutput, didOutput depthData: AVDepthData, timestamp: CMTime, connection: AVCaptureConnection) {
117 | // Write depth data to a file
118 | if(self.isRecording) {
119 | let ddm = depthData.depthDataMap
120 | depthCapture.addPixelBuffers(pixelBuffer: ddm)
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp/DepthCapture.swift:
--------------------------------------------------------------------------------
1 | // DepthCapture.swift
2 | // AVCamPhotoFilter
3 | //
4 | // Created by Eyal Fink on 07/04/2018.
5 | // Copyright © 2018 Resonai. All rights reserved.
6 | //
7 | // Capture the depth pixelBuffer into a compress file.
8 | // This is very hacky and there are lots of TODOs but instead we need to replace
9 | // it with a much better compression (video compression)....
10 |
11 | import AVFoundation
12 | import Foundation
13 | import Compression
14 |
15 |
16 | class DepthCapture {
17 | let kErrorDomain = "DepthCapture"
18 | let maxNumberOfFrame = 250
19 | lazy var bufferSize = 640 * 480 * 2 * maxNumberOfFrame // maxNumberOfFrame frames
20 | var dstBuffer: UnsafeMutablePointer?
21 | var frameCount: Int64 = 0
22 | var outputURL: URL?
23 | var compresserPtr: UnsafeMutablePointer?
24 | var file: FileHandle?
25 |
26 | // All operations handling the compresser oobjects are done on the
27 | // porcessingQ so they will happen sequentially
28 | var processingQ = DispatchQueue(label: "compression",
29 | qos: .userInteractive)
30 |
31 |
32 | func reset() {
33 | frameCount = 0
34 | outputURL = nil
35 |
36 | if self.dstBuffer != nil {
37 | self.dstBuffer!.deallocate()
38 | self.dstBuffer = nil
39 | }
40 |
41 | if self.compresserPtr != nil {
42 | //free(compresserPtr!.pointee.dst_ptr)
43 | compression_stream_destroy(self.compresserPtr!)
44 | self.compresserPtr = nil
45 | }
46 | if self.file != nil {
47 | self.file!.closeFile()
48 | self.file = nil
49 | }
50 | }
51 | func prepareForRecording() {
52 | reset()
53 | // Create the output zip file, remove old one if exists
54 | let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
55 | self.outputURL = URL(fileURLWithPath: documentsPath.appendingPathComponent("Depth"))
56 | FileManager.default.createFile(atPath: self.outputURL!.path, contents: nil, attributes: nil)
57 | self.file = FileHandle(forUpdatingAtPath: self.outputURL!.path)
58 | if self.file == nil {
59 | NSLog("Cannot create file at: \(self.outputURL!.path)")
60 | return
61 | }
62 |
63 | // Init the compression object
64 | compresserPtr = UnsafeMutablePointer.allocate(capacity: 1)
65 | compression_stream_init(compresserPtr!, COMPRESSION_STREAM_ENCODE, COMPRESSION_ZLIB)
66 | dstBuffer = UnsafeMutablePointer.allocate(capacity: bufferSize)
67 | compresserPtr!.pointee.dst_ptr = dstBuffer!
68 | //defer { free(bufferPtr) }
69 | compresserPtr!.pointee.dst_size = bufferSize
70 |
71 |
72 | }
73 | func flush() {
74 | //let data = Data(bytesNoCopy: compresserPtr!.pointee.dst_ptr, count: bufferSize, deallocator: .none)
75 | let nBytes = bufferSize - compresserPtr!.pointee.dst_size
76 | print("Writing \(nBytes)")
77 | let data = Data(bytesNoCopy: dstBuffer!, count: nBytes, deallocator: .none)
78 | self.file?.write(data)
79 | }
80 |
81 | func startRecording() throws {
82 | processingQ.async {
83 | self.prepareForRecording()
84 | }
85 | }
86 | func addPixelBuffers(pixelBuffer: CVPixelBuffer) {
87 | processingQ.async {
88 | if self.frameCount >= self.maxNumberOfFrame {
89 | // TODO now!! flush when needed!!!
90 | print("MAXED OUT")
91 | return
92 | }
93 |
94 | CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
95 | let add : UnsafeMutableRawPointer = CVPixelBufferGetBaseAddress(pixelBuffer)!
96 | self.compresserPtr!.pointee.src_ptr = UnsafePointer(add.assumingMemoryBound(to: UInt8.self))
97 | let height = CVPixelBufferGetHeight(pixelBuffer)
98 | self.compresserPtr!.pointee.src_size = CVPixelBufferGetBytesPerRow(pixelBuffer) * height
99 | let flags = Int32(0)
100 | let compression_status = compression_stream_process(self.compresserPtr!, flags)
101 | if compression_status != COMPRESSION_STATUS_OK {
102 | NSLog("Buffer compression retured: \(compression_status)")
103 | return
104 | }
105 | if self.compresserPtr!.pointee.src_size != 0 {
106 | NSLog("Compression lib didn't eat all data: \(compression_status)")
107 | return
108 | }
109 | CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)
110 | // TODO(eyal): flush when needed!!!
111 | self.frameCount += 1
112 | print("handled \(self.frameCount) buffers")
113 | }
114 | }
115 | func finishRecording(success: @escaping ((URL) -> Void)) throws {
116 | processingQ.async {
117 | let flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
118 | self.compresserPtr!.pointee.src_size = 0
119 | //compresserPtr!.pointee.src_ptr = UnsafePointer(0)
120 | let compression_status = compression_stream_process(self.compresserPtr!, flags)
121 | if compression_status != COMPRESSION_STATUS_END {
122 | NSLog("ERROR: Finish failed. compression retured: \(compression_status)")
123 | return
124 | }
125 | self.flush()
126 | DispatchQueue.main.sync {
127 | success(self.outputURL!)
128 | }
129 | self.reset()
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/DepthApp/DepthApp.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | F019924122395746003F6D32 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F019924022395746003F6D32 /* AppDelegate.swift */; };
11 | F019924322395746003F6D32 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F019924222395746003F6D32 /* ViewController.swift */; };
12 | F019924622395746003F6D32 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F019924422395746003F6D32 /* Main.storyboard */; };
13 | F019924922395746003F6D32 /* DepthApp.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F019924722395746003F6D32 /* DepthApp.xcdatamodeld */; };
14 | F019924B22395748003F6D32 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F019924A22395748003F6D32 /* Assets.xcassets */; };
15 | F019924E22395748003F6D32 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F019924C22395748003F6D32 /* LaunchScreen.storyboard */; };
16 | F0DCF166224CDDAB00A1AA5E /* DepthCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0DCF165224CDDAB00A1AA5E /* DepthCapture.swift */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | F019923D22395746003F6D32 /* DepthApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DepthApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | F019924022395746003F6D32 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
22 | F019924222395746003F6D32 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
23 | F019924522395746003F6D32 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
24 | F019924822395746003F6D32 /* DepthApp.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DepthApp.xcdatamodel; sourceTree = ""; };
25 | F019924A22395748003F6D32 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
26 | F019924D22395748003F6D32 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
27 | F019924F22395748003F6D32 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | F0DCF165224CDDAB00A1AA5E /* DepthCapture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepthCapture.swift; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | F019923A22395746003F6D32 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | F019923422395746003F6D32 = {
43 | isa = PBXGroup;
44 | children = (
45 | F019923F22395746003F6D32 /* DepthApp */,
46 | F019923E22395746003F6D32 /* Products */,
47 | );
48 | sourceTree = "";
49 | };
50 | F019923E22395746003F6D32 /* Products */ = {
51 | isa = PBXGroup;
52 | children = (
53 | F019923D22395746003F6D32 /* DepthApp.app */,
54 | );
55 | name = Products;
56 | sourceTree = "";
57 | };
58 | F019923F22395746003F6D32 /* DepthApp */ = {
59 | isa = PBXGroup;
60 | children = (
61 | F019924022395746003F6D32 /* AppDelegate.swift */,
62 | F019924222395746003F6D32 /* ViewController.swift */,
63 | F019924422395746003F6D32 /* Main.storyboard */,
64 | F019924A22395748003F6D32 /* Assets.xcassets */,
65 | F019924C22395748003F6D32 /* LaunchScreen.storyboard */,
66 | F019924F22395748003F6D32 /* Info.plist */,
67 | F019924722395746003F6D32 /* DepthApp.xcdatamodeld */,
68 | F0DCF165224CDDAB00A1AA5E /* DepthCapture.swift */,
69 | );
70 | path = DepthApp;
71 | sourceTree = "";
72 | };
73 | /* End PBXGroup section */
74 |
75 | /* Begin PBXNativeTarget section */
76 | F019923C22395746003F6D32 /* DepthApp */ = {
77 | isa = PBXNativeTarget;
78 | buildConfigurationList = F019925222395748003F6D32 /* Build configuration list for PBXNativeTarget "DepthApp" */;
79 | buildPhases = (
80 | F019923922395746003F6D32 /* Sources */,
81 | F019923A22395746003F6D32 /* Frameworks */,
82 | F019923B22395746003F6D32 /* Resources */,
83 | );
84 | buildRules = (
85 | );
86 | dependencies = (
87 | );
88 | name = DepthApp;
89 | productName = DepthApp;
90 | productReference = F019923D22395746003F6D32 /* DepthApp.app */;
91 | productType = "com.apple.product-type.application";
92 | };
93 | /* End PBXNativeTarget section */
94 |
95 | /* Begin PBXProject section */
96 | F019923522395746003F6D32 /* Project object */ = {
97 | isa = PBXProject;
98 | attributes = {
99 | LastSwiftUpdateCheck = 1010;
100 | LastUpgradeCheck = 1010;
101 | ORGANIZATIONNAME = "Juha Eskonen";
102 | TargetAttributes = {
103 | F019923C22395746003F6D32 = {
104 | CreatedOnToolsVersion = 10.1;
105 | };
106 | };
107 | };
108 | buildConfigurationList = F019923822395746003F6D32 /* Build configuration list for PBXProject "DepthApp" */;
109 | compatibilityVersion = "Xcode 9.3";
110 | developmentRegion = en;
111 | hasScannedForEncodings = 0;
112 | knownRegions = (
113 | en,
114 | Base,
115 | );
116 | mainGroup = F019923422395746003F6D32;
117 | productRefGroup = F019923E22395746003F6D32 /* Products */;
118 | projectDirPath = "";
119 | projectRoot = "";
120 | targets = (
121 | F019923C22395746003F6D32 /* DepthApp */,
122 | );
123 | };
124 | /* End PBXProject section */
125 |
126 | /* Begin PBXResourcesBuildPhase section */
127 | F019923B22395746003F6D32 /* Resources */ = {
128 | isa = PBXResourcesBuildPhase;
129 | buildActionMask = 2147483647;
130 | files = (
131 | F019924E22395748003F6D32 /* LaunchScreen.storyboard in Resources */,
132 | F019924B22395748003F6D32 /* Assets.xcassets in Resources */,
133 | F019924622395746003F6D32 /* Main.storyboard in Resources */,
134 | );
135 | runOnlyForDeploymentPostprocessing = 0;
136 | };
137 | /* End PBXResourcesBuildPhase section */
138 |
139 | /* Begin PBXSourcesBuildPhase section */
140 | F019923922395746003F6D32 /* Sources */ = {
141 | isa = PBXSourcesBuildPhase;
142 | buildActionMask = 2147483647;
143 | files = (
144 | F019924322395746003F6D32 /* ViewController.swift in Sources */,
145 | F019924122395746003F6D32 /* AppDelegate.swift in Sources */,
146 | F0DCF166224CDDAB00A1AA5E /* DepthCapture.swift in Sources */,
147 | F019924922395746003F6D32 /* DepthApp.xcdatamodeld in Sources */,
148 | );
149 | runOnlyForDeploymentPostprocessing = 0;
150 | };
151 | /* End PBXSourcesBuildPhase section */
152 |
153 | /* Begin PBXVariantGroup section */
154 | F019924422395746003F6D32 /* Main.storyboard */ = {
155 | isa = PBXVariantGroup;
156 | children = (
157 | F019924522395746003F6D32 /* Base */,
158 | );
159 | name = Main.storyboard;
160 | sourceTree = "";
161 | };
162 | F019924C22395748003F6D32 /* LaunchScreen.storyboard */ = {
163 | isa = PBXVariantGroup;
164 | children = (
165 | F019924D22395748003F6D32 /* Base */,
166 | );
167 | name = LaunchScreen.storyboard;
168 | sourceTree = "";
169 | };
170 | /* End PBXVariantGroup section */
171 |
172 | /* Begin XCBuildConfiguration section */
173 | F019925022395748003F6D32 /* Debug */ = {
174 | isa = XCBuildConfiguration;
175 | buildSettings = {
176 | ALWAYS_SEARCH_USER_PATHS = NO;
177 | CLANG_ANALYZER_NONNULL = YES;
178 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
179 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
180 | CLANG_CXX_LIBRARY = "libc++";
181 | CLANG_ENABLE_MODULES = YES;
182 | CLANG_ENABLE_OBJC_ARC = YES;
183 | CLANG_ENABLE_OBJC_WEAK = YES;
184 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
185 | CLANG_WARN_BOOL_CONVERSION = YES;
186 | CLANG_WARN_COMMA = YES;
187 | CLANG_WARN_CONSTANT_CONVERSION = YES;
188 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
189 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
190 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
191 | CLANG_WARN_EMPTY_BODY = YES;
192 | CLANG_WARN_ENUM_CONVERSION = YES;
193 | CLANG_WARN_INFINITE_RECURSION = YES;
194 | CLANG_WARN_INT_CONVERSION = YES;
195 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
196 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
197 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
198 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
199 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
200 | CLANG_WARN_STRICT_PROTOTYPES = YES;
201 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
202 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
203 | CLANG_WARN_UNREACHABLE_CODE = YES;
204 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
205 | CODE_SIGN_IDENTITY = "iPhone Developer";
206 | COPY_PHASE_STRIP = NO;
207 | DEBUG_INFORMATION_FORMAT = dwarf;
208 | ENABLE_STRICT_OBJC_MSGSEND = YES;
209 | ENABLE_TESTABILITY = YES;
210 | GCC_C_LANGUAGE_STANDARD = gnu11;
211 | GCC_DYNAMIC_NO_PIC = NO;
212 | GCC_NO_COMMON_BLOCKS = YES;
213 | GCC_OPTIMIZATION_LEVEL = 0;
214 | GCC_PREPROCESSOR_DEFINITIONS = (
215 | "DEBUG=1",
216 | "$(inherited)",
217 | );
218 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
219 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
220 | GCC_WARN_UNDECLARED_SELECTOR = YES;
221 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
222 | GCC_WARN_UNUSED_FUNCTION = YES;
223 | GCC_WARN_UNUSED_VARIABLE = YES;
224 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
225 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
226 | MTL_FAST_MATH = YES;
227 | ONLY_ACTIVE_ARCH = YES;
228 | SDKROOT = iphoneos;
229 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
230 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
231 | };
232 | name = Debug;
233 | };
234 | F019925122395748003F6D32 /* Release */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CLANG_ANALYZER_NONNULL = YES;
239 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
240 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
241 | CLANG_CXX_LIBRARY = "libc++";
242 | CLANG_ENABLE_MODULES = YES;
243 | CLANG_ENABLE_OBJC_ARC = YES;
244 | CLANG_ENABLE_OBJC_WEAK = YES;
245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
246 | CLANG_WARN_BOOL_CONVERSION = YES;
247 | CLANG_WARN_COMMA = YES;
248 | CLANG_WARN_CONSTANT_CONVERSION = YES;
249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
251 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
252 | CLANG_WARN_EMPTY_BODY = YES;
253 | CLANG_WARN_ENUM_CONVERSION = YES;
254 | CLANG_WARN_INFINITE_RECURSION = YES;
255 | CLANG_WARN_INT_CONVERSION = YES;
256 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
257 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
258 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
260 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
261 | CLANG_WARN_STRICT_PROTOTYPES = YES;
262 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
263 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
264 | CLANG_WARN_UNREACHABLE_CODE = YES;
265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
266 | CODE_SIGN_IDENTITY = "iPhone Developer";
267 | COPY_PHASE_STRIP = NO;
268 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
269 | ENABLE_NS_ASSERTIONS = NO;
270 | ENABLE_STRICT_OBJC_MSGSEND = YES;
271 | GCC_C_LANGUAGE_STANDARD = gnu11;
272 | GCC_NO_COMMON_BLOCKS = YES;
273 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
274 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
275 | GCC_WARN_UNDECLARED_SELECTOR = YES;
276 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
277 | GCC_WARN_UNUSED_FUNCTION = YES;
278 | GCC_WARN_UNUSED_VARIABLE = YES;
279 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
280 | MTL_ENABLE_DEBUG_INFO = NO;
281 | MTL_FAST_MATH = YES;
282 | SDKROOT = iphoneos;
283 | SWIFT_COMPILATION_MODE = wholemodule;
284 | SWIFT_OPTIMIZATION_LEVEL = "-O";
285 | VALIDATE_PRODUCT = YES;
286 | };
287 | name = Release;
288 | };
289 | F019925322395748003F6D32 /* Debug */ = {
290 | isa = XCBuildConfiguration;
291 | buildSettings = {
292 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
293 | CODE_SIGN_STYLE = Automatic;
294 | DEVELOPMENT_TEAM = "";
295 | INFOPLIST_FILE = DepthApp/Info.plist;
296 | LD_RUNPATH_SEARCH_PATHS = (
297 | "$(inherited)",
298 | "@executable_path/Frameworks",
299 | );
300 | PRODUCT_BUNDLE_IDENTIFIER = com.mantoone.DepthApp;
301 | PRODUCT_NAME = "$(TARGET_NAME)";
302 | SWIFT_VERSION = 4.2;
303 | TARGETED_DEVICE_FAMILY = "1,2";
304 | };
305 | name = Debug;
306 | };
307 | F019925422395748003F6D32 /* Release */ = {
308 | isa = XCBuildConfiguration;
309 | buildSettings = {
310 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
311 | CODE_SIGN_STYLE = Automatic;
312 | DEVELOPMENT_TEAM = "";
313 | INFOPLIST_FILE = DepthApp/Info.plist;
314 | LD_RUNPATH_SEARCH_PATHS = (
315 | "$(inherited)",
316 | "@executable_path/Frameworks",
317 | );
318 | PRODUCT_BUNDLE_IDENTIFIER = com.mantoone.DepthApp;
319 | PRODUCT_NAME = "$(TARGET_NAME)";
320 | SWIFT_VERSION = 4.2;
321 | TARGETED_DEVICE_FAMILY = "1,2";
322 | };
323 | name = Release;
324 | };
325 | /* End XCBuildConfiguration section */
326 |
327 | /* Begin XCConfigurationList section */
328 | F019923822395746003F6D32 /* Build configuration list for PBXProject "DepthApp" */ = {
329 | isa = XCConfigurationList;
330 | buildConfigurations = (
331 | F019925022395748003F6D32 /* Debug */,
332 | F019925122395748003F6D32 /* Release */,
333 | );
334 | defaultConfigurationIsVisible = 0;
335 | defaultConfigurationName = Release;
336 | };
337 | F019925222395748003F6D32 /* Build configuration list for PBXNativeTarget "DepthApp" */ = {
338 | isa = XCConfigurationList;
339 | buildConfigurations = (
340 | F019925322395748003F6D32 /* Debug */,
341 | F019925422395748003F6D32 /* Release */,
342 | );
343 | defaultConfigurationIsVisible = 0;
344 | defaultConfigurationName = Release;
345 | };
346 | /* End XCConfigurationList section */
347 |
348 | /* Begin XCVersionGroup section */
349 | F019924722395746003F6D32 /* DepthApp.xcdatamodeld */ = {
350 | isa = XCVersionGroup;
351 | children = (
352 | F019924822395746003F6D32 /* DepthApp.xcdatamodel */,
353 | );
354 | currentVersion = F019924822395746003F6D32 /* DepthApp.xcdatamodel */;
355 | path = DepthApp.xcdatamodeld;
356 | sourceTree = "";
357 | versionGroupType = wrapper.xcdatamodel;
358 | };
359 | /* End XCVersionGroup section */
360 | };
361 | rootObject = F019923522395746003F6D32 /* Project object */;
362 | }
363 |
--------------------------------------------------------------------------------
/notebooks/ReadDepth.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Example for reading depth data file"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 24,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "import zlib\n",
17 | "import numpy as np\n",
18 | "import matplotlib.pyplot as plt\n",
19 | "import cv2"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 25,
25 | "metadata": {},
26 | "outputs": [],
27 | "source": [
28 | "depth_path = '/tmp/Depth'\n",
29 | "\n",
30 | "# Depth data parameters\n",
31 | "w = 640\n",
32 | "h = 480"
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | "### Read and decompress the depth data"
40 | ]
41 | },
42 | {
43 | "cell_type": "code",
44 | "execution_count": 26,
45 | "metadata": {},
46 | "outputs": [],
47 | "source": [
48 | "with open(depth_path, 'rb') as f:\n",
49 | " data = zlib.decompress(f.read(), -15)"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "execution_count": 27,
55 | "metadata": {},
56 | "outputs": [],
57 | "source": [
58 | "FRAME_COUNT = int(len(data) / w / h / 2)"
59 | ]
60 | },
61 | {
62 | "cell_type": "markdown",
63 | "metadata": {},
64 | "source": [
65 | "### Convert bytes to numpy array and set NaNs to zero"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": 28,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "frames = np.frombuffer(data, np.float16).reshape(FRAME_COUNT,h,w).copy()\n",
75 | "frames = np.nan_to_num(frames, 0)"
76 | ]
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {},
81 | "source": [
82 | "### Preprocess data for visualization"
83 | ]
84 | },
85 | {
86 | "cell_type": "code",
87 | "execution_count": 29,
88 | "metadata": {},
89 | "outputs": [],
90 | "source": [
91 | "maxim = frames.max()\n",
92 | "imgs = (frames / maxim * 255.0).astype('uint8')"
93 | ]
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {},
98 | "source": [
99 | "### Show one frame"
100 | ]
101 | },
102 | {
103 | "cell_type": "code",
104 | "execution_count": 30,
105 | "metadata": {},
106 | "outputs": [
107 | {
108 | "data": {
109 | "text/plain": [
110 | ""
111 | ]
112 | },
113 | "execution_count": 30,
114 | "metadata": {},
115 | "output_type": "execute_result"
116 | },
117 | {
118 | "data": {
119 | "image/png": "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\n",
120 | "text/plain": [
121 | ""
122 | ]
123 | },
124 | "metadata": {
125 | "needs_background": "light"
126 | },
127 | "output_type": "display_data"
128 | }
129 | ],
130 | "source": [
131 | "plt.imshow(np.flip(imgs[0,:,:].T, axis=1))"
132 | ]
133 | },
134 | {
135 | "cell_type": "markdown",
136 | "metadata": {},
137 | "source": [
138 | "### Write depth video to a file"
139 | ]
140 | },
141 | {
142 | "cell_type": "code",
143 | "execution_count": 31,
144 | "metadata": {},
145 | "outputs": [],
146 | "source": [
147 | "FPS = 25 # TODO: figure out the correct fps\n",
148 | "fourcc = cv2.VideoWriter_fourcc(*'mpv4')\n",
149 | "out = cv2.VideoWriter('depth_video.mp4',fourcc, FPS, (h,w))\n",
150 | "\n",
151 | "for i in range(FRAME_COUNT):\n",
152 | " out.write(cv2.cvtColor(np.flip(imgs[i,:,:].T, axis=1), cv2.COLOR_GRAY2BGR))\n",
153 | "\n",
154 | "out.release()"
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "execution_count": null,
160 | "metadata": {},
161 | "outputs": [],
162 | "source": []
163 | }
164 | ],
165 | "metadata": {
166 | "kernelspec": {
167 | "display_name": "Python 3",
168 | "language": "python",
169 | "name": "python3"
170 | },
171 | "language_info": {
172 | "codemirror_mode": {
173 | "name": "ipython",
174 | "version": 3
175 | },
176 | "file_extension": ".py",
177 | "mimetype": "text/x-python",
178 | "name": "python",
179 | "nbconvert_exporter": "python",
180 | "pygments_lexer": "ipython3",
181 | "version": "3.6.5"
182 | }
183 | },
184 | "nbformat": 4,
185 | "nbformat_minor": 2
186 | }
187 |
--------------------------------------------------------------------------------