├── .gitignore ├── Convert ├── age.py ├── ages.txt ├── download.sh ├── emotion.py ├── emotions.txt ├── gender.py └── genders.txt ├── Faces.xcodeproj └── project.pbxproj ├── Faces.xcworkspace └── contents.xcworkspacedata ├── Faces ├── AppDelegate.swift ├── ClassificationService.swift ├── Resources │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-40.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-72.png │ │ │ ├── Icon-72@2x.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ ├── Icon-Small-50.png │ │ │ ├── Icon-Small-50@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ ├── Icon.png │ │ │ ├── Icon@2x.png │ │ │ ├── NotificationIcon@2x.png │ │ │ ├── NotificationIcon@3x.png │ │ │ ├── NotificationIcon~ipad.png │ │ │ └── NotificationIcon~ipad@2x.png │ │ └── Contents.json │ ├── Info.plist │ └── LaunchScreen.storyboard └── ViewController.swift ├── LICENSE ├── Podfile ├── Podfile.lock ├── README.md └── Screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | Icon 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | .idea/ 29 | *.xcworkspace/xcshareddata/*.xcscmblueprint 30 | 31 | # CocoaPods 32 | Pods 33 | 34 | # Carthage 35 | Carthage 36 | 37 | # SPM 38 | .build/ 39 | 40 | ## CoreML models 41 | *.mlmodel 42 | -------------------------------------------------------------------------------- /Convert/age.py: -------------------------------------------------------------------------------- 1 | import coremltools 2 | 3 | folder = 'cnn_age_gender_models_and_data.0.0.2' 4 | 5 | coreml_model = coremltools.converters.caffe.convert( 6 | (folder + '/age_net.caffemodel', folder + '/deploy_age.prototxt'), 7 | image_input_names = 'data', 8 | class_labels = 'ages.txt' 9 | ) 10 | coreml_model.author = 'Gil Levi and Tal Hassner' 11 | coreml_model.license = 'Unknown' 12 | coreml_model.short_description = 'Age Classification using Convolutional Neural Networks' 13 | coreml_model.input_description['data'] = 'An image with a face.' 14 | coreml_model.output_description['prob'] = 'The probabilities for each age, for the given input.' 15 | coreml_model.output_description['classLabel'] = 'The most likely age, for the given input.' 16 | coreml_model.save('AgeNet.mlmodel') 17 | -------------------------------------------------------------------------------- /Convert/ages.txt: -------------------------------------------------------------------------------- 1 | 0-2 2 | 4-6 3 | 8-12 4 | 15-20 5 | 25-32 6 | 38-43 7 | 48-53 8 | 60-100 -------------------------------------------------------------------------------- /Convert/download.sh: -------------------------------------------------------------------------------- 1 | # Age and gender models 2 | wget http://www.openu.ac.il/home/hassner/projects/cnn_agegender/cnn_age_gender_models_and_data.0.0.2.zip 3 | unzip -a cnn_age_gender_models_and_data.0.0.2.zip 4 | 5 | # Emotions model 6 | # Download Caffe model: https://drive.google.com/open?id=0BydFau0VP3XSNVYtWnNPMU1TOGM 7 | # Download deploy.prototxt 8 | # Move the files to Covert/EmotionClassification 9 | -------------------------------------------------------------------------------- /Convert/emotion.py: -------------------------------------------------------------------------------- 1 | import coremltools 2 | 3 | folder = 'EmotionClassification' 4 | 5 | coreml_model = coremltools.converters.caffe.convert( 6 | (folder + '/EmotiW_VGG_S.caffemodel', folder + '/deploy.prototxt'), 7 | image_input_names = 'data', 8 | class_labels = 'emotions.txt' 9 | ) 10 | coreml_model.author = 'Gil Levi and Tal Hassner' 11 | coreml_model.license = 'Unknown' 12 | coreml_model.short_description = 'Emotion Recognition in the Wild via Convolutional Neural Networks and Mapped Binary Patterns' 13 | coreml_model.input_description['data'] = 'An image with a face.' 14 | coreml_model.output_description['prob'] = 'The probabilities for each emotion, for the given input.' 15 | coreml_model.output_description['classLabel'] = 'The most likely type of emotion, for the given input.' 16 | coreml_model.save('CNNEmotions.mlmodel') 17 | -------------------------------------------------------------------------------- /Convert/emotions.txt: -------------------------------------------------------------------------------- 1 | Angry 2 | Disgust 3 | Fear 4 | Happy 5 | Neutral 6 | Sad 7 | Surprise -------------------------------------------------------------------------------- /Convert/gender.py: -------------------------------------------------------------------------------- 1 | import coremltools 2 | 3 | folder = 'cnn_age_gender_models_and_data.0.0.2' 4 | 5 | coreml_model = coremltools.converters.caffe.convert( 6 | (folder + '/gender_net.caffemodel', folder + '/deploy_gender.prototxt'), 7 | image_input_names = 'data', 8 | class_labels = 'genders.txt' 9 | ) 10 | coreml_model.author = 'Gil Levi and Tal Hassner' 11 | coreml_model.license = 'Unknown' 12 | coreml_model.short_description = 'Gender Classification using Convolutional Neural Networks' 13 | coreml_model.input_description['data'] = 'An image with a face.' 14 | coreml_model.output_description['prob'] = 'The probabilities for each gender, for the given input.' 15 | coreml_model.output_description['classLabel'] = 'The most likely gender, for the given input.' 16 | coreml_model.save('GenderNet.mlmodel') 17 | -------------------------------------------------------------------------------- /Convert/genders.txt: -------------------------------------------------------------------------------- 1 | Male 2 | Female -------------------------------------------------------------------------------- /Faces.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D3D02D1E27F921CA4F2560A7 /* Pods_Faces.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E17C981B6486AA47385EAC2D /* Pods_Faces.framework */; }; 11 | D50B13FE1EFC980E0049A04B /* GenderNet.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = D50B13FD1EFC97F20049A04B /* GenderNet.mlmodel */; }; 12 | D50B14001EFC981B0049A04B /* AgeNet.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = D50B13FF1EFC98190049A04B /* AgeNet.mlmodel */; }; 13 | D50B14041EFC98690049A04B /* CNNEmotions.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = D50B14031EFC98640049A04B /* CNNEmotions.mlmodel */; }; 14 | D517500A1EFB327C000D98EB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51750091EFB327C000D98EB /* AppDelegate.swift */; }; 15 | D517500C1EFB327C000D98EB /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D517500B1EFB327C000D98EB /* ViewController.swift */; }; 16 | D51750111EFB327C000D98EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D51750101EFB327C000D98EB /* Assets.xcassets */; }; 17 | D5D4DFC71EFB3A84005EBAA6 /* ClassificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D4DFC61EFB3A84005EBAA6 /* ClassificationService.swift */; }; 18 | D5D4DFCC1EFB4014005EBAA6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5D4DFC81EFB3F42005EBAA6 /* LaunchScreen.storyboard */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXCopyFilesBuildPhase section */ 22 | D5D4DFE21EFB5088005EBAA6 /* Embed Frameworks */ = { 23 | isa = PBXCopyFilesBuildPhase; 24 | buildActionMask = 2147483647; 25 | dstPath = ""; 26 | dstSubfolderSpec = 10; 27 | files = ( 28 | ); 29 | name = "Embed Frameworks"; 30 | runOnlyForDeploymentPostprocessing = 0; 31 | }; 32 | /* End PBXCopyFilesBuildPhase section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 56B4141162F0B3857C785841 /* Pods-Faces.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Faces.release.xcconfig"; path = "Pods/Target Support Files/Pods-Faces/Pods-Faces.release.xcconfig"; sourceTree = ""; }; 36 | 933C9CB45BEDBEF9A0B10DB8 /* Pods-Faces.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Faces.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Faces/Pods-Faces.debug.xcconfig"; sourceTree = ""; }; 37 | D50B13FD1EFC97F20049A04B /* GenderNet.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = GenderNet.mlmodel; sourceTree = ""; }; 38 | D50B13FF1EFC98190049A04B /* AgeNet.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = AgeNet.mlmodel; sourceTree = ""; }; 39 | D50B14031EFC98640049A04B /* CNNEmotions.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = CNNEmotions.mlmodel; sourceTree = ""; }; 40 | D51750061EFB327C000D98EB /* Faces.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Faces.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | D51750091EFB327C000D98EB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 42 | D517500B1EFB327C000D98EB /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 43 | D51750101EFB327C000D98EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 44 | D51750151EFB327C000D98EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | D5D4DFC61EFB3A84005EBAA6 /* ClassificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassificationService.swift; sourceTree = ""; }; 46 | D5D4DFC81EFB3F42005EBAA6 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 47 | E17C981B6486AA47385EAC2D /* Pods_Faces.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Faces.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | D51750031EFB327C000D98EB /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | D3D02D1E27F921CA4F2560A7 /* Pods_Faces.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 70750F74172FF47CA8368154 /* Frameworks */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | E17C981B6486AA47385EAC2D /* Pods_Faces.framework */, 66 | ); 67 | name = Frameworks; 68 | sourceTree = ""; 69 | }; 70 | C80B9AD8D82800BF8C30CFD8 /* Pods */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 933C9CB45BEDBEF9A0B10DB8 /* Pods-Faces.debug.xcconfig */, 74 | 56B4141162F0B3857C785841 /* Pods-Faces.release.xcconfig */, 75 | ); 76 | name = Pods; 77 | sourceTree = ""; 78 | }; 79 | D5174FFD1EFB327C000D98EB = { 80 | isa = PBXGroup; 81 | children = ( 82 | D51750081EFB327C000D98EB /* Faces */, 83 | D51750071EFB327C000D98EB /* Products */, 84 | C80B9AD8D82800BF8C30CFD8 /* Pods */, 85 | 70750F74172FF47CA8368154 /* Frameworks */, 86 | ); 87 | sourceTree = ""; 88 | }; 89 | D51750071EFB327C000D98EB /* Products */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | D51750061EFB327C000D98EB /* Faces.app */, 93 | ); 94 | name = Products; 95 | sourceTree = ""; 96 | }; 97 | D51750081EFB327C000D98EB /* Faces */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | D517501B1EFB3282000D98EB /* Resources */, 101 | D51750091EFB327C000D98EB /* AppDelegate.swift */, 102 | D517500B1EFB327C000D98EB /* ViewController.swift */, 103 | D5D4DFC61EFB3A84005EBAA6 /* ClassificationService.swift */, 104 | ); 105 | path = Faces; 106 | sourceTree = ""; 107 | }; 108 | D517501B1EFB3282000D98EB /* Resources */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | D50B14031EFC98640049A04B /* CNNEmotions.mlmodel */, 112 | D50B13FF1EFC98190049A04B /* AgeNet.mlmodel */, 113 | D50B13FD1EFC97F20049A04B /* GenderNet.mlmodel */, 114 | D5D4DFC81EFB3F42005EBAA6 /* LaunchScreen.storyboard */, 115 | D51750101EFB327C000D98EB /* Assets.xcassets */, 116 | D51750151EFB327C000D98EB /* Info.plist */, 117 | ); 118 | path = Resources; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | D51750051EFB327C000D98EB /* Faces */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = D51750181EFB327C000D98EB /* Build configuration list for PBXNativeTarget "Faces" */; 127 | buildPhases = ( 128 | D2AF09707BCC5F84B98418D8 /* [CP] Check Pods Manifest.lock */, 129 | D51750021EFB327C000D98EB /* Sources */, 130 | D51750031EFB327C000D98EB /* Frameworks */, 131 | D51750041EFB327C000D98EB /* Resources */, 132 | D5D4DFE21EFB5088005EBAA6 /* Embed Frameworks */, 133 | 49C9436B64704B4C0F685514 /* [CP] Embed Pods Frameworks */, 134 | D7E2571462ED3BEE7A4FF4F8 /* [CP] Copy Pods Resources */, 135 | ); 136 | buildRules = ( 137 | ); 138 | dependencies = ( 139 | ); 140 | name = Faces; 141 | productName = Faces; 142 | productReference = D51750061EFB327C000D98EB /* Faces.app */; 143 | productType = "com.apple.product-type.application"; 144 | }; 145 | /* End PBXNativeTarget section */ 146 | 147 | /* Begin PBXProject section */ 148 | D5174FFE1EFB327C000D98EB /* Project object */ = { 149 | isa = PBXProject; 150 | attributes = { 151 | LastSwiftUpdateCheck = 0900; 152 | LastUpgradeCheck = 0900; 153 | ORGANIZATIONNAME = "Vadym Markov"; 154 | TargetAttributes = { 155 | D51750051EFB327C000D98EB = { 156 | CreatedOnToolsVersion = 9.0; 157 | ProvisioningStyle = Manual; 158 | }; 159 | }; 160 | }; 161 | buildConfigurationList = D51750011EFB327C000D98EB /* Build configuration list for PBXProject "Faces" */; 162 | compatibilityVersion = "Xcode 8.0"; 163 | developmentRegion = en; 164 | hasScannedForEncodings = 0; 165 | knownRegions = ( 166 | en, 167 | Base, 168 | ); 169 | mainGroup = D5174FFD1EFB327C000D98EB; 170 | productRefGroup = D51750071EFB327C000D98EB /* Products */; 171 | projectDirPath = ""; 172 | projectRoot = ""; 173 | targets = ( 174 | D51750051EFB327C000D98EB /* Faces */, 175 | ); 176 | }; 177 | /* End PBXProject section */ 178 | 179 | /* Begin PBXResourcesBuildPhase section */ 180 | D51750041EFB327C000D98EB /* Resources */ = { 181 | isa = PBXResourcesBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | D51750111EFB327C000D98EB /* Assets.xcassets in Resources */, 185 | D5D4DFCC1EFB4014005EBAA6 /* LaunchScreen.storyboard in Resources */, 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | /* End PBXResourcesBuildPhase section */ 190 | 191 | /* Begin PBXShellScriptBuildPhase section */ 192 | 49C9436B64704B4C0F685514 /* [CP] Embed Pods Frameworks */ = { 193 | isa = PBXShellScriptBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | ); 197 | inputPaths = ( 198 | "${SRCROOT}/Pods/Target Support Files/Pods-Faces/Pods-Faces-frameworks.sh", 199 | "${BUILT_PRODUCTS_DIR}/VisionLab/VisionLab.framework", 200 | ); 201 | name = "[CP] Embed Pods Frameworks"; 202 | outputPaths = ( 203 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/VisionLab.framework", 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | shellPath = /bin/sh; 207 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Faces/Pods-Faces-frameworks.sh\"\n"; 208 | showEnvVarsInLog = 0; 209 | }; 210 | D2AF09707BCC5F84B98418D8 /* [CP] Check Pods Manifest.lock */ = { 211 | isa = PBXShellScriptBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | ); 215 | inputPaths = ( 216 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 217 | "${PODS_ROOT}/Manifest.lock", 218 | ); 219 | name = "[CP] Check Pods Manifest.lock"; 220 | outputPaths = ( 221 | "$(DERIVED_FILE_DIR)/Pods-Faces-checkManifestLockResult.txt", 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | shellPath = /bin/sh; 225 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 226 | showEnvVarsInLog = 0; 227 | }; 228 | D7E2571462ED3BEE7A4FF4F8 /* [CP] Copy Pods Resources */ = { 229 | isa = PBXShellScriptBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | ); 233 | inputPaths = ( 234 | ); 235 | name = "[CP] Copy Pods Resources"; 236 | outputPaths = ( 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | shellPath = /bin/sh; 240 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Faces/Pods-Faces-resources.sh\"\n"; 241 | showEnvVarsInLog = 0; 242 | }; 243 | /* End PBXShellScriptBuildPhase section */ 244 | 245 | /* Begin PBXSourcesBuildPhase section */ 246 | D51750021EFB327C000D98EB /* Sources */ = { 247 | isa = PBXSourcesBuildPhase; 248 | buildActionMask = 2147483647; 249 | files = ( 250 | D50B14041EFC98690049A04B /* CNNEmotions.mlmodel in Sources */, 251 | D5D4DFC71EFB3A84005EBAA6 /* ClassificationService.swift in Sources */, 252 | D50B14001EFC981B0049A04B /* AgeNet.mlmodel in Sources */, 253 | D50B13FE1EFC980E0049A04B /* GenderNet.mlmodel in Sources */, 254 | D517500C1EFB327C000D98EB /* ViewController.swift in Sources */, 255 | D517500A1EFB327C000D98EB /* AppDelegate.swift in Sources */, 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | }; 259 | /* End PBXSourcesBuildPhase section */ 260 | 261 | /* Begin XCBuildConfiguration section */ 262 | D51750161EFB327C000D98EB /* Debug */ = { 263 | isa = XCBuildConfiguration; 264 | buildSettings = { 265 | ALWAYS_SEARCH_USER_PATHS = NO; 266 | CLANG_ANALYZER_NONNULL = YES; 267 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 269 | CLANG_CXX_LIBRARY = "libc++"; 270 | CLANG_ENABLE_MODULES = YES; 271 | CLANG_ENABLE_OBJC_ARC = YES; 272 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 273 | CLANG_WARN_BOOL_CONVERSION = YES; 274 | CLANG_WARN_COMMA = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INFINITE_RECURSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 286 | CLANG_WARN_STRICT_PROTOTYPES = YES; 287 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 288 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | CODE_SIGN_IDENTITY = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = dwarf; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | ENABLE_TESTABILITY = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu11; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_NO_COMMON_BLOCKS = YES; 299 | GCC_OPTIMIZATION_LEVEL = 0; 300 | GCC_PREPROCESSOR_DEFINITIONS = ( 301 | "DEBUG=1", 302 | "$(inherited)", 303 | ); 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 311 | MTL_ENABLE_DEBUG_INFO = YES; 312 | ONLY_ACTIVE_ARCH = YES; 313 | SDKROOT = iphoneos; 314 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 315 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 316 | }; 317 | name = Debug; 318 | }; 319 | D51750171EFB327C000D98EB /* Release */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_ANALYZER_NONNULL = YES; 324 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 326 | CLANG_CXX_LIBRARY = "libc++"; 327 | CLANG_ENABLE_MODULES = YES; 328 | CLANG_ENABLE_OBJC_ARC = YES; 329 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 330 | CLANG_WARN_BOOL_CONVERSION = YES; 331 | CLANG_WARN_COMMA = YES; 332 | CLANG_WARN_CONSTANT_CONVERSION = YES; 333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 334 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 335 | CLANG_WARN_EMPTY_BODY = YES; 336 | CLANG_WARN_ENUM_CONVERSION = YES; 337 | CLANG_WARN_INFINITE_RECURSION = YES; 338 | CLANG_WARN_INT_CONVERSION = YES; 339 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 340 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 341 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 342 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 343 | CLANG_WARN_STRICT_PROTOTYPES = YES; 344 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 345 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 346 | CLANG_WARN_UNREACHABLE_CODE = YES; 347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 348 | CODE_SIGN_IDENTITY = "iPhone Developer"; 349 | COPY_PHASE_STRIP = NO; 350 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 351 | ENABLE_NS_ASSERTIONS = NO; 352 | ENABLE_STRICT_OBJC_MSGSEND = YES; 353 | GCC_C_LANGUAGE_STANDARD = gnu11; 354 | GCC_NO_COMMON_BLOCKS = YES; 355 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 356 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 357 | GCC_WARN_UNDECLARED_SELECTOR = YES; 358 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 359 | GCC_WARN_UNUSED_FUNCTION = YES; 360 | GCC_WARN_UNUSED_VARIABLE = YES; 361 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 362 | MTL_ENABLE_DEBUG_INFO = NO; 363 | SDKROOT = iphoneos; 364 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 365 | VALIDATE_PRODUCT = YES; 366 | }; 367 | name = Release; 368 | }; 369 | D51750191EFB327C000D98EB /* Debug */ = { 370 | isa = XCBuildConfiguration; 371 | baseConfigurationReference = 933C9CB45BEDBEF9A0B10DB8 /* Pods-Faces.debug.xcconfig */; 372 | buildSettings = { 373 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 375 | CODE_SIGN_STYLE = Manual; 376 | COREML_CODEGEN_LANGUAGE = Swift; 377 | DEVELOPMENT_TEAM = ""; 378 | INFOPLIST_FILE = Faces/Resources/Info.plist; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 380 | PRODUCT_BUNDLE_IDENTIFIER = codes.cocoaml.Faces; 381 | PRODUCT_NAME = "$(TARGET_NAME)"; 382 | PROVISIONING_PROFILE = ""; 383 | PROVISIONING_PROFILE_SPECIFIER = ""; 384 | SWIFT_VERSION = 4.0; 385 | TARGETED_DEVICE_FAMILY = "1,2"; 386 | }; 387 | name = Debug; 388 | }; 389 | D517501A1EFB327C000D98EB /* Release */ = { 390 | isa = XCBuildConfiguration; 391 | baseConfigurationReference = 56B4141162F0B3857C785841 /* Pods-Faces.release.xcconfig */; 392 | buildSettings = { 393 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 395 | CODE_SIGN_STYLE = Manual; 396 | COREML_CODEGEN_LANGUAGE = Swift; 397 | DEVELOPMENT_TEAM = ""; 398 | INFOPLIST_FILE = Faces/Resources/Info.plist; 399 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 400 | PRODUCT_BUNDLE_IDENTIFIER = codes.cocoaml.Faces; 401 | PRODUCT_NAME = "$(TARGET_NAME)"; 402 | PROVISIONING_PROFILE = ""; 403 | PROVISIONING_PROFILE_SPECIFIER = ""; 404 | SWIFT_VERSION = 4.0; 405 | TARGETED_DEVICE_FAMILY = "1,2"; 406 | }; 407 | name = Release; 408 | }; 409 | /* End XCBuildConfiguration section */ 410 | 411 | /* Begin XCConfigurationList section */ 412 | D51750011EFB327C000D98EB /* Build configuration list for PBXProject "Faces" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | D51750161EFB327C000D98EB /* Debug */, 416 | D51750171EFB327C000D98EB /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | defaultConfigurationName = Release; 420 | }; 421 | D51750181EFB327C000D98EB /* Build configuration list for PBXNativeTarget "Faces" */ = { 422 | isa = XCConfigurationList; 423 | buildConfigurations = ( 424 | D51750191EFB327C000D98EB /* Debug */, 425 | D517501A1EFB327C000D98EB /* Release */, 426 | ); 427 | defaultConfigurationIsVisible = 0; 428 | defaultConfigurationName = Release; 429 | }; 430 | /* End XCConfigurationList section */ 431 | }; 432 | rootObject = D5174FFE1EFB327C000D98EB /* Project object */; 433 | } 434 | -------------------------------------------------------------------------------- /Faces.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Faces/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | final class AppDelegate: UIResponder, UIApplicationDelegate { 5 | var window: UIWindow? 6 | private lazy var controller: UIViewController = ViewController() 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 9 | window = UIWindow() 10 | window?.rootViewController = controller 11 | window?.makeKeyAndVisible() 12 | 13 | return true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Faces/ClassificationService.swift: -------------------------------------------------------------------------------- 1 | import CoreML 2 | import Vision 3 | import VisionLab 4 | 5 | /// Delegate protocol used for `ClassificationService` 6 | protocol ClassificationServiceDelegate: class { 7 | func classificationService(_ service: ClassificationService, didDetectGender gender: String) 8 | func classificationService(_ service: ClassificationService, didDetectAge age: String) 9 | func classificationService(_ service: ClassificationService, didDetectEmotion emotion: String) 10 | } 11 | 12 | /// Service used to perform gender, age and emotion classification 13 | final class ClassificationService: ClassificationServiceProtocol { 14 | /// The service's delegate 15 | weak var delegate: ClassificationServiceDelegate? 16 | /// Array of vision requests 17 | private var requests = [VNRequest]() 18 | 19 | /// Create CoreML model and classification requests 20 | func setup() { 21 | do { 22 | // Gender request 23 | requests.append(VNCoreMLRequest( 24 | model: try VNCoreMLModel(for: GenderNet().model), 25 | completionHandler: handleGenderClassification 26 | )) 27 | // Age request 28 | requests.append(VNCoreMLRequest( 29 | model: try VNCoreMLModel(for: AgeNet().model), 30 | completionHandler: handleAgeClassification 31 | )) 32 | // Emotions request 33 | requests.append(VNCoreMLRequest( 34 | model: try VNCoreMLModel(for: CNNEmotions().model), 35 | completionHandler: handleEmotionClassification 36 | )) 37 | } catch { 38 | assertionFailure("Can't load Vision ML model: \(error)") 39 | } 40 | } 41 | 42 | /// Run individual requests one by one. 43 | func classify(image: CIImage) { 44 | do { 45 | for request in self.requests { 46 | let handler = VNImageRequestHandler(ciImage: image) 47 | try handler.perform([request]) 48 | } 49 | } catch { 50 | print(error) 51 | } 52 | } 53 | 54 | // MARK: - Handling 55 | 56 | @objc private func handleGenderClassification(request: VNRequest, error: Error?) { 57 | let result = extractClassificationResult(from: request, count: 1) 58 | delegate?.classificationService(self, didDetectGender: result) 59 | } 60 | 61 | @objc private func handleAgeClassification(request: VNRequest, error: Error?) { 62 | let result = extractClassificationResult(from: request, count: 1) 63 | delegate?.classificationService(self, didDetectAge: result) 64 | } 65 | 66 | @objc private func handleEmotionClassification(request: VNRequest, error: Error?) { 67 | let result = extractClassificationResult(from: request, count: 1) 68 | delegate?.classificationService(self, didDetectEmotion: result) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "NotificationIcon@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "NotificationIcon@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-Small@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "57x57", 47 | "idiom" : "iphone", 48 | "filename" : "Icon.png", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "size" : "57x57", 53 | "idiom" : "iphone", 54 | "filename" : "Icon@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "Icon-60@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "60x60", 65 | "idiom" : "iphone", 66 | "filename" : "Icon-60@3x.png", 67 | "scale" : "3x" 68 | }, 69 | { 70 | "size" : "20x20", 71 | "idiom" : "ipad", 72 | "filename" : "NotificationIcon~ipad.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "20x20", 77 | "idiom" : "ipad", 78 | "filename" : "NotificationIcon~ipad@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "29x29", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-Small.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "29x29", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-Small@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "40x40", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-40.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "40x40", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-40@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "50x50", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-Small-50.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "50x50", 113 | "idiom" : "ipad", 114 | "filename" : "Icon-Small-50@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "72x72", 119 | "idiom" : "ipad", 120 | "filename" : "Icon-72.png", 121 | "scale" : "1x" 122 | }, 123 | { 124 | "size" : "72x72", 125 | "idiom" : "ipad", 126 | "filename" : "Icon-72@2x.png", 127 | "scale" : "2x" 128 | }, 129 | { 130 | "size" : "76x76", 131 | "idiom" : "ipad", 132 | "filename" : "Icon-76.png", 133 | "scale" : "1x" 134 | }, 135 | { 136 | "size" : "76x76", 137 | "idiom" : "ipad", 138 | "filename" : "Icon-76@2x.png", 139 | "scale" : "2x" 140 | }, 141 | { 142 | "size" : "83.5x83.5", 143 | "idiom" : "ipad", 144 | "filename" : "Icon-83.5@2x.png", 145 | "scale" : "2x" 146 | }, 147 | { 148 | "idiom" : "ios-marketing", 149 | "size" : "1024x1024", 150 | "scale" : "1x" 151 | } 152 | ], 153 | "info" : { 154 | "version" : 1, 155 | "author" : "xcode" 156 | } 157 | } -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-72.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-72@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon@3x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Faces/Resources/Assets.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png -------------------------------------------------------------------------------- /Faces/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } -------------------------------------------------------------------------------- /Faces/Resources/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 demonstrate image recognition. 25 | NSPhotoLibraryUsageDescription 26 | To demonstrate image recognition. 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Faces/Resources/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 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Faces/ViewController.swift: -------------------------------------------------------------------------------- 1 | import VisionLab 2 | 3 | final class ViewController: ImageClassificationController { 4 | override func viewDidLoad() { 5 | super.viewDidLoad() 6 | classificationService.delegate = self 7 | } 8 | } 9 | 10 | // MARK: - ClassificationServiceDelegate 11 | 12 | extension ViewController: ClassificationServiceDelegate { 13 | func classificationService(_ service: ClassificationService, didDetectGender gender: String) { 14 | append(to: mainView.label, title: "Gender", text: gender) 15 | } 16 | 17 | func classificationService(_ service: ClassificationService, didDetectAge age: String) { 18 | append(to: mainView.label, title: "Age", text: age) 19 | } 20 | 21 | func classificationService(_ service: ClassificationService, didDetectEmotion emotion: String) { 22 | append(to: mainView.label, title: "Emotions", text: emotion) 23 | } 24 | 25 | /// Set results of the classification request 26 | func append(to label: UILabel, title: String, text: String) { 27 | DispatchQueue.main.async { [weak label] in 28 | let attributedText = label?.attributedText ?? NSAttributedString(string: "") 29 | let string = NSMutableAttributedString(attributedString: attributedText) 30 | string.append(.init(string: "\(title): ", attributes: [.font: UIFont.boldSystemFont(ofSize: 18)])) 31 | string.append(.init(string: text, attributes: [.font: UIFont.systemFont(ofSize: 18)])) 32 | string.append(.init(string: "\n\n")) 33 | 34 | label?.attributedText = string 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Vadym Markov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | platform :ios, '11.0' 3 | pod 'VisionLab', git: 'https://github.com/cocoa-ai/VisionLab' 4 | target 'Faces' 5 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - VisionLab (0.2.0) 3 | 4 | DEPENDENCIES: 5 | - VisionLab (from `https://github.com/cocoa-ai/VisionLab`) 6 | 7 | EXTERNAL SOURCES: 8 | VisionLab: 9 | :git: https://github.com/cocoa-ai/VisionLab 10 | 11 | CHECKOUT OPTIONS: 12 | VisionLab: 13 | :commit: aea33bfae9755aa9f175f2783f97593775f664e5 14 | :git: https://github.com/cocoa-ai/VisionLab 15 | 16 | SPEC CHECKSUMS: 17 | VisionLab: 6fc2dcc1f731dd21891c7bd9878a93c0526bfc91 18 | 19 | PODFILE CHECKSUM: 25333acb62cf6c93332927d56cd69395b6ecc153 20 | 21 | COCOAPODS: 1.3.1 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Faces Vision Demo 2 | 3 | iOS11 demo application for age and gender classification of facial images using `Vision` and `CoreML`. 4 | 5 |
6 | FacesVisionDemo 7 |
8 | 9 | ## Model 10 | 11 | This demo is based on the age, gender and emotion neural network classifiers, 12 | which were converted from `Caffe` models to `CoreML` models using [coremltools](https://pypi.python.org/pypi/coremltools) python package. 13 | 14 | ### Age classification 15 | 16 | - [Paper](http://www.openu.ac.il/home/hassner/projects/cnn_agegender/) 17 | - [CoreML model](https://drive.google.com/file/d/1PLkI4Jyg086JlvTzwHHI5EbGWgJI-Atv/view?usp=sharing) 18 | 19 | ### Gender classification 20 | 21 | - [Paper](http://www.openu.ac.il/home/hassner/projects/cnn_agegender/) 22 | - [CoreML model](https://drive.google.com/file/d/1IxU0E1EDjuL-sbY3wd5Wh6BsXTbYTScb/view?usp=sharing) 23 | 24 | ### Emotion Recognition 25 | 26 | - [Paper](http://www.openu.ac.il/home/hassner/projects/cnn_emotions/) 27 | - [CoreML model](https://drive.google.com/file/d/1ElCJvnEvhtIxZkyEzVUAFPJAMgyBXo57/view?usp=sharing) 28 | 29 | ## Requirements 30 | 31 | - Xcode 9 32 | - iOS 11 33 | 34 | ## Installation 35 | 36 | ```sh 37 | git clone https://github.com/cocoa-ai/FacesVisionDemo.git 38 | cd FacesVisionDemo 39 | pod install 40 | open Faces.xcworkspace/ 41 | ``` 42 | 43 | ## Conversion 44 | 45 | Download [Caffe model](https://drive.google.com/open?id=0BydFau0VP3XSNVYtWnNPMU1TOGM) 46 | and [deploy.prototxt](https://drive.google.com/open?id=0BydFau0VP3XSOFp4Ri1ITzZuUkk). 47 | Links can also be found [here](https://gist.github.com/GilLevi/54aee1b8b0397721aa4b#emotion-classification-cnn---rgb). 48 | Move downloaded files to `Covert/EmotionClassification` folder. 49 | 50 | ```sh 51 | cd Convert 52 | ./download.sh 53 | python age.py 54 | python gender.py 55 | python emotion.py 56 | ``` 57 | 58 | Download the [Age](https://drive.google.com/file/d/0B1ghKa_MYL6mT1J3T1BEeWx4TWc/view?usp=sharing), 59 | [Gender](https://drive.google.com/file/d/0B1ghKa_MYL6mYkNsZHlyc2ZuaFk/view?usp=sharing) and 60 | [Emotion](https://drive.google.com/file/d/0B1ghKa_MYL6mTlYtRGdXNFlpWDQ/view?usp=sharing) 61 | CoreML models and add the files to "Resources" folder in the project's directory. 62 | 63 | Build the project and run it on a simulator or a device with iOS 11. 64 | 65 | ## Author 66 | 67 | Vadym Markov, markov.vadym@gmail.com 68 | 69 | ## Credits 70 | 71 | - [Age and Gender Classification using Convolutional Neural Networks](http://www.openu.ac.il/home/hassner/projects/cnn_agegender/) 72 | - [Emotion Recognition in the Wild via Convolutional Neural Networks and Mapped Binary Patterns](http://www.openu.ac.il/home/hassner/projects/cnn_emotions/) 73 | 74 | ## References 75 | - [Caffe Model Zoo](https://github.com/caffe2/caffe2/wiki/Model-Zoo) 76 | - [Apple Machine Learning](https://developer.apple.com/machine-learning/) 77 | - [Vision Framework](https://developer.apple.com/documentation/vision) 78 | - [CoreML Framework](https://developer.apple.com/documentation/coreml) 79 | - [coremltools](https://pypi.python.org/pypi/coremltools) 80 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cocoa-ai/FacesVisionDemo/d835a89ebe5bb18009bf81e006860f8ae329f60b/Screenshot.png --------------------------------------------------------------------------------