├── bodyDetection
├── Experience.rcproject
│ ├── Library
│ │ └── ProjectLibrary
│ │ │ ├── Contents.json
│ │ │ └── Version.json
│ ├── SceneThumbnails
│ │ ├── F9610871-0955-494F-A5C3-51D1A281BAB3
│ │ └── F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails
│ │ │ ├── wide
│ │ │ └── square
│ └── com.apple.RCFoundation.Project
├── View
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
├── Extensions
│ ├── CGFloat+Extension.swift
│ ├── ARKit+Extension.swift
│ ├── UIKit+Extension.swift
│ └── CGPoint+Extension.swift
├── Info.plist
├── AppDelegate.swift
└── Controller
│ └── ViewController.swift
├── .gitignore
└── bodyDetection.xcodeproj
└── project.pbxproj
/bodyDetection/Experience.rcproject/Library/ProjectLibrary/Contents.json:
--------------------------------------------------------------------------------
1 | [
2 |
3 | ]
--------------------------------------------------------------------------------
/bodyDetection/View/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/bodyDetection/Experience.rcproject/Library/ProjectLibrary/Version.json:
--------------------------------------------------------------------------------
1 | {
2 | "LibraryID" : "BBB5EDD2-CBE1-49E5-931D-2C81F724D19D",
3 | "Version" : "1.0"
4 | }
--------------------------------------------------------------------------------
/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valengo/bodyDetection/HEAD/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3
--------------------------------------------------------------------------------
/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/wide:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valengo/bodyDetection/HEAD/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/wide
--------------------------------------------------------------------------------
/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/square:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valengo/bodyDetection/HEAD/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/square
--------------------------------------------------------------------------------
/bodyDetection/Extensions/CGFloat+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGFloat+Extension.swift
3 | // bodyDetection
4 | //
5 | // Created by Andressa Valengo on 28/10/19.
6 | // Copyright © 2019 Andressa Valengo. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CGFloat {
12 | func fomatted(with pattern: String = "%.3f") -> String {
13 | return String(format: pattern, Double(self))
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots/**/*.png
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/bodyDetection/View/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 |
--------------------------------------------------------------------------------
/bodyDetection/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 | arkit
33 |
34 | UIStatusBarHidden
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/bodyDetection/Extensions/ARKit+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ARExtensions.swift
3 | // bodyDetection
4 | //
5 | // Created by Andressa Valengo on 22/10/19.
6 | // Copyright © 2019 Andressa Valengo. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ARKit
11 |
12 | extension ARSkeleton.JointName {
13 |
14 | // from bottom to top
15 | @available(iOS 13.0, *)
16 | public static let spine2 = ARSkeleton.JointName(rawValue: "spine_2_joint")
17 |
18 | @available(iOS 13.0, *)
19 | public static let spine3 = ARSkeleton.JointName(rawValue: "spine_3_joint")
20 |
21 | @available(iOS 13.0, *)
22 | public static let spine4 = ARSkeleton.JointName(rawValue: "spine_4_joint")
23 |
24 | @available(iOS 13.0, *)
25 | public static let spine5 = ARSkeleton.JointName(rawValue: "spine_5_joint")
26 |
27 | @available(iOS 13.0, *)
28 | public static let spine6 = ARSkeleton.JointName(rawValue: "spine_6_joint")
29 |
30 | @available(iOS 13.0, *)
31 | public static let spine7 = ARSkeleton.JointName(rawValue: "spine_7_joint")
32 |
33 | // from bottom to top
34 | @available(iOS 13.0, *)
35 | public static let neck1 = ARSkeleton.JointName(rawValue: "neck_1_joint")
36 |
37 | @available(iOS 13.0, *)
38 | public static let neck2 = ARSkeleton.JointName(rawValue: "neck_2_joint")
39 |
40 | @available(iOS 13.0, *)
41 | public static let neck3 = ARSkeleton.JointName(rawValue: "neck_3_joint")
42 |
43 | @available(iOS 13.0, *)
44 | public static let neck4 = ARSkeleton.JointName(rawValue: "neck_4_joint")
45 |
46 | @available(iOS 13.0, *)
47 | public static let rigthArm = ARSkeleton.JointName(rawValue: "right_arm_joint")
48 |
49 | @available(iOS 13.0, *)
50 | public static let leftArm = ARSkeleton.JointName(rawValue: "left_arm_joint")
51 | }
52 |
--------------------------------------------------------------------------------
/bodyDetection/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // bodyDetection
4 | //
5 | // Created by Andressa Valengo on 22/10/19.
6 | // Copyright © 2019 Andressa Valengo. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // 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.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // 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.
29 | }
30 |
31 | func applicationWillEnterForeground(_ application: UIApplication) {
32 | // 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.
33 | }
34 |
35 | func applicationDidBecomeActive(_ application: UIApplication) {
36 | // 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.
37 | }
38 |
39 |
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/bodyDetection/View/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 | }
--------------------------------------------------------------------------------
/bodyDetection/Experience.rcproject/com.apple.RCFoundation.Project:
--------------------------------------------------------------------------------
1 | {
2 | "__version" : 1,
3 | "__content" : [
4 | {
5 | "tags" : {
6 | "__version" : 1,
7 | "__content" : [
8 | {
9 | "tagsStore" : {
10 |
11 | }
12 | }
13 | ]
14 | },
15 | "scenes" : [
16 | {
17 | "__version" : 2,
18 | "__content" : [
19 | {
20 | "hasGroundPlane" : true,
21 | "gravity" : [
22 | 0,
23 | -9.8000001907348633,
24 | 0
25 | ],
26 | "arAnchorSpecification" : {
27 | "name" : "surface",
28 | "classification" : 0,
29 | "alignment" : 1
30 | },
31 | "title" : "Box",
32 | "material" : "concrete",
33 | "layoutData" : {
34 | "version" : 1,
35 | "constraints" : [
36 |
37 | ]
38 | },
39 | "identifier" : "F9610871-0955-494F-A5C3-51D1A281BAB3",
40 | "behaviors" : [
41 |
42 | ],
43 | "overrides" : {
44 | "factory" : null,
45 | "children" : {
46 | "4A213441-135C-450E-8EF8-1A4EAB267C1D" : {
47 | "overrides" : {
48 | "factory" : {
49 | "version" : "1.0",
50 | "identifier" : "com.apple.rc.af.CoreAssetFactories.PrimitiveShapeAssetFactory"
51 | },
52 | "arguments" : [
53 | [
54 | "material",
55 | {
56 | "value" : "steel",
57 | "typeName" : "String"
58 | }
59 | ],
60 | [
61 | "type",
62 | {
63 | "value" : "box",
64 | "typeName" : "String"
65 | }
66 | ]
67 | ],
68 | "runtimeAttributes" : [
69 | [
70 | "RuntimeIdentifier",
71 | {
72 | "value" : "3788A5B5-0388-488A-8304-7B90FEBA6FAC",
73 | "typeName" : "UUID"
74 | }
75 | ],
76 | [
77 | "entityName",
78 | {
79 | "value" : "Steel Box",
80 | "typeName" : "String"
81 | }
82 | ]
83 | ]
84 | },
85 | "transform" : {
86 | "matrix" : [
87 | 1,
88 | 0,
89 | 0,
90 | 0,
91 | 0,
92 | 1,
93 | 0,
94 | 0,
95 | 0,
96 | 0,
97 | 1,
98 | 0,
99 | 0,
100 | 0.05000000074505806,
101 | 0,
102 | 1
103 | ]
104 | }
105 | },
106 | "B91C7CA3-4AB1-4253-9A84-07383168A8A8" : null,
107 | "7F5F1ADC-E5E4-4EF5-A5B5-FC43B071FFA5" : null,
108 | "632E476F-1E55-4E30-9723-1C51DD2E8B89" : null
109 | }
110 | },
111 | "viewTransform" : {
112 | "sceneTransform" : [
113 | 1,
114 | 0,
115 | 0,
116 | 0,
117 | 0,
118 | 0.99999994039535522,
119 | 0,
120 | 0,
121 | 0,
122 | 0,
123 | 0.99999994039535522,
124 | 0,
125 | 0,
126 | 0,
127 | 0,
128 | 1
129 | ],
130 | "cameraTransform" : [
131 | 0.99999994039535522,
132 | 0,
133 | 0,
134 | 0,
135 | 0,
136 | 0.80754852294921875,
137 | -0.58980101346969604,
138 | 0,
139 | 0,
140 | 0.58980101346969604,
141 | 0.80754852294921875,
142 | 0,
143 | 0,
144 | 1.135667085647583,
145 | 1.5549418926239014,
146 | 1
147 | ]
148 | }
149 | }
150 | ]
151 | }
152 | ]
153 | }
154 | ]
155 | }
--------------------------------------------------------------------------------
/bodyDetection/Extensions/UIKit+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // bodyDetection
4 | //
5 | // Created by Andressa Valengo on 22/10/19.
6 | // Copyright © 2019 Andressa Valengo. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import VideoToolbox
12 |
13 | extension CGImage {
14 | func colors(at: [CGPoint]) -> [UIColor]? {
15 | let colorSpace = CGColorSpaceCreateDeviceRGB()
16 | let bytesPerPixel = 4
17 | let bytesPerRow = bytesPerPixel * width
18 | let bitsPerComponent = 8
19 | let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
20 |
21 | guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo),
22 | let ptr = context.data?.assumingMemoryBound(to: UInt8.self) else {
23 | return nil
24 | }
25 |
26 | context.draw(self, in: CGRect(x: 0, y: 0, width: width, height: height))
27 |
28 | return at.map { p in
29 | let i = bytesPerRow * Int(p.y) + bytesPerPixel * Int(p.x)
30 |
31 | let a = CGFloat(ptr[i + 3]) / 255.0
32 | let r = (CGFloat(ptr[i]) / a) / 255.0
33 | let g = (CGFloat(ptr[i + 1]) / a) / 255.0
34 | let b = (CGFloat(ptr[i + 2]) / a) / 255.0
35 |
36 | return UIColor(red: r, green: g, blue: b, alpha: a)
37 | }
38 | }
39 | }
40 |
41 | extension UIImage {
42 | func rotate(radians: CGFloat) -> UIImage {
43 | let rotatedSize = CGRect(origin: .zero, size: size)
44 | .applying(CGAffineTransform(rotationAngle: CGFloat(radians)))
45 | .integral.size
46 | UIGraphicsBeginImageContext(rotatedSize)
47 | if let context = UIGraphicsGetCurrentContext() {
48 | let origin = CGPoint(x: rotatedSize.width / 2.0,
49 | y: rotatedSize.height / 2.0)
50 | context.translateBy(x: origin.x, y: origin.y)
51 | context.rotate(by: radians)
52 | draw(in: CGRect(x: -origin.y, y: -origin.x,
53 | width: size.width, height: size.height))
54 | let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
55 | UIGraphicsEndImageContext()
56 |
57 | return rotatedImage ?? self
58 | }
59 | return self
60 | }
61 | }
62 |
63 | extension UIImage {
64 | public convenience init?(pixelBuffer: CVPixelBuffer) {
65 | var cgImage: CGImage?
66 | VTCreateCGImageFromCVPixelBuffer(pixelBuffer, options: nil, imageOut: &cgImage)
67 |
68 | if let cgImage = cgImage {
69 | self.init(cgImage: cgImage)
70 | } else {
71 | return nil
72 | }
73 | }
74 | }
75 |
76 | extension UIColor {
77 | var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
78 | var red: CGFloat = 0
79 | var green: CGFloat = 0
80 | var blue: CGFloat = 0
81 | var alpha: CGFloat = 0
82 | getRed(&red, green: &green, blue: &blue, alpha: &alpha)
83 |
84 | return (red, green, blue, alpha)
85 | }
86 | }
87 |
88 | extension UIImage {
89 | func resizedImage(newSize: CGSize) -> UIImage? {
90 | guard self.size != newSize else { return self }
91 | UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
92 | self.draw(in: CGRect(origin: .zero, size: newSize))
93 | let newImage = UIGraphicsGetImageFromCurrentImageContext()
94 | UIGraphicsEndImageContext()
95 | return newImage
96 | }
97 |
98 | func resizedImageWithinRect(rectSize: CGSize) -> UIImage? {
99 | let widthFactor = size.width / rectSize.width
100 | let heightFactor = size.height / rectSize.height
101 |
102 | var resizeFactor = widthFactor
103 | if size.height > size.width {
104 | resizeFactor = heightFactor
105 | }
106 |
107 | let newSize = CGSize(width: size.width/resizeFactor, height: size.height/resizeFactor)
108 | let resized = resizedImage(newSize: newSize)
109 | return resized
110 | }
111 |
112 | func resizedImageWithAspectFill(for rectSize: CGSize) -> UIImage? {
113 | let newWidth: CGFloat = rectSize.width / size.width
114 | let newHeight: CGFloat = rectSize.height / size.height
115 | var aspectFillSize = CGSize(width: rectSize.width, height: rectSize.height)
116 |
117 | if newHeight > newWidth {
118 | aspectFillSize.width = newHeight * size.width
119 | } else if newWidth > newHeight {
120 | aspectFillSize.height = newWidth * size.height
121 | }
122 | return resizedImage(newSize: aspectFillSize)
123 | }
124 | }
125 |
126 | extension UIImageView {
127 | var aspectFitSize: CGSize {
128 | guard let image = image else { return CGSize.zero }
129 |
130 | var aspectFitSize = CGSize(width: frame.size.width, height: frame.size.height)
131 | let newWidth: CGFloat = frame.size.width / image.size.width
132 | let newHeight: CGFloat = frame.size.height / image.size.height
133 |
134 | if newHeight < newWidth {
135 | aspectFitSize.width = newHeight * image.size.width
136 | } else if newWidth < newHeight {
137 | aspectFitSize.height = newWidth * image.size.height
138 | }
139 |
140 | return aspectFitSize
141 | }
142 |
143 | var aspectFillSize: CGSize {
144 | guard let image = image else { return CGSize.zero }
145 |
146 | var aspectFillSize = CGSize(width: frame.size.width, height: frame.size.height)
147 | let newWidth: CGFloat = frame.size.width / image.size.width
148 | let newHeight: CGFloat = frame.size.height / image.size.height
149 |
150 | if newHeight > newWidth {
151 | aspectFillSize.width = newHeight * image.size.width
152 | } else if newWidth > newHeight {
153 | aspectFillSize.height = newWidth * image.size.height
154 | }
155 |
156 | return aspectFillSize
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/bodyDetection/Extensions/CGPoint+Extension.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013-2014 Razeware LLC
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | import CoreGraphics
24 | import SpriteKit
25 |
26 | public extension CGPoint {
27 | /**
28 | * Creates a new CGPoint given a CGVector.
29 | */
30 | init(vector: CGVector) {
31 | self.init(x: vector.dx, y: vector.dy)
32 | }
33 |
34 | /**
35 | * Given an angle in radians, creates a vector of length 1.0 and returns the
36 | * result as a new CGPoint. An angle of 0 is assumed to point to the right.
37 | */
38 | init(angle: CGFloat) {
39 | self.init(x: cos(angle), y: sin(angle))
40 | }
41 |
42 | /**
43 | * Adds (dx, dy) to the point.
44 | */
45 | mutating func offset(dx: CGFloat, dy: CGFloat) -> CGPoint {
46 | x += dx
47 | y += dy
48 | return self
49 | }
50 |
51 | /**
52 | * Returns the length (magnitude) of the vector described by the CGPoint.
53 | */
54 | func length() -> CGFloat {
55 | return sqrt(x*x + y*y)
56 | }
57 |
58 | /**
59 | * Returns the squared length of the vector described by the CGPoint.
60 | */
61 | func lengthSquared() -> CGFloat {
62 | return x*x + y*y
63 | }
64 |
65 | /**
66 | * Normalizes the vector described by the CGPoint to length 1.0 and returns
67 | * the result as a new CGPoint.
68 | */
69 | func normalized() -> CGPoint {
70 | let len = length()
71 | return len>0 ? self / len : CGPoint.zero
72 | }
73 |
74 | /**
75 | * Normalizes the vector described by the CGPoint to length 1.0.
76 | */
77 | mutating func normalize() -> CGPoint {
78 | self = normalized()
79 | return self
80 | }
81 |
82 | /**
83 | * Calculates the distance between two CGPoints. Pythagoras!
84 | */
85 | func distanceTo(_ point: CGPoint) -> CGFloat {
86 | return (self - point).length()
87 | }
88 |
89 | /**
90 | * Returns the angle in radians of the vector described by the CGPoint.
91 | * The range of the angle is -π to π; an angle of 0 points to the right.
92 | */
93 | var angle: CGFloat {
94 | return atan2(y, x)
95 | }
96 | }
97 |
98 | /**
99 | * Adds two CGPoint values and returns the result as a new CGPoint.
100 | */
101 | public func + (left: CGPoint, right: CGPoint) -> CGPoint {
102 | return CGPoint(x: left.x + right.x, y: left.y + right.y)
103 | }
104 |
105 | /**
106 | * Increments a CGPoint with the value of another.
107 | */
108 | public func += (left: inout CGPoint, right: CGPoint) {
109 | left = left + right
110 | }
111 |
112 | /**
113 | * Adds a CGVector to this CGPoint and returns the result as a new CGPoint.
114 | */
115 | public func + (left: CGPoint, right: CGVector) -> CGPoint {
116 | return CGPoint(x: left.x + right.dx, y: left.y + right.dy)
117 | }
118 |
119 | /**
120 | * Increments a CGPoint with the value of a CGVector.
121 | */
122 | public func += (left: inout CGPoint, right: CGVector) {
123 | left = left + right
124 | }
125 |
126 | /**
127 | * Subtracts two CGPoint values and returns the result as a new CGPoint.
128 | */
129 | public func - (left: CGPoint, right: CGPoint) -> CGPoint {
130 | return CGPoint(x: left.x - right.x, y: left.y - right.y)
131 | }
132 |
133 | /**
134 | * Decrements a CGPoint with the value of another.
135 | */
136 | public func -= (left: inout CGPoint, right: CGPoint) {
137 | left = left - right
138 | }
139 |
140 | /**
141 | * Subtracts a CGVector from a CGPoint and returns the result as a new CGPoint.
142 | */
143 | public func - (left: CGPoint, right: CGVector) -> CGPoint {
144 | return CGPoint(x: left.x - right.dx, y: left.y - right.dy)
145 | }
146 |
147 | /**
148 | * Decrements a CGPoint with the value of a CGVector.
149 | */
150 | public func -= (left: inout CGPoint, right: CGVector) {
151 | left = left - right
152 | }
153 |
154 | /**
155 | * Multiplies two CGPoint values and returns the result as a new CGPoint.
156 | */
157 | public func * (left: CGPoint, right: CGPoint) -> CGPoint {
158 | return CGPoint(x: left.x * right.x, y: left.y * right.y)
159 | }
160 |
161 | /**
162 | * Multiplies a CGPoint with another.
163 | */
164 | public func *= (left: inout CGPoint, right: CGPoint) {
165 | left = left * right
166 | }
167 |
168 | /**
169 | * Multiplies the x and y fields of a CGPoint with the same scalar value and
170 | * returns the result as a new CGPoint.
171 | */
172 | public func * (point: CGPoint, scalar: CGFloat) -> CGPoint {
173 | return CGPoint(x: point.x * scalar, y: point.y * scalar)
174 | }
175 |
176 | /**
177 | * Multiplies the x and y fields of a CGPoint with the same scalar value.
178 | */
179 | public func *= (point: inout CGPoint, scalar: CGFloat) {
180 | point = point * scalar
181 | }
182 |
183 | /**
184 | * Multiplies a CGPoint with a CGVector and returns the result as a new CGPoint.
185 | */
186 | public func * (left: CGPoint, right: CGVector) -> CGPoint {
187 | return CGPoint(x: left.x * right.dx, y: left.y * right.dy)
188 | }
189 |
190 | /**
191 | * Multiplies a CGPoint with a CGVector.
192 | */
193 | public func *= (left: inout CGPoint, right: CGVector) {
194 | left = left * right
195 | }
196 |
197 | /**
198 | * Divides two CGPoint values and returns the result as a new CGPoint.
199 | */
200 | public func / (left: CGPoint, right: CGPoint) -> CGPoint {
201 | return CGPoint(x: left.x / right.x, y: left.y / right.y)
202 | }
203 |
204 | /**
205 | * Divides a CGPoint by another.
206 | */
207 | public func /= (left: inout CGPoint, right: CGPoint) {
208 | left = left / right
209 | }
210 |
211 | /**
212 | * Divides the x and y fields of a CGPoint by the same scalar value and returns
213 | * the result as a new CGPoint.
214 | */
215 | public func / (point: CGPoint, scalar: CGFloat) -> CGPoint {
216 | return CGPoint(x: point.x / scalar, y: point.y / scalar)
217 | }
218 |
219 | /**
220 | * Divides the x and y fields of a CGPoint by the same scalar value.
221 | */
222 | public func /= (point: inout CGPoint, scalar: CGFloat) {
223 | point = point / scalar
224 | }
225 |
226 | /**
227 | * Divides a CGPoint by a CGVector and returns the result as a new CGPoint.
228 | */
229 | public func / (left: CGPoint, right: CGVector) -> CGPoint {
230 | return CGPoint(x: left.x / right.dx, y: left.y / right.dy)
231 | }
232 |
233 | /**
234 | * Divides a CGPoint by a CGVector.
235 | */
236 | public func /= (left: inout CGPoint, right: CGVector) {
237 | left = left / right
238 | }
239 |
240 | /**
241 | * Performs a linear interpolation between two CGPoint values.
242 | */
243 | public func lerp(start: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint {
244 | return start + (end - start) * t
245 | }
246 |
--------------------------------------------------------------------------------
/bodyDetection/View/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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
53 |
59 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/bodyDetection/Controller/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // bodyDetection
4 | //
5 | // Created by Andressa Valengo on 22/10/19.
6 | // Copyright © 2019 Andressa Valengo. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import RealityKit
11 | import ARKit
12 | import Combine
13 |
14 | class CustomSphere: Entity, HasModel {
15 | required init(color: UIColor, radius: Float) {
16 | super.init()
17 | self.components[ModelComponent] = ModelComponent(
18 | mesh: .generateSphere(radius: radius),
19 | materials: [SimpleMaterial(
20 | color: color,
21 | isMetallic: false)
22 | ]
23 | )
24 | }
25 |
26 | required init() {
27 | fatalError("init() has not been implemented")
28 | }
29 | }
30 |
31 | class JointViewModel {
32 | var name: ARSkeleton.JointName
33 | var transform: simd_float4x4
34 | var point: CGPoint
35 |
36 | init(name: ARSkeleton.JointName, transform: simd_float4x4, point: CGPoint) {
37 | self.name = name
38 | self.transform = transform
39 | self.point = point
40 | }
41 | }
42 |
43 | class ViewController: UIViewController {
44 |
45 | enum SceneState {
46 | case looking
47 | case detectingStart
48 | case dectingEnd
49 | case trackingStart
50 | }
51 |
52 | var sceneState: SceneState = .looking
53 |
54 | @IBOutlet weak var distancesTextView: UITextView!
55 | @IBOutlet weak var stateMessage: UILabel!
56 | @IBOutlet var arView: ARView!
57 | @IBOutlet weak var segmentationImage: UIImageView!
58 | @IBOutlet weak var startRecordingStateImage: UIImageView!
59 | @IBOutlet weak var stopRecordingStateImage: UIImageView!
60 |
61 | let jointNames: [ARSkeleton.JointName] = [.root, .spine2, .spine3, .spine4, .spine5, .spine6, .spine7]
62 | let context = CIContext(options: nil)
63 |
64 | var jointDots = [CAShapeLayer]()
65 | var jointProjections = [ARSkeleton.JointName: JointViewModel]()
66 | var estimationDots = [CAShapeLayer]()
67 | var addedSpheres = [CustomSphere]()
68 |
69 | var corePointsDistance = [ARSkeleton.JointName: CGFloat]()
70 |
71 | let spheresAnchor = AnchorEntity()
72 |
73 | var bodyAnchor: ARBodyAnchor?
74 |
75 | override func viewDidLoad() {
76 | super.viewDidLoad()
77 | arView.session.delegate = self
78 |
79 | distancesTextView.text = ""
80 |
81 | guard ARWorldTrackingConfiguration.isSupported else {
82 | fatalError("This feature is only supported on devices with an A12 chip")
83 | }
84 |
85 | // arView.debugOptions = [.showAnchorGeometry, .showAnchorOrigins, .showWorldOrigin]
86 | }
87 |
88 | func toggleCamera() {
89 | startRecordingStateImage.isHidden = !startRecordingStateImage.isHidden
90 | stopRecordingStateImage.isHidden = !stopRecordingStateImage.isHidden
91 | }
92 |
93 | @IBAction func cameraButtonTap(_ sender: Any) {
94 | switch sceneState {
95 | case .looking:
96 | sceneState = .detectingStart
97 | detectBody()
98 | case .detectingStart:
99 | sceneState = .dectingEnd
100 | case .dectingEnd:
101 | sceneState = .trackingStart
102 | detectJoints()
103 | case .trackingStart:
104 | sceneState = .looking
105 | estimateScale()
106 | estimateCoreScale()
107 | }
108 | toggleCamera()
109 | setStateMessage()
110 | }
111 |
112 | func setStateMessage() {
113 | if sceneState == .detectingStart {
114 | stateMessage.text = "Detecting body..."
115 | } else if sceneState == .trackingStart {
116 | stateMessage.text = "Detecting joints..."
117 | } else {
118 | stateMessage.text = ""
119 | }
120 | }
121 |
122 | @IBAction func resetState() {
123 | sceneState = .looking
124 | segmentationImage.image = nil
125 | hideAllJoints2D()
126 | setStateMessage()
127 | hideEstimationDots()
128 | distancesTextView.text = ""
129 |
130 | startRecordingStateImage.isHidden = false
131 | stopRecordingStateImage.isHidden = true
132 |
133 | addedSpheres.forEach {
134 | $0.removeFromParent()
135 | }
136 | addedSpheres.removeAll()
137 | }
138 |
139 | func detectJoints() {
140 | let configuration = ARBodyTrackingConfiguration()
141 | arView.session.run(configuration)
142 | arView.scene.addAnchor(spheresAnchor)
143 | }
144 |
145 | func detectBody() {
146 | let config = ARWorldTrackingConfiguration()
147 | config.frameSemantics = [.personSegmentation]
148 | arView.session.run(config)
149 | }
150 |
151 | @IBAction func hideAllJoints2D() {
152 | jointDots.forEach {
153 | $0.removeFromSuperlayer()
154 | }
155 | jointDots.removeAll()
156 | }
157 |
158 | @IBAction func hideEstimationDots() {
159 | estimationDots.forEach {
160 | $0.removeFromSuperlayer()
161 | }
162 | estimationDots.removeAll()
163 | }
164 |
165 | @IBAction func toggleSegmentationImageContentMode() {
166 | if segmentationImage.contentMode == .scaleAspectFit {
167 | segmentationImage.contentMode = .scaleAspectFill
168 | } else {
169 | segmentationImage.contentMode = .scaleAspectFit
170 | }
171 | }
172 |
173 | @IBAction func showAllJoints2D() {
174 | guard let anchors = arView.session.currentFrame?.anchors else {return}
175 | for anchor in anchors {
176 | if let bodyAnchor = anchor as? ARBodyAnchor {
177 | self.bodyAnchor = bodyAnchor
178 |
179 | hideAllJoints2D()
180 |
181 | let bodyPosition = simd_make_float3(bodyAnchor.transform.columns.3)
182 |
183 | for jointName in jointNames {
184 | if let transform = bodyAnchor.skeleton.modelTransform(for: jointName) {
185 | let position = bodyPosition + simd_make_float3(transform.columns.3)
186 | print("original \(jointName.rawValue): \(position)")
187 | let projection = arView.project([position.x, position.y, position.z])!
188 |
189 | let shapeLayer = CAShapeLayer();
190 | shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: CGFloat(projection.x), y: CGFloat(projection.y), width: 3, height: 3)).cgPath;
191 | shapeLayer.fillColor = UIColor.green.cgColor
192 | view.layer.addSublayer(shapeLayer)
193 | jointDots.append(shapeLayer)
194 |
195 | jointProjections[jointName] = JointViewModel(name: jointName, transform: transform, point: projection)
196 | }
197 | }
198 | }
199 | }
200 | }
201 |
202 | func estimatePoint(pointsOfInterest: [CGPoint], cgImage: CGImage) {
203 | if let colors = cgImage.colors(at: pointsOfInterest) {
204 | for i in 0.. float4x4 {
253 | var normalized = matrix
254 | normalized.columns.0 = simd.normalize(normalized.columns.0)
255 | normalized.columns.1 = simd.normalize(normalized.columns.1)
256 | normalized.columns.2 = simd.normalize(normalized.columns.2)
257 | return normalized
258 | }
259 |
260 | func estimateMaxPoint(of pointsOfInterest: [CGPoint], in cgImage: CGImage) -> CGPoint? {
261 | if let colors = cgImage.colors(at: pointsOfInterest) {
262 | let offset = abs(segmentationImage.aspectFillSize.width - segmentationImage.frame.size.width) / 2
263 | let xProportion = segmentationImage.aspectFillSize.width / CGFloat(cgImage.width)
264 | let yProportion = segmentationImage.aspectFillSize.height / CGFloat(cgImage.height)
265 |
266 | for i in 0.. 3D \(CGFloat(simd_distance(rightUnp, leftUnp)).fomatted())\n")
289 | }
290 | }
291 |
292 | func addSphere(radius: Float, anchor: AnchorEntity, transform: Transform) {
293 | let sphere = CustomSphere(color: .systemPink, radius: radius)
294 | sphere.transform = transform
295 | anchor.addChild(sphere, preservingWorldTransform: true)
296 | addedSpheres.append(sphere)
297 | }
298 |
299 | func estimateCoreScale() {
300 |
301 | guard let rootData = jointProjections[.root],
302 | let spine7data = jointProjections[.spine7] else {return}
303 |
304 | let distance3D = CGFloat(simd_distance(spine7data.transform.columns.3, rootData.transform.columns.3))
305 | let distance2D = spine7data.point.distanceTo(rootData.point)
306 | let scaleProportion = distance3D / distance2D
307 |
308 | distancesTextView.text.append(contentsOf: "Estimated distances:\n")
309 | distancesTextView.text.append(contentsOf: "Core height -> 2D: \(distance2D.fomatted()); 3D \(distance3D.fomatted())\n")
310 |
311 | if let image = segmentationImage.image, let cgImage = image.cgImage {
312 | for jointName in jointNames {
313 | let xProportion = CGFloat(cgImage.width) / view.frame.size.width
314 | let yProportion = CGFloat(cgImage.height) / view.frame.size.height
315 | if let screenPoint = jointProjections[jointName]?.point {
316 | let projectedScreenPoint = CGPoint(x: screenPoint.x * xProportion, y: screenPoint.y * yProportion)
317 | var pointsOfInterest = [CGPoint]()
318 | for i in Int(screenPoint.x)...Int(view.frame.width) {
319 | pointsOfInterest.append(CGPoint(x: CGFloat(i) * xProportion, y: projectedScreenPoint.y))
320 | }
321 | let rightPoint = estimateMaxPoint(of: pointsOfInterest, in: cgImage)
322 | pointsOfInterest.removeAll()
323 |
324 | for i in 0...Int(view.frame.width)/2 {
325 | pointsOfInterest.append(CGPoint(x: CGFloat(i) * xProportion, y: projectedScreenPoint.y))
326 | }
327 | let leftPoint = estimateMaxPoint(of: pointsOfInterest.reversed(), in: cgImage)
328 |
329 | if let rightPoint = rightPoint, let leftPoint = leftPoint {
330 | if jointName == .root {
331 | checkSize(left: leftPoint, right: rightPoint)
332 | }
333 | let distanceBetweenPoints = rightPoint.distanceTo(leftPoint)
334 | corePointsDistance[jointName] = distanceBetweenPoints
335 | distancesTextView.text.append(contentsOf: "\(jointName.rawValue) -> 2D: \(distanceBetweenPoints.fomatted()); 3D \((distanceBetweenPoints * scaleProportion).fomatted())\n")
336 | }
337 |
338 | }
339 | }
340 | }
341 | }
342 | }
343 |
344 | extension ViewController: ARSessionDelegate {
345 | func session(_ session: ARSession, didUpdate frame: ARFrame) {
346 | if sceneState == .detectingStart, let segmentationBuffer = frame.segmentationBuffer {
347 | if let image = UIImage(pixelBuffer: segmentationBuffer)?.rotate(radians: .pi / 2) {
348 | segmentationImage.image = image
349 | }
350 | }
351 | }
352 |
353 | func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
354 | for anchor in anchors {
355 | guard let _ = anchor as? ARBodyAnchor else {continue}
356 | if sceneState == .trackingStart {
357 | showAllJoints2D()
358 | }
359 | }
360 | }
361 | }
362 |
--------------------------------------------------------------------------------
/bodyDetection.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 6418F775235F4A8400CE2EAE /* UIKit+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6418F774235F4A8400CE2EAE /* UIKit+Extension.swift */; };
11 | 64853755236786B700C0FCAA /* CGPoint+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64853754236786B700C0FCAA /* CGPoint+Extension.swift */; };
12 | 648537572367CDB500C0FCAA /* CGFloat+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648537562367CDB500C0FCAA /* CGFloat+Extension.swift */; };
13 | 64C8C756235FE68A0099949C /* ARKit+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C8C755235FE68A0099949C /* ARKit+Extension.swift */; };
14 | 64EC6A52235F3E0C00CB6B59 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC6A51235F3E0C00CB6B59 /* AppDelegate.swift */; };
15 | 64EC6A54235F3E0C00CB6B59 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC6A53235F3E0C00CB6B59 /* ViewController.swift */; };
16 | 64EC6A59235F3E0C00CB6B59 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64EC6A57235F3E0C00CB6B59 /* Main.storyboard */; };
17 | 64EC6A5B235F3E0E00CB6B59 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64EC6A5A235F3E0E00CB6B59 /* Assets.xcassets */; };
18 | 64EC6A5E235F3E0E00CB6B59 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64EC6A5C235F3E0E00CB6B59 /* LaunchScreen.storyboard */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXFileReference section */
22 | 6418F774235F4A8400CE2EAE /* UIKit+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKit+Extension.swift"; sourceTree = ""; };
23 | 64853754236786B700C0FCAA /* CGPoint+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGPoint+Extension.swift"; sourceTree = ""; };
24 | 648537562367CDB500C0FCAA /* CGFloat+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extension.swift"; sourceTree = ""; };
25 | 64C8C755235FE68A0099949C /* ARKit+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ARKit+Extension.swift"; sourceTree = ""; };
26 | 64EC6A4E235F3E0C00CB6B59 /* Body Detection.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Body Detection.app"; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 64EC6A51235F3E0C00CB6B59 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
28 | 64EC6A53235F3E0C00CB6B59 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
29 | 64EC6A58235F3E0C00CB6B59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
30 | 64EC6A5A235F3E0E00CB6B59 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
31 | 64EC6A5D235F3E0E00CB6B59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
32 | 64EC6A5F235F3E0E00CB6B59 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
33 | /* End PBXFileReference section */
34 |
35 | /* Begin PBXFrameworksBuildPhase section */
36 | 64EC6A4B235F3E0C00CB6B59 /* Frameworks */ = {
37 | isa = PBXFrameworksBuildPhase;
38 | buildActionMask = 2147483647;
39 | files = (
40 | );
41 | runOnlyForDeploymentPostprocessing = 0;
42 | };
43 | /* End PBXFrameworksBuildPhase section */
44 |
45 | /* Begin PBXGroup section */
46 | 6418F773235F4A7200CE2EAE /* Extensions */ = {
47 | isa = PBXGroup;
48 | children = (
49 | 6418F774235F4A8400CE2EAE /* UIKit+Extension.swift */,
50 | 64C8C755235FE68A0099949C /* ARKit+Extension.swift */,
51 | 64853754236786B700C0FCAA /* CGPoint+Extension.swift */,
52 | 648537562367CDB500C0FCAA /* CGFloat+Extension.swift */,
53 | );
54 | path = Extensions;
55 | sourceTree = "";
56 | };
57 | 64C8C752235FE4790099949C /* Model */ = {
58 | isa = PBXGroup;
59 | children = (
60 | );
61 | path = Model;
62 | sourceTree = "";
63 | };
64 | 64C8C753235FE4880099949C /* View */ = {
65 | isa = PBXGroup;
66 | children = (
67 | 64EC6A5A235F3E0E00CB6B59 /* Assets.xcassets */,
68 | 64EC6A57235F3E0C00CB6B59 /* Main.storyboard */,
69 | 64EC6A5C235F3E0E00CB6B59 /* LaunchScreen.storyboard */,
70 | );
71 | path = View;
72 | sourceTree = "";
73 | };
74 | 64C8C754235FE48E0099949C /* Controller */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 64EC6A53235F3E0C00CB6B59 /* ViewController.swift */,
78 | );
79 | path = Controller;
80 | sourceTree = "";
81 | };
82 | 64EC6A45235F3E0C00CB6B59 = {
83 | isa = PBXGroup;
84 | children = (
85 | 64EC6A50235F3E0C00CB6B59 /* bodyDetection */,
86 | 64EC6A4F235F3E0C00CB6B59 /* Products */,
87 | );
88 | sourceTree = "";
89 | };
90 | 64EC6A4F235F3E0C00CB6B59 /* Products */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 64EC6A4E235F3E0C00CB6B59 /* Body Detection.app */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 64EC6A50235F3E0C00CB6B59 /* bodyDetection */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 64C8C752235FE4790099949C /* Model */,
102 | 64C8C753235FE4880099949C /* View */,
103 | 64C8C754235FE48E0099949C /* Controller */,
104 | 6418F773235F4A7200CE2EAE /* Extensions */,
105 | 64EC6A51235F3E0C00CB6B59 /* AppDelegate.swift */,
106 | 64EC6A5F235F3E0E00CB6B59 /* Info.plist */,
107 | );
108 | path = bodyDetection;
109 | sourceTree = "";
110 | };
111 | /* End PBXGroup section */
112 |
113 | /* Begin PBXNativeTarget section */
114 | 64EC6A4D235F3E0C00CB6B59 /* bodyDetection */ = {
115 | isa = PBXNativeTarget;
116 | buildConfigurationList = 64EC6A62235F3E0E00CB6B59 /* Build configuration list for PBXNativeTarget "bodyDetection" */;
117 | buildPhases = (
118 | 64EC6A4A235F3E0C00CB6B59 /* Sources */,
119 | 64EC6A4B235F3E0C00CB6B59 /* Frameworks */,
120 | 64EC6A4C235F3E0C00CB6B59 /* Resources */,
121 | );
122 | buildRules = (
123 | );
124 | dependencies = (
125 | );
126 | name = bodyDetection;
127 | productName = bodyDetection;
128 | productReference = 64EC6A4E235F3E0C00CB6B59 /* Body Detection.app */;
129 | productType = "com.apple.product-type.application";
130 | };
131 | /* End PBXNativeTarget section */
132 |
133 | /* Begin PBXProject section */
134 | 64EC6A46235F3E0C00CB6B59 /* Project object */ = {
135 | isa = PBXProject;
136 | attributes = {
137 | LastSwiftUpdateCheck = 1110;
138 | LastUpgradeCheck = 1110;
139 | ORGANIZATIONNAME = "Andressa Valengo";
140 | TargetAttributes = {
141 | 64EC6A4D235F3E0C00CB6B59 = {
142 | CreatedOnToolsVersion = 11.1;
143 | };
144 | };
145 | };
146 | buildConfigurationList = 64EC6A49235F3E0C00CB6B59 /* Build configuration list for PBXProject "bodyDetection" */;
147 | compatibilityVersion = "Xcode 9.3";
148 | developmentRegion = en;
149 | hasScannedForEncodings = 0;
150 | knownRegions = (
151 | en,
152 | Base,
153 | );
154 | mainGroup = 64EC6A45235F3E0C00CB6B59;
155 | productRefGroup = 64EC6A4F235F3E0C00CB6B59 /* Products */;
156 | projectDirPath = "";
157 | projectRoot = "";
158 | targets = (
159 | 64EC6A4D235F3E0C00CB6B59 /* bodyDetection */,
160 | );
161 | };
162 | /* End PBXProject section */
163 |
164 | /* Begin PBXResourcesBuildPhase section */
165 | 64EC6A4C235F3E0C00CB6B59 /* Resources */ = {
166 | isa = PBXResourcesBuildPhase;
167 | buildActionMask = 2147483647;
168 | files = (
169 | 64EC6A5E235F3E0E00CB6B59 /* LaunchScreen.storyboard in Resources */,
170 | 64EC6A5B235F3E0E00CB6B59 /* Assets.xcassets in Resources */,
171 | 64EC6A59235F3E0C00CB6B59 /* Main.storyboard in Resources */,
172 | );
173 | runOnlyForDeploymentPostprocessing = 0;
174 | };
175 | /* End PBXResourcesBuildPhase section */
176 |
177 | /* Begin PBXSourcesBuildPhase section */
178 | 64EC6A4A235F3E0C00CB6B59 /* Sources */ = {
179 | isa = PBXSourcesBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | 64C8C756235FE68A0099949C /* ARKit+Extension.swift in Sources */,
183 | 64EC6A54235F3E0C00CB6B59 /* ViewController.swift in Sources */,
184 | 648537572367CDB500C0FCAA /* CGFloat+Extension.swift in Sources */,
185 | 6418F775235F4A8400CE2EAE /* UIKit+Extension.swift in Sources */,
186 | 64853755236786B700C0FCAA /* CGPoint+Extension.swift in Sources */,
187 | 64EC6A52235F3E0C00CB6B59 /* AppDelegate.swift in Sources */,
188 | );
189 | runOnlyForDeploymentPostprocessing = 0;
190 | };
191 | /* End PBXSourcesBuildPhase section */
192 |
193 | /* Begin PBXVariantGroup section */
194 | 64EC6A57235F3E0C00CB6B59 /* Main.storyboard */ = {
195 | isa = PBXVariantGroup;
196 | children = (
197 | 64EC6A58235F3E0C00CB6B59 /* Base */,
198 | );
199 | name = Main.storyboard;
200 | sourceTree = "";
201 | };
202 | 64EC6A5C235F3E0E00CB6B59 /* LaunchScreen.storyboard */ = {
203 | isa = PBXVariantGroup;
204 | children = (
205 | 64EC6A5D235F3E0E00CB6B59 /* Base */,
206 | );
207 | name = LaunchScreen.storyboard;
208 | sourceTree = "";
209 | };
210 | /* End PBXVariantGroup section */
211 |
212 | /* Begin XCBuildConfiguration section */
213 | 64EC6A60235F3E0E00CB6B59 /* Debug */ = {
214 | isa = XCBuildConfiguration;
215 | buildSettings = {
216 | ALWAYS_SEARCH_USER_PATHS = NO;
217 | CLANG_ANALYZER_NONNULL = YES;
218 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
219 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
220 | CLANG_CXX_LIBRARY = "libc++";
221 | CLANG_ENABLE_MODULES = YES;
222 | CLANG_ENABLE_OBJC_ARC = YES;
223 | CLANG_ENABLE_OBJC_WEAK = YES;
224 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
225 | CLANG_WARN_BOOL_CONVERSION = YES;
226 | CLANG_WARN_COMMA = YES;
227 | CLANG_WARN_CONSTANT_CONVERSION = YES;
228 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
229 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
230 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
231 | CLANG_WARN_EMPTY_BODY = YES;
232 | CLANG_WARN_ENUM_CONVERSION = YES;
233 | CLANG_WARN_INFINITE_RECURSION = YES;
234 | CLANG_WARN_INT_CONVERSION = YES;
235 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
236 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
237 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
238 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
239 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
240 | CLANG_WARN_STRICT_PROTOTYPES = YES;
241 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
242 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
243 | CLANG_WARN_UNREACHABLE_CODE = YES;
244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
245 | COPY_PHASE_STRIP = NO;
246 | DEBUG_INFORMATION_FORMAT = dwarf;
247 | ENABLE_STRICT_OBJC_MSGSEND = YES;
248 | ENABLE_TESTABILITY = YES;
249 | GCC_C_LANGUAGE_STANDARD = gnu11;
250 | GCC_DYNAMIC_NO_PIC = NO;
251 | GCC_NO_COMMON_BLOCKS = YES;
252 | GCC_OPTIMIZATION_LEVEL = 0;
253 | GCC_PREPROCESSOR_DEFINITIONS = (
254 | "DEBUG=1",
255 | "$(inherited)",
256 | );
257 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
258 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
259 | GCC_WARN_UNDECLARED_SELECTOR = YES;
260 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
261 | GCC_WARN_UNUSED_FUNCTION = YES;
262 | GCC_WARN_UNUSED_VARIABLE = YES;
263 | IPHONEOS_DEPLOYMENT_TARGET = 13.1;
264 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
265 | MTL_FAST_MATH = YES;
266 | ONLY_ACTIVE_ARCH = YES;
267 | SDKROOT = iphoneos;
268 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
269 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
270 | };
271 | name = Debug;
272 | };
273 | 64EC6A61235F3E0E00CB6B59 /* Release */ = {
274 | isa = XCBuildConfiguration;
275 | buildSettings = {
276 | ALWAYS_SEARCH_USER_PATHS = NO;
277 | CLANG_ANALYZER_NONNULL = YES;
278 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
280 | CLANG_CXX_LIBRARY = "libc++";
281 | CLANG_ENABLE_MODULES = YES;
282 | CLANG_ENABLE_OBJC_ARC = YES;
283 | CLANG_ENABLE_OBJC_WEAK = YES;
284 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
285 | CLANG_WARN_BOOL_CONVERSION = YES;
286 | CLANG_WARN_COMMA = YES;
287 | CLANG_WARN_CONSTANT_CONVERSION = YES;
288 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
289 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
290 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
291 | CLANG_WARN_EMPTY_BODY = YES;
292 | CLANG_WARN_ENUM_CONVERSION = YES;
293 | CLANG_WARN_INFINITE_RECURSION = YES;
294 | CLANG_WARN_INT_CONVERSION = YES;
295 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
296 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
297 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
298 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
299 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
300 | CLANG_WARN_STRICT_PROTOTYPES = YES;
301 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
302 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
303 | CLANG_WARN_UNREACHABLE_CODE = YES;
304 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
305 | COPY_PHASE_STRIP = NO;
306 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
307 | ENABLE_NS_ASSERTIONS = NO;
308 | ENABLE_STRICT_OBJC_MSGSEND = YES;
309 | GCC_C_LANGUAGE_STANDARD = gnu11;
310 | GCC_NO_COMMON_BLOCKS = YES;
311 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
312 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
313 | GCC_WARN_UNDECLARED_SELECTOR = YES;
314 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
315 | GCC_WARN_UNUSED_FUNCTION = YES;
316 | GCC_WARN_UNUSED_VARIABLE = YES;
317 | IPHONEOS_DEPLOYMENT_TARGET = 13.1;
318 | MTL_ENABLE_DEBUG_INFO = NO;
319 | MTL_FAST_MATH = YES;
320 | SDKROOT = iphoneos;
321 | SWIFT_COMPILATION_MODE = wholemodule;
322 | SWIFT_OPTIMIZATION_LEVEL = "-O";
323 | VALIDATE_PRODUCT = YES;
324 | };
325 | name = Release;
326 | };
327 | 64EC6A63235F3E0E00CB6B59 /* Debug */ = {
328 | isa = XCBuildConfiguration;
329 | buildSettings = {
330 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
331 | CODE_SIGN_STYLE = Automatic;
332 | DEVELOPMENT_TEAM = UDGF2JUP82;
333 | INFOPLIST_FILE = bodyDetection/Info.plist;
334 | LD_RUNPATH_SEARCH_PATHS = (
335 | "$(inherited)",
336 | "@executable_path/Frameworks",
337 | );
338 | PRODUCT_BUNDLE_IDENTIFIER = andydeva.bodyDetection;
339 | PRODUCT_NAME = "Body Detection";
340 | SWIFT_VERSION = 5.0;
341 | TARGETED_DEVICE_FAMILY = "1,2";
342 | };
343 | name = Debug;
344 | };
345 | 64EC6A64235F3E0E00CB6B59 /* Release */ = {
346 | isa = XCBuildConfiguration;
347 | buildSettings = {
348 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
349 | CODE_SIGN_STYLE = Automatic;
350 | DEVELOPMENT_TEAM = UDGF2JUP82;
351 | INFOPLIST_FILE = bodyDetection/Info.plist;
352 | LD_RUNPATH_SEARCH_PATHS = (
353 | "$(inherited)",
354 | "@executable_path/Frameworks",
355 | );
356 | PRODUCT_BUNDLE_IDENTIFIER = andydeva.bodyDetection;
357 | PRODUCT_NAME = "Body Detection";
358 | SWIFT_VERSION = 5.0;
359 | TARGETED_DEVICE_FAMILY = "1,2";
360 | };
361 | name = Release;
362 | };
363 | /* End XCBuildConfiguration section */
364 |
365 | /* Begin XCConfigurationList section */
366 | 64EC6A49235F3E0C00CB6B59 /* Build configuration list for PBXProject "bodyDetection" */ = {
367 | isa = XCConfigurationList;
368 | buildConfigurations = (
369 | 64EC6A60235F3E0E00CB6B59 /* Debug */,
370 | 64EC6A61235F3E0E00CB6B59 /* Release */,
371 | );
372 | defaultConfigurationIsVisible = 0;
373 | defaultConfigurationName = Release;
374 | };
375 | 64EC6A62235F3E0E00CB6B59 /* Build configuration list for PBXNativeTarget "bodyDetection" */ = {
376 | isa = XCConfigurationList;
377 | buildConfigurations = (
378 | 64EC6A63235F3E0E00CB6B59 /* Debug */,
379 | 64EC6A64235F3E0E00CB6B59 /* Release */,
380 | );
381 | defaultConfigurationIsVisible = 0;
382 | defaultConfigurationName = Release;
383 | };
384 | /* End XCConfigurationList section */
385 | };
386 | rootObject = 64EC6A46235F3E0C00CB6B59 /* Project object */;
387 | }
388 |
--------------------------------------------------------------------------------