├── .gitignore ├── JunVisionFace ├── JunVisionFace.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── JunVisionFace │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-60.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-Small29@2x.png │ │ │ ├── Icon-Small29@3x.png │ │ │ ├── Icon-Spotlight-40.png │ │ │ ├── Icon-Spotlight-40@2x.png │ │ │ ├── Icon-Spotlight-40@3x.png │ │ │ └── icon1024.png │ │ ├── Contents.json │ │ ├── eyes.imageset │ │ │ ├── Contents.json │ │ │ ├── eyes@2x.png │ │ │ └── eyes@3x.png │ │ ├── photo189.imageset │ │ │ ├── Contents.json │ │ │ └── photo189.png │ │ └── photo193.imageset │ │ │ ├── Contents.json │ │ │ └── photo193.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── JunVisionFace.xcdatamodeld │ │ ├── .xccurrentversion │ │ └── JunVisionFace.xcdatamodel │ │ │ └── contents │ ├── ViewController.swift │ ├── VisionTool │ │ ├── BaseVIewController │ │ │ ├── DectectBaseViewController.swift │ │ │ └── ScanBaseViewController.swift │ │ └── Tools │ │ │ ├── JunViewTool.swift │ │ │ ├── JunVisionTool.swift │ │ │ └── UIExtension.swift │ ├── 动态人脸识别 │ │ └── DynamicFaceViewController.swift │ ├── 实时动态添加 │ │ └── RealAddViewController.swift │ ├── 对象检测和跟踪 │ │ └── TrackViewController.swift │ ├── 文字识别 │ │ └── TextViewController.swift │ ├── 条码识别 │ │ ├── CodeModel.swift │ │ └── CodeViewController.swift │ ├── 特征识别 │ │ ├── FaceFeatureModel.swift │ │ ├── FaceFeatureView.swift │ │ └── FeatureViewController.swift │ ├── 矩形识别 │ │ └── RectangleViewController.swift │ └── 静态人脸识别 │ │ └── StaticFaceViewController.swift ├── JunVisionFaceTests │ ├── Info.plist │ └── JunVisionFaceTests.swift └── JunVisionFaceUITests │ ├── Info.plist │ └── JunVisionFaceUITests.swift ├── LICENSE └── README.md /.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 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4702D95E1FC555DD00A9FD11 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D95D1FC555DD00A9FD11 /* AppDelegate.swift */; }; 11 | 4702D9601FC555DD00A9FD11 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D95F1FC555DD00A9FD11 /* ViewController.swift */; }; 12 | 4702D9631FC555DD00A9FD11 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4702D9611FC555DD00A9FD11 /* Main.storyboard */; }; 13 | 4702D9661FC555DD00A9FD11 /* JunVisionFace.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9641FC555DD00A9FD11 /* JunVisionFace.xcdatamodeld */; }; 14 | 4702D9681FC555DD00A9FD11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4702D9671FC555DD00A9FD11 /* Assets.xcassets */; }; 15 | 4702D96B1FC555DD00A9FD11 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4702D9691FC555DD00A9FD11 /* LaunchScreen.storyboard */; }; 16 | 4702D9761FC555DD00A9FD11 /* JunVisionFaceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9751FC555DD00A9FD11 /* JunVisionFaceTests.swift */; }; 17 | 4702D9811FC555DD00A9FD11 /* JunVisionFaceUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9801FC555DD00A9FD11 /* JunVisionFaceUITests.swift */; }; 18 | 4702D99A1FC69C9500A9FD11 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9981FC69C9500A9FD11 /* TextViewController.swift */; }; 19 | 4702D99E1FC69CB200A9FD11 /* FeatureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D99C1FC69CB200A9FD11 /* FeatureViewController.swift */; }; 20 | 4702D9A21FC69CD300A9FD11 /* RectangleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9A01FC69CD300A9FD11 /* RectangleViewController.swift */; }; 21 | 4702D9A61FC69CFB00A9FD11 /* StaticFaceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9A41FC69CFB00A9FD11 /* StaticFaceViewController.swift */; }; 22 | 4702D9AA1FC69D2200A9FD11 /* DynamicFaceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9A81FC69D2200A9FD11 /* DynamicFaceViewController.swift */; }; 23 | 4702D9AE1FC69D5800A9FD11 /* RealAddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9AC1FC69D5800A9FD11 /* RealAddViewController.swift */; }; 24 | 4702D9B61FC6AD1900A9FD11 /* UIExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4702D9B51FC6AD1900A9FD11 /* UIExtension.swift */; }; 25 | 470904631FCBB954009D86B0 /* DectectBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470904621FCBB954009D86B0 /* DectectBaseViewController.swift */; }; 26 | 470904651FCBB95E009D86B0 /* ScanBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470904641FCBB95E009D86B0 /* ScanBaseViewController.swift */; }; 27 | 47EB9AC81FCD7AD300806487 /* TrackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EB9AC71FCD7AD300806487 /* TrackViewController.swift */; }; 28 | 47EDDF921FC7C1C20080EA4B /* JunVisionTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EDDF911FC7C1C20080EA4B /* JunVisionTool.swift */; }; 29 | 47EDDF941FC906BF0080EA4B /* FaceFeatureModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EDDF931FC906BF0080EA4B /* FaceFeatureModel.swift */; }; 30 | 47EDDF961FC911E90080EA4B /* JunViewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EDDF951FC911E90080EA4B /* JunViewTool.swift */; }; 31 | 47EDDF981FC95BA90080EA4B /* FaceFeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EDDF971FC95BA90080EA4B /* FaceFeatureView.swift */; }; 32 | 47EDDF9B1FC98EBD0080EA4B /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EDDF9A1FC98EBD0080EA4B /* CodeViewController.swift */; }; 33 | 47EDDF9D1FC991020080EA4B /* CodeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47EDDF9C1FC991020080EA4B /* CodeModel.swift */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXContainerItemProxy section */ 37 | 4702D9721FC555DD00A9FD11 /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 4702D9521FC555DC00A9FD11 /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = 4702D9591FC555DD00A9FD11; 42 | remoteInfo = JunVisionFace; 43 | }; 44 | 4702D97D1FC555DD00A9FD11 /* PBXContainerItemProxy */ = { 45 | isa = PBXContainerItemProxy; 46 | containerPortal = 4702D9521FC555DC00A9FD11 /* Project object */; 47 | proxyType = 1; 48 | remoteGlobalIDString = 4702D9591FC555DD00A9FD11; 49 | remoteInfo = JunVisionFace; 50 | }; 51 | /* End PBXContainerItemProxy section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | 4702D95A1FC555DD00A9FD11 /* JunVisionFace.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JunVisionFace.app; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 4702D95D1FC555DD00A9FD11 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 56 | 4702D95F1FC555DD00A9FD11 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 57 | 4702D9621FC555DD00A9FD11 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 58 | 4702D9651FC555DD00A9FD11 /* JunVisionFace.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = JunVisionFace.xcdatamodel; sourceTree = ""; }; 59 | 4702D9671FC555DD00A9FD11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 60 | 4702D96A1FC555DD00A9FD11 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 61 | 4702D96C1FC555DD00A9FD11 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 4702D9711FC555DD00A9FD11 /* JunVisionFaceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JunVisionFaceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 4702D9751FC555DD00A9FD11 /* JunVisionFaceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JunVisionFaceTests.swift; sourceTree = ""; }; 64 | 4702D9771FC555DD00A9FD11 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65 | 4702D97C1FC555DD00A9FD11 /* JunVisionFaceUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JunVisionFaceUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | 4702D9801FC555DD00A9FD11 /* JunVisionFaceUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JunVisionFaceUITests.swift; sourceTree = ""; }; 67 | 4702D9821FC555DD00A9FD11 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68 | 4702D9911FC696F000A9FD11 /* Vision.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vision.framework; path = System/Library/Frameworks/Vision.framework; sourceTree = SDKROOT; }; 69 | 4702D9981FC69C9500A9FD11 /* TextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewController.swift; sourceTree = ""; }; 70 | 4702D99C1FC69CB200A9FD11 /* FeatureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureViewController.swift; sourceTree = ""; }; 71 | 4702D9A01FC69CD300A9FD11 /* RectangleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RectangleViewController.swift; sourceTree = ""; }; 72 | 4702D9A41FC69CFB00A9FD11 /* StaticFaceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticFaceViewController.swift; sourceTree = ""; }; 73 | 4702D9A81FC69D2200A9FD11 /* DynamicFaceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicFaceViewController.swift; sourceTree = ""; }; 74 | 4702D9AC1FC69D5800A9FD11 /* RealAddViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealAddViewController.swift; sourceTree = ""; }; 75 | 4702D9B51FC6AD1900A9FD11 /* UIExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIExtension.swift; sourceTree = ""; }; 76 | 470904621FCBB954009D86B0 /* DectectBaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DectectBaseViewController.swift; sourceTree = ""; }; 77 | 470904641FCBB95E009D86B0 /* ScanBaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanBaseViewController.swift; sourceTree = ""; }; 78 | 47EB9AC71FCD7AD300806487 /* TrackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackViewController.swift; sourceTree = ""; }; 79 | 47EDDF911FC7C1C20080EA4B /* JunVisionTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JunVisionTool.swift; sourceTree = ""; }; 80 | 47EDDF931FC906BF0080EA4B /* FaceFeatureModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaceFeatureModel.swift; sourceTree = ""; }; 81 | 47EDDF951FC911E90080EA4B /* JunViewTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JunViewTool.swift; sourceTree = ""; }; 82 | 47EDDF971FC95BA90080EA4B /* FaceFeatureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaceFeatureView.swift; sourceTree = ""; }; 83 | 47EDDF9A1FC98EBD0080EA4B /* CodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeViewController.swift; sourceTree = ""; }; 84 | 47EDDF9C1FC991020080EA4B /* CodeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeModel.swift; sourceTree = ""; }; 85 | /* End PBXFileReference section */ 86 | 87 | /* Begin PBXFrameworksBuildPhase section */ 88 | 4702D9571FC555DD00A9FD11 /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | 4702D96E1FC555DD00A9FD11 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | 4702D9791FC555DD00A9FD11 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | /* End PBXFrameworksBuildPhase section */ 110 | 111 | /* Begin PBXGroup section */ 112 | 4702D9511FC555DC00A9FD11 = { 113 | isa = PBXGroup; 114 | children = ( 115 | 4702D95C1FC555DD00A9FD11 /* JunVisionFace */, 116 | 4702D9741FC555DD00A9FD11 /* JunVisionFaceTests */, 117 | 4702D97F1FC555DD00A9FD11 /* JunVisionFaceUITests */, 118 | 4702D95B1FC555DD00A9FD11 /* Products */, 119 | 4702D9901FC696EF00A9FD11 /* Frameworks */, 120 | ); 121 | sourceTree = ""; 122 | }; 123 | 4702D95B1FC555DD00A9FD11 /* Products */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 4702D95A1FC555DD00A9FD11 /* JunVisionFace.app */, 127 | 4702D9711FC555DD00A9FD11 /* JunVisionFaceTests.xctest */, 128 | 4702D97C1FC555DD00A9FD11 /* JunVisionFaceUITests.xctest */, 129 | ); 130 | name = Products; 131 | sourceTree = ""; 132 | }; 133 | 4702D95C1FC555DD00A9FD11 /* JunVisionFace */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 4702D9B01FC6A40200A9FD11 /* VisionTool */, 137 | 47EDDF991FC98EA00080EA4B /* 条码识别 */, 138 | 4702D9931FC69C6F00A9FD11 /* 动态人脸识别 */, 139 | 4702D9941FC69C6F00A9FD11 /* 静态人脸识别 */, 140 | 4702D9951FC69C6F00A9FD11 /* 矩形识别 */, 141 | 4702D9961FC69C6F00A9FD11 /* 实时动态添加 */, 142 | 4702D9971FC69C6F00A9FD11 /* 特征识别 */, 143 | 47EB9AC61FCD7A9C00806487 /* 对象检测和跟踪 */, 144 | 4702D9921FC69C6F00A9FD11 /* 文字识别 */, 145 | 4702D95D1FC555DD00A9FD11 /* AppDelegate.swift */, 146 | 4702D95F1FC555DD00A9FD11 /* ViewController.swift */, 147 | 4702D9611FC555DD00A9FD11 /* Main.storyboard */, 148 | 4702D9671FC555DD00A9FD11 /* Assets.xcassets */, 149 | 4702D9691FC555DD00A9FD11 /* LaunchScreen.storyboard */, 150 | 4702D96C1FC555DD00A9FD11 /* Info.plist */, 151 | 4702D9641FC555DD00A9FD11 /* JunVisionFace.xcdatamodeld */, 152 | ); 153 | path = JunVisionFace; 154 | sourceTree = ""; 155 | }; 156 | 4702D9741FC555DD00A9FD11 /* JunVisionFaceTests */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 4702D9751FC555DD00A9FD11 /* JunVisionFaceTests.swift */, 160 | 4702D9771FC555DD00A9FD11 /* Info.plist */, 161 | ); 162 | path = JunVisionFaceTests; 163 | sourceTree = ""; 164 | }; 165 | 4702D97F1FC555DD00A9FD11 /* JunVisionFaceUITests */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 4702D9801FC555DD00A9FD11 /* JunVisionFaceUITests.swift */, 169 | 4702D9821FC555DD00A9FD11 /* Info.plist */, 170 | ); 171 | path = JunVisionFaceUITests; 172 | sourceTree = ""; 173 | }; 174 | 4702D9901FC696EF00A9FD11 /* Frameworks */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 4702D9911FC696F000A9FD11 /* Vision.framework */, 178 | ); 179 | name = Frameworks; 180 | sourceTree = ""; 181 | }; 182 | 4702D9921FC69C6F00A9FD11 /* 文字识别 */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 4702D9981FC69C9500A9FD11 /* TextViewController.swift */, 186 | ); 187 | path = "文字识别"; 188 | sourceTree = ""; 189 | }; 190 | 4702D9931FC69C6F00A9FD11 /* 动态人脸识别 */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 4702D9A81FC69D2200A9FD11 /* DynamicFaceViewController.swift */, 194 | ); 195 | path = "动态人脸识别"; 196 | sourceTree = ""; 197 | }; 198 | 4702D9941FC69C6F00A9FD11 /* 静态人脸识别 */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | 4702D9A41FC69CFB00A9FD11 /* StaticFaceViewController.swift */, 202 | ); 203 | path = "静态人脸识别"; 204 | sourceTree = ""; 205 | }; 206 | 4702D9951FC69C6F00A9FD11 /* 矩形识别 */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 4702D9A01FC69CD300A9FD11 /* RectangleViewController.swift */, 210 | ); 211 | path = "矩形识别"; 212 | sourceTree = ""; 213 | }; 214 | 4702D9961FC69C6F00A9FD11 /* 实时动态添加 */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 4702D9AC1FC69D5800A9FD11 /* RealAddViewController.swift */, 218 | ); 219 | path = "实时动态添加"; 220 | sourceTree = ""; 221 | }; 222 | 4702D9971FC69C6F00A9FD11 /* 特征识别 */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | 4702D99C1FC69CB200A9FD11 /* FeatureViewController.swift */, 226 | 47EDDF931FC906BF0080EA4B /* FaceFeatureModel.swift */, 227 | 47EDDF971FC95BA90080EA4B /* FaceFeatureView.swift */, 228 | ); 229 | path = "特征识别"; 230 | sourceTree = ""; 231 | }; 232 | 4702D9B01FC6A40200A9FD11 /* VisionTool */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | 4702D9B11FC6A40200A9FD11 /* BaseVIewController */, 236 | 4702D9B21FC6A40200A9FD11 /* Tools */, 237 | ); 238 | path = VisionTool; 239 | sourceTree = ""; 240 | }; 241 | 4702D9B11FC6A40200A9FD11 /* BaseVIewController */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | 470904621FCBB954009D86B0 /* DectectBaseViewController.swift */, 245 | 470904641FCBB95E009D86B0 /* ScanBaseViewController.swift */, 246 | ); 247 | path = BaseVIewController; 248 | sourceTree = ""; 249 | }; 250 | 4702D9B21FC6A40200A9FD11 /* Tools */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | 4702D9B51FC6AD1900A9FD11 /* UIExtension.swift */, 254 | 47EDDF911FC7C1C20080EA4B /* JunVisionTool.swift */, 255 | 47EDDF951FC911E90080EA4B /* JunViewTool.swift */, 256 | ); 257 | path = Tools; 258 | sourceTree = ""; 259 | }; 260 | 47EB9AC61FCD7A9C00806487 /* 对象检测和跟踪 */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | 47EB9AC71FCD7AD300806487 /* TrackViewController.swift */, 264 | ); 265 | path = "对象检测和跟踪"; 266 | sourceTree = ""; 267 | }; 268 | 47EDDF991FC98EA00080EA4B /* 条码识别 */ = { 269 | isa = PBXGroup; 270 | children = ( 271 | 47EDDF9A1FC98EBD0080EA4B /* CodeViewController.swift */, 272 | 47EDDF9C1FC991020080EA4B /* CodeModel.swift */, 273 | ); 274 | path = "条码识别"; 275 | sourceTree = ""; 276 | }; 277 | /* End PBXGroup section */ 278 | 279 | /* Begin PBXNativeTarget section */ 280 | 4702D9591FC555DD00A9FD11 /* JunVisionFace */ = { 281 | isa = PBXNativeTarget; 282 | buildConfigurationList = 4702D9851FC555DD00A9FD11 /* Build configuration list for PBXNativeTarget "JunVisionFace" */; 283 | buildPhases = ( 284 | 4702D9561FC555DD00A9FD11 /* Sources */, 285 | 4702D9571FC555DD00A9FD11 /* Frameworks */, 286 | 4702D9581FC555DD00A9FD11 /* Resources */, 287 | ); 288 | buildRules = ( 289 | ); 290 | dependencies = ( 291 | ); 292 | name = JunVisionFace; 293 | productName = JunVisionFace; 294 | productReference = 4702D95A1FC555DD00A9FD11 /* JunVisionFace.app */; 295 | productType = "com.apple.product-type.application"; 296 | }; 297 | 4702D9701FC555DD00A9FD11 /* JunVisionFaceTests */ = { 298 | isa = PBXNativeTarget; 299 | buildConfigurationList = 4702D9881FC555DD00A9FD11 /* Build configuration list for PBXNativeTarget "JunVisionFaceTests" */; 300 | buildPhases = ( 301 | 4702D96D1FC555DD00A9FD11 /* Sources */, 302 | 4702D96E1FC555DD00A9FD11 /* Frameworks */, 303 | 4702D96F1FC555DD00A9FD11 /* Resources */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | 4702D9731FC555DD00A9FD11 /* PBXTargetDependency */, 309 | ); 310 | name = JunVisionFaceTests; 311 | productName = JunVisionFaceTests; 312 | productReference = 4702D9711FC555DD00A9FD11 /* JunVisionFaceTests.xctest */; 313 | productType = "com.apple.product-type.bundle.unit-test"; 314 | }; 315 | 4702D97B1FC555DD00A9FD11 /* JunVisionFaceUITests */ = { 316 | isa = PBXNativeTarget; 317 | buildConfigurationList = 4702D98B1FC555DD00A9FD11 /* Build configuration list for PBXNativeTarget "JunVisionFaceUITests" */; 318 | buildPhases = ( 319 | 4702D9781FC555DD00A9FD11 /* Sources */, 320 | 4702D9791FC555DD00A9FD11 /* Frameworks */, 321 | 4702D97A1FC555DD00A9FD11 /* Resources */, 322 | ); 323 | buildRules = ( 324 | ); 325 | dependencies = ( 326 | 4702D97E1FC555DD00A9FD11 /* PBXTargetDependency */, 327 | ); 328 | name = JunVisionFaceUITests; 329 | productName = JunVisionFaceUITests; 330 | productReference = 4702D97C1FC555DD00A9FD11 /* JunVisionFaceUITests.xctest */; 331 | productType = "com.apple.product-type.bundle.ui-testing"; 332 | }; 333 | /* End PBXNativeTarget section */ 334 | 335 | /* Begin PBXProject section */ 336 | 4702D9521FC555DC00A9FD11 /* Project object */ = { 337 | isa = PBXProject; 338 | attributes = { 339 | LastSwiftUpdateCheck = 0910; 340 | LastUpgradeCheck = 0910; 341 | ORGANIZATIONNAME = CoderJun; 342 | TargetAttributes = { 343 | 4702D9591FC555DD00A9FD11 = { 344 | CreatedOnToolsVersion = 9.1; 345 | ProvisioningStyle = Automatic; 346 | }; 347 | 4702D9701FC555DD00A9FD11 = { 348 | CreatedOnToolsVersion = 9.1; 349 | ProvisioningStyle = Automatic; 350 | TestTargetID = 4702D9591FC555DD00A9FD11; 351 | }; 352 | 4702D97B1FC555DD00A9FD11 = { 353 | CreatedOnToolsVersion = 9.1; 354 | ProvisioningStyle = Automatic; 355 | TestTargetID = 4702D9591FC555DD00A9FD11; 356 | }; 357 | }; 358 | }; 359 | buildConfigurationList = 4702D9551FC555DC00A9FD11 /* Build configuration list for PBXProject "JunVisionFace" */; 360 | compatibilityVersion = "Xcode 8.0"; 361 | developmentRegion = en; 362 | hasScannedForEncodings = 0; 363 | knownRegions = ( 364 | en, 365 | Base, 366 | ); 367 | mainGroup = 4702D9511FC555DC00A9FD11; 368 | productRefGroup = 4702D95B1FC555DD00A9FD11 /* Products */; 369 | projectDirPath = ""; 370 | projectRoot = ""; 371 | targets = ( 372 | 4702D9591FC555DD00A9FD11 /* JunVisionFace */, 373 | 4702D9701FC555DD00A9FD11 /* JunVisionFaceTests */, 374 | 4702D97B1FC555DD00A9FD11 /* JunVisionFaceUITests */, 375 | ); 376 | }; 377 | /* End PBXProject section */ 378 | 379 | /* Begin PBXResourcesBuildPhase section */ 380 | 4702D9581FC555DD00A9FD11 /* Resources */ = { 381 | isa = PBXResourcesBuildPhase; 382 | buildActionMask = 2147483647; 383 | files = ( 384 | 4702D96B1FC555DD00A9FD11 /* LaunchScreen.storyboard in Resources */, 385 | 4702D9681FC555DD00A9FD11 /* Assets.xcassets in Resources */, 386 | 4702D9631FC555DD00A9FD11 /* Main.storyboard in Resources */, 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | 4702D96F1FC555DD00A9FD11 /* Resources */ = { 391 | isa = PBXResourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | ); 395 | runOnlyForDeploymentPostprocessing = 0; 396 | }; 397 | 4702D97A1FC555DD00A9FD11 /* Resources */ = { 398 | isa = PBXResourcesBuildPhase; 399 | buildActionMask = 2147483647; 400 | files = ( 401 | ); 402 | runOnlyForDeploymentPostprocessing = 0; 403 | }; 404 | /* End PBXResourcesBuildPhase section */ 405 | 406 | /* Begin PBXSourcesBuildPhase section */ 407 | 4702D9561FC555DD00A9FD11 /* Sources */ = { 408 | isa = PBXSourcesBuildPhase; 409 | buildActionMask = 2147483647; 410 | files = ( 411 | 470904631FCBB954009D86B0 /* DectectBaseViewController.swift in Sources */, 412 | 4702D9661FC555DD00A9FD11 /* JunVisionFace.xcdatamodeld in Sources */, 413 | 4702D9601FC555DD00A9FD11 /* ViewController.swift in Sources */, 414 | 4702D9AE1FC69D5800A9FD11 /* RealAddViewController.swift in Sources */, 415 | 4702D99E1FC69CB200A9FD11 /* FeatureViewController.swift in Sources */, 416 | 4702D95E1FC555DD00A9FD11 /* AppDelegate.swift in Sources */, 417 | 47EDDF921FC7C1C20080EA4B /* JunVisionTool.swift in Sources */, 418 | 4702D9A21FC69CD300A9FD11 /* RectangleViewController.swift in Sources */, 419 | 47EDDF981FC95BA90080EA4B /* FaceFeatureView.swift in Sources */, 420 | 4702D9AA1FC69D2200A9FD11 /* DynamicFaceViewController.swift in Sources */, 421 | 4702D99A1FC69C9500A9FD11 /* TextViewController.swift in Sources */, 422 | 47EDDF961FC911E90080EA4B /* JunViewTool.swift in Sources */, 423 | 4702D9B61FC6AD1900A9FD11 /* UIExtension.swift in Sources */, 424 | 47EDDF9B1FC98EBD0080EA4B /* CodeViewController.swift in Sources */, 425 | 470904651FCBB95E009D86B0 /* ScanBaseViewController.swift in Sources */, 426 | 47EDDF9D1FC991020080EA4B /* CodeModel.swift in Sources */, 427 | 47EDDF941FC906BF0080EA4B /* FaceFeatureModel.swift in Sources */, 428 | 4702D9A61FC69CFB00A9FD11 /* StaticFaceViewController.swift in Sources */, 429 | 47EB9AC81FCD7AD300806487 /* TrackViewController.swift in Sources */, 430 | ); 431 | runOnlyForDeploymentPostprocessing = 0; 432 | }; 433 | 4702D96D1FC555DD00A9FD11 /* Sources */ = { 434 | isa = PBXSourcesBuildPhase; 435 | buildActionMask = 2147483647; 436 | files = ( 437 | 4702D9761FC555DD00A9FD11 /* JunVisionFaceTests.swift in Sources */, 438 | ); 439 | runOnlyForDeploymentPostprocessing = 0; 440 | }; 441 | 4702D9781FC555DD00A9FD11 /* Sources */ = { 442 | isa = PBXSourcesBuildPhase; 443 | buildActionMask = 2147483647; 444 | files = ( 445 | 4702D9811FC555DD00A9FD11 /* JunVisionFaceUITests.swift in Sources */, 446 | ); 447 | runOnlyForDeploymentPostprocessing = 0; 448 | }; 449 | /* End PBXSourcesBuildPhase section */ 450 | 451 | /* Begin PBXTargetDependency section */ 452 | 4702D9731FC555DD00A9FD11 /* PBXTargetDependency */ = { 453 | isa = PBXTargetDependency; 454 | target = 4702D9591FC555DD00A9FD11 /* JunVisionFace */; 455 | targetProxy = 4702D9721FC555DD00A9FD11 /* PBXContainerItemProxy */; 456 | }; 457 | 4702D97E1FC555DD00A9FD11 /* PBXTargetDependency */ = { 458 | isa = PBXTargetDependency; 459 | target = 4702D9591FC555DD00A9FD11 /* JunVisionFace */; 460 | targetProxy = 4702D97D1FC555DD00A9FD11 /* PBXContainerItemProxy */; 461 | }; 462 | /* End PBXTargetDependency section */ 463 | 464 | /* Begin PBXVariantGroup section */ 465 | 4702D9611FC555DD00A9FD11 /* Main.storyboard */ = { 466 | isa = PBXVariantGroup; 467 | children = ( 468 | 4702D9621FC555DD00A9FD11 /* Base */, 469 | ); 470 | name = Main.storyboard; 471 | sourceTree = ""; 472 | }; 473 | 4702D9691FC555DD00A9FD11 /* LaunchScreen.storyboard */ = { 474 | isa = PBXVariantGroup; 475 | children = ( 476 | 4702D96A1FC555DD00A9FD11 /* Base */, 477 | ); 478 | name = LaunchScreen.storyboard; 479 | sourceTree = ""; 480 | }; 481 | /* End PBXVariantGroup section */ 482 | 483 | /* Begin XCBuildConfiguration section */ 484 | 4702D9831FC555DD00A9FD11 /* Debug */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ALWAYS_SEARCH_USER_PATHS = NO; 488 | CLANG_ANALYZER_NONNULL = YES; 489 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 490 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 491 | CLANG_CXX_LIBRARY = "libc++"; 492 | CLANG_ENABLE_MODULES = YES; 493 | CLANG_ENABLE_OBJC_ARC = YES; 494 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 495 | CLANG_WARN_BOOL_CONVERSION = YES; 496 | CLANG_WARN_COMMA = YES; 497 | CLANG_WARN_CONSTANT_CONVERSION = YES; 498 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 499 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 500 | CLANG_WARN_EMPTY_BODY = YES; 501 | CLANG_WARN_ENUM_CONVERSION = YES; 502 | CLANG_WARN_INFINITE_RECURSION = YES; 503 | CLANG_WARN_INT_CONVERSION = YES; 504 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 505 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 506 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 507 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 508 | CLANG_WARN_STRICT_PROTOTYPES = YES; 509 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 510 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 511 | CLANG_WARN_UNREACHABLE_CODE = YES; 512 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 513 | CODE_SIGN_IDENTITY = "iPhone Developer"; 514 | COPY_PHASE_STRIP = NO; 515 | DEBUG_INFORMATION_FORMAT = dwarf; 516 | ENABLE_STRICT_OBJC_MSGSEND = YES; 517 | ENABLE_TESTABILITY = YES; 518 | GCC_C_LANGUAGE_STANDARD = gnu11; 519 | GCC_DYNAMIC_NO_PIC = NO; 520 | GCC_NO_COMMON_BLOCKS = YES; 521 | GCC_OPTIMIZATION_LEVEL = 0; 522 | GCC_PREPROCESSOR_DEFINITIONS = ( 523 | "DEBUG=1", 524 | "$(inherited)", 525 | ); 526 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 527 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 528 | GCC_WARN_UNDECLARED_SELECTOR = YES; 529 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 530 | GCC_WARN_UNUSED_FUNCTION = YES; 531 | GCC_WARN_UNUSED_VARIABLE = YES; 532 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 533 | MTL_ENABLE_DEBUG_INFO = YES; 534 | ONLY_ACTIVE_ARCH = YES; 535 | SDKROOT = iphoneos; 536 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 537 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 538 | }; 539 | name = Debug; 540 | }; 541 | 4702D9841FC555DD00A9FD11 /* Release */ = { 542 | isa = XCBuildConfiguration; 543 | buildSettings = { 544 | ALWAYS_SEARCH_USER_PATHS = NO; 545 | CLANG_ANALYZER_NONNULL = YES; 546 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 547 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 548 | CLANG_CXX_LIBRARY = "libc++"; 549 | CLANG_ENABLE_MODULES = YES; 550 | CLANG_ENABLE_OBJC_ARC = YES; 551 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 552 | CLANG_WARN_BOOL_CONVERSION = YES; 553 | CLANG_WARN_COMMA = YES; 554 | CLANG_WARN_CONSTANT_CONVERSION = YES; 555 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 556 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 557 | CLANG_WARN_EMPTY_BODY = YES; 558 | CLANG_WARN_ENUM_CONVERSION = YES; 559 | CLANG_WARN_INFINITE_RECURSION = YES; 560 | CLANG_WARN_INT_CONVERSION = YES; 561 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 562 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 563 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 564 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 565 | CLANG_WARN_STRICT_PROTOTYPES = YES; 566 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 567 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 568 | CLANG_WARN_UNREACHABLE_CODE = YES; 569 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 570 | CODE_SIGN_IDENTITY = "iPhone Developer"; 571 | COPY_PHASE_STRIP = NO; 572 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 573 | ENABLE_NS_ASSERTIONS = NO; 574 | ENABLE_STRICT_OBJC_MSGSEND = YES; 575 | GCC_C_LANGUAGE_STANDARD = gnu11; 576 | GCC_NO_COMMON_BLOCKS = YES; 577 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 578 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 579 | GCC_WARN_UNDECLARED_SELECTOR = YES; 580 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 581 | GCC_WARN_UNUSED_FUNCTION = YES; 582 | GCC_WARN_UNUSED_VARIABLE = YES; 583 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 584 | MTL_ENABLE_DEBUG_INFO = NO; 585 | SDKROOT = iphoneos; 586 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 587 | VALIDATE_PRODUCT = YES; 588 | }; 589 | name = Release; 590 | }; 591 | 4702D9861FC555DD00A9FD11 /* Debug */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 595 | CODE_SIGN_STYLE = Automatic; 596 | DEVELOPMENT_TEAM = 3HG8J7L5X5; 597 | INFOPLIST_FILE = JunVisionFace/Info.plist; 598 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 599 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 600 | PRODUCT_BUNDLE_IDENTIFIER = "com.ios-tian.JunVisionFace"; 601 | PRODUCT_NAME = "$(TARGET_NAME)"; 602 | SWIFT_VERSION = 4.0; 603 | TARGETED_DEVICE_FAMILY = "1,2"; 604 | }; 605 | name = Debug; 606 | }; 607 | 4702D9871FC555DD00A9FD11 /* Release */ = { 608 | isa = XCBuildConfiguration; 609 | buildSettings = { 610 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 611 | CODE_SIGN_STYLE = Automatic; 612 | DEVELOPMENT_TEAM = 3HG8J7L5X5; 613 | INFOPLIST_FILE = JunVisionFace/Info.plist; 614 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 615 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 616 | PRODUCT_BUNDLE_IDENTIFIER = "com.ios-tian.JunVisionFace"; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | SWIFT_VERSION = 4.0; 619 | TARGETED_DEVICE_FAMILY = "1,2"; 620 | }; 621 | name = Release; 622 | }; 623 | 4702D9891FC555DD00A9FD11 /* Debug */ = { 624 | isa = XCBuildConfiguration; 625 | buildSettings = { 626 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 627 | BUNDLE_LOADER = "$(TEST_HOST)"; 628 | CODE_SIGN_STYLE = Automatic; 629 | INFOPLIST_FILE = JunVisionFaceTests/Info.plist; 630 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 631 | PRODUCT_BUNDLE_IDENTIFIER = "com.ios-tian.JunVisionFaceTests"; 632 | PRODUCT_NAME = "$(TARGET_NAME)"; 633 | SWIFT_VERSION = 4.0; 634 | TARGETED_DEVICE_FAMILY = "1,2"; 635 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JunVisionFace.app/JunVisionFace"; 636 | }; 637 | name = Debug; 638 | }; 639 | 4702D98A1FC555DD00A9FD11 /* Release */ = { 640 | isa = XCBuildConfiguration; 641 | buildSettings = { 642 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 643 | BUNDLE_LOADER = "$(TEST_HOST)"; 644 | CODE_SIGN_STYLE = Automatic; 645 | INFOPLIST_FILE = JunVisionFaceTests/Info.plist; 646 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 647 | PRODUCT_BUNDLE_IDENTIFIER = "com.ios-tian.JunVisionFaceTests"; 648 | PRODUCT_NAME = "$(TARGET_NAME)"; 649 | SWIFT_VERSION = 4.0; 650 | TARGETED_DEVICE_FAMILY = "1,2"; 651 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JunVisionFace.app/JunVisionFace"; 652 | }; 653 | name = Release; 654 | }; 655 | 4702D98C1FC555DD00A9FD11 /* Debug */ = { 656 | isa = XCBuildConfiguration; 657 | buildSettings = { 658 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 659 | CODE_SIGN_STYLE = Automatic; 660 | INFOPLIST_FILE = JunVisionFaceUITests/Info.plist; 661 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 662 | PRODUCT_BUNDLE_IDENTIFIER = "com.ios-tian.JunVisionFaceUITests"; 663 | PRODUCT_NAME = "$(TARGET_NAME)"; 664 | SWIFT_VERSION = 4.0; 665 | TARGETED_DEVICE_FAMILY = "1,2"; 666 | TEST_TARGET_NAME = JunVisionFace; 667 | }; 668 | name = Debug; 669 | }; 670 | 4702D98D1FC555DD00A9FD11 /* Release */ = { 671 | isa = XCBuildConfiguration; 672 | buildSettings = { 673 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 674 | CODE_SIGN_STYLE = Automatic; 675 | INFOPLIST_FILE = JunVisionFaceUITests/Info.plist; 676 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 677 | PRODUCT_BUNDLE_IDENTIFIER = "com.ios-tian.JunVisionFaceUITests"; 678 | PRODUCT_NAME = "$(TARGET_NAME)"; 679 | SWIFT_VERSION = 4.0; 680 | TARGETED_DEVICE_FAMILY = "1,2"; 681 | TEST_TARGET_NAME = JunVisionFace; 682 | }; 683 | name = Release; 684 | }; 685 | /* End XCBuildConfiguration section */ 686 | 687 | /* Begin XCConfigurationList section */ 688 | 4702D9551FC555DC00A9FD11 /* Build configuration list for PBXProject "JunVisionFace" */ = { 689 | isa = XCConfigurationList; 690 | buildConfigurations = ( 691 | 4702D9831FC555DD00A9FD11 /* Debug */, 692 | 4702D9841FC555DD00A9FD11 /* Release */, 693 | ); 694 | defaultConfigurationIsVisible = 0; 695 | defaultConfigurationName = Release; 696 | }; 697 | 4702D9851FC555DD00A9FD11 /* Build configuration list for PBXNativeTarget "JunVisionFace" */ = { 698 | isa = XCConfigurationList; 699 | buildConfigurations = ( 700 | 4702D9861FC555DD00A9FD11 /* Debug */, 701 | 4702D9871FC555DD00A9FD11 /* Release */, 702 | ); 703 | defaultConfigurationIsVisible = 0; 704 | defaultConfigurationName = Release; 705 | }; 706 | 4702D9881FC555DD00A9FD11 /* Build configuration list for PBXNativeTarget "JunVisionFaceTests" */ = { 707 | isa = XCConfigurationList; 708 | buildConfigurations = ( 709 | 4702D9891FC555DD00A9FD11 /* Debug */, 710 | 4702D98A1FC555DD00A9FD11 /* Release */, 711 | ); 712 | defaultConfigurationIsVisible = 0; 713 | defaultConfigurationName = Release; 714 | }; 715 | 4702D98B1FC555DD00A9FD11 /* Build configuration list for PBXNativeTarget "JunVisionFaceUITests" */ = { 716 | isa = XCConfigurationList; 717 | buildConfigurations = ( 718 | 4702D98C1FC555DD00A9FD11 /* Debug */, 719 | 4702D98D1FC555DD00A9FD11 /* Release */, 720 | ); 721 | defaultConfigurationIsVisible = 0; 722 | defaultConfigurationName = Release; 723 | }; 724 | /* End XCConfigurationList section */ 725 | 726 | /* Begin XCVersionGroup section */ 727 | 4702D9641FC555DD00A9FD11 /* JunVisionFace.xcdatamodeld */ = { 728 | isa = XCVersionGroup; 729 | children = ( 730 | 4702D9651FC555DD00A9FD11 /* JunVisionFace.xcdatamodel */, 731 | ); 732 | currentVersion = 4702D9651FC555DD00A9FD11 /* JunVisionFace.xcdatamodel */; 733 | path = JunVisionFace.xcdatamodeld; 734 | sourceTree = ""; 735 | versionGroupType = wrapper.xcdatamodel; 736 | }; 737 | /* End XCVersionGroup section */ 738 | }; 739 | rootObject = 4702D9521FC555DC00A9FD11 /* Project object */; 740 | } 741 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/22. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 19 | 20 | 21 | 22 | return true 23 | } 24 | 25 | func applicationWillResignActive(_ application: UIApplication) { 26 | // 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. 27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | func applicationWillEnterForeground(_ application: UIApplication) { 36 | // 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. 37 | } 38 | 39 | func applicationDidBecomeActive(_ application: UIApplication) { 40 | // 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. 41 | } 42 | 43 | func applicationWillTerminate(_ application: UIApplication) { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | // Saves changes in the application's managed object context before the application terminates. 46 | self.saveContext() 47 | } 48 | 49 | // MARK: - Core Data stack 50 | 51 | lazy var persistentContainer: NSPersistentContainer = { 52 | /* 53 | The persistent container for the application. This implementation 54 | creates and returns a container, having loaded the store for the 55 | application to it. This property is optional since there are legitimate 56 | error conditions that could cause the creation of the store to fail. 57 | */ 58 | let container = NSPersistentContainer(name: "JunVisionFace") 59 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in 60 | if let error = error as NSError? { 61 | // Replace this implementation with code to handle the error appropriately. 62 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 63 | 64 | /* 65 | Typical reasons for an error here include: 66 | * The parent directory does not exist, cannot be created, or disallows writing. 67 | * The persistent store is not accessible, due to permissions or data protection when the device is locked. 68 | * The device is out of space. 69 | * The store could not be migrated to the current model version. 70 | Check the error message to determine what the actual problem was. 71 | */ 72 | fatalError("Unresolved error \(error), \(error.userInfo)") 73 | } 74 | }) 75 | return container 76 | }() 77 | 78 | // MARK: - Core Data Saving support 79 | 80 | func saveContext () { 81 | let context = persistentContainer.viewContext 82 | if context.hasChanges { 83 | do { 84 | try context.save() 85 | } catch { 86 | // Replace this implementation with code to handle the error appropriately. 87 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 88 | let nserror = error as NSError 89 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 90 | } 91 | } 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Spotlight-40.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-60.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-Spotlight-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-Spotlight-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "1024x1024", 53 | "idiom" : "ios-marketing", 54 | "filename" : "icon1024.png", 55 | "scale" : "1x" 56 | } 57 | ], 58 | "info" : { 59 | "version" : 1, 60 | "author" : "xcode" 61 | } 62 | } -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-60.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Small29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Small29@2x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Small29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Small29@3x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/AppIcon.appiconset/icon1024.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/eyes.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "eyes@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "eyes@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/eyes.imageset/eyes@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/eyes.imageset/eyes@2x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/eyes.imageset/eyes@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/eyes.imageset/eyes@3x.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/photo189.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "photo189.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/photo189.imageset/photo189.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/photo189.imageset/photo189.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/photo193.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "photo193.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Assets.xcassets/photo193.imageset/photo193.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTitan/JunVisionFace/f1ec363719f95b802e8a253396813db0b234b61c/JunVisionFace/JunVisionFace/Assets.xcassets/photo193.imageset/photo193.png -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/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 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/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 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | NSPhotoLibraryAddUsageDescription 45 | 修改相册 46 | NSPhotoLibraryUsageDescription 47 | 访问相册 48 | NSCameraUsageDescription 49 | 使用相机 50 | 51 | 52 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/JunVisionFace.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | JunVisionFace.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/JunVisionFace.xcdatamodeld/JunVisionFace.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/22. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | @IBOutlet weak var tableView: UITableView! 14 | fileprivate var titleArr = ["文字识别", "矩形识别", "条码识别", "人脸特征识别", "静态人脸识别", "动态人脸识别", "实时动态添加", "对象检测和跟踪"] 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | title = "Vision列表" 19 | } 20 | } 21 | 22 | extension ViewController: UITableViewDelegate, UITableViewDataSource{ 23 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 24 | return titleArr.count 25 | } 26 | 27 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 28 | var cell = tableView.dequeueReusableCell(withIdentifier: "cell") 29 | if cell == nil{ 30 | cell = UITableViewCell(style: .default, reuseIdentifier: "cell") 31 | cell?.textLabel?.text = titleArr[indexPath.row] 32 | cell?.accessoryType = .disclosureIndicator 33 | cell?.selectionStyle = .none 34 | } 35 | return cell! 36 | } 37 | 38 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 39 | let vcs = [TextViewController(), RectangleViewController(), CodeViewController(), FeatureViewController(), StaticFaceViewController(), DynamicFaceViewController(), RealAddViewController(), TrackViewController()] 40 | let vc = vcs[indexPath.row] 41 | vc.hidesBottomBarWhenPushed = true 42 | navigationController?.pushViewController(vc, animated: true) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/VisionTool/BaseVIewController/DectectBaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DectectBaseViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/27. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DectectBaseViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { 12 | 13 | ///相册选择的图片 14 | var selectorImage: UIImage? 15 | var imageView = UIImageView() 16 | lazy var cleanView: UIView = { 17 | guard let imageSize = selectorImage?.scaleImage() else { return UIView() } 18 | let cleanVIew = UIView() 19 | cleanVIew.backgroundColor = UIColor.clear 20 | return cleanVIew 21 | }() 22 | 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | 27 | setupVIews() 28 | } 29 | 30 | /// 创建界面 31 | func setupVIews(){ 32 | view.backgroundColor = UIColor.white 33 | 34 | view.addSubview(addButton(title: "选择图片", rect: CGRect(x: 50, y: 74, width: kScreenWidth - 100, height: 30), action: #selector(selectedImageAction(_:)))) 35 | view.addSubview(addButton(title: "开始识别", rect: CGRect(x: 50, y: kScreenHeight - 40, width: kScreenWidth - 100, height: 30), action: #selector(startRecognitionAction(_:)))) 36 | 37 | imageView.frame = CGRect(x: 0, y: 120, width: kScreenWidth, height: kScreenWidth / 125 * 161) 38 | imageView.backgroundColor = UIColor.cyan 39 | imageView.contentMode = .scaleAspectFit 40 | view.addSubview(imageView) 41 | 42 | imageView.addSubview(cleanView) 43 | } 44 | 45 | 46 | //访问相册 47 | func useringPhotoLibrary(){ 48 | //1. 判断是否允许该操作 49 | if !UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { 50 | print("操作限制, 不可执行") 51 | return 52 | } 53 | 54 | //2. 创建照片选择器 55 | let imagePC = UIImagePickerController() 56 | //2.1 设置数据源 57 | imagePC.sourceType = .photoLibrary 58 | //2.2 设置代理 59 | imagePC.delegate = self 60 | //2.3 的弹出控制器 61 | present(imagePC, animated: true, completion: nil) 62 | } 63 | 64 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 65 | // 1. 获取选中的图片 66 | guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else { return } 67 | 68 | selectorImage = image 69 | imageView.image = image 70 | 71 | //3. 退出控制器 72 | picker.dismiss(animated: true, completion: nil) 73 | } 74 | 75 | //选取完成后调用 76 | func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 77 | picker.dismiss(animated: true, completion: nil) 78 | } 79 | } 80 | 81 | 82 | //MARK: 界面处理 83 | extension DectectBaseViewController{ 84 | fileprivate func addButton(title: String, rect: CGRect, action: Selector) -> UIButton{ 85 | let button = UIButton(type: .custom) 86 | button.frame = rect 87 | button.setTitle(title, for: .normal) 88 | button.setTitleColor(UIColor.white, for: .normal) 89 | button.backgroundColor = UIColor.red 90 | button.addTarget(self, action: action, for: .touchUpInside) 91 | return button 92 | } 93 | 94 | //选择图片 95 | @objc func selectedImageAction(_ sender: Any) { 96 | //0. 清除所有红框 97 | for subview in cleanView.subviews { 98 | subview.removeFromSuperview() 99 | } 100 | 101 | //1. 选择图片 102 | useringPhotoLibrary() 103 | } 104 | 105 | //开始识别 106 | @objc func startRecognitionAction(_ sender: Any) { 107 | //0. 清除所有红框 108 | for subview in cleanView.subviews { 109 | subview.removeFromSuperview() 110 | } 111 | 112 | //1. 获取尺寸一样的图片 113 | guard let image = selectorImage else { return } 114 | 115 | //2. 修改cleanView尺寸 116 | let imageSize = image.scaleImage() 117 | cleanView.frame = CGRect(x: (kScreenWidth - imageSize.width) / 2, y: (kScreenWidth / imageViewScale - imageSize.height) / 2, width: imageSize.width, height: imageSize.height) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/VisionTool/BaseVIewController/ScanBaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScanBaseViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/27. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | import Vision 12 | 13 | class ScanBaseViewController: UIViewController { 14 | 15 | fileprivate var session = AVCaptureSession() 16 | fileprivate var videoOutput = AVCaptureVideoDataOutput() 17 | 18 | var previewLayer = AVCaptureVideoPreviewLayer() 19 | var deviceInput: AVCaptureDeviceInput? 20 | //懒加载属性 21 | lazy var cleanView: UIView = { 22 | let view = UIView() 23 | view.frame = CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight) 24 | view.backgroundColor = UIColor.clear 25 | return view 26 | }() 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | 31 | setupViews() 32 | getAuthorization() 33 | } 34 | 35 | override func viewWillDisappear(_ animated: Bool) { 36 | super.viewWillAppear(animated) 37 | 38 | //停止扫描 39 | session.stopRunning() 40 | previewLayer.removeFromSuperlayer() 41 | } 42 | } 43 | 44 | 45 | //MARK: 设置界面 46 | extension ScanBaseViewController{ 47 | fileprivate func setupViews(){ 48 | view.backgroundColor = UIColor.black 49 | 50 | //添加透明View 51 | view.addSubview(cleanView) 52 | 53 | let bottomView = UIView(frame: CGRect(x: 0, y: view.frame.height - 50, width: kScreenWidth, height: 50)) 54 | bottomView.backgroundColor = UIColor(white: 0, alpha: 0.7) 55 | cleanView.addSubview(bottomView) 56 | 57 | //切换摄像头 58 | navigationItem.rightBarButtonItem = UIBarButtonItem(title: "切换摄像", style: .plain, target: self, action: #selector(switchCameraAction)) 59 | } 60 | 61 | //切换摄像头 62 | @objc fileprivate func switchCameraAction(){ 63 | //1. 执行转场动画 64 | let anima = CATransition() 65 | anima.type = "oglFlip" 66 | anima.subtype = "fromLeft" 67 | anima.duration = 0.5 68 | view.layer.add(anima, forKey: nil) 69 | 70 | //2. 获取当前摄像头 71 | guard let deviceIn = deviceInput else { return } 72 | let position: AVCaptureDevice.Position = deviceIn.device.position == .back ? .front : .back 73 | 74 | //3. 创建新的input 75 | let deviceSession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: position) 76 | guard let newDevice = deviceSession.devices.filter({ $0.position == position }).first else { return } 77 | guard let newVideoInput = try? AVCaptureDeviceInput(device: newDevice) else { return } 78 | 79 | //4. 移除旧输入,添加新输入 80 | //4.1 设备加锁 81 | session.beginConfiguration() 82 | //4.2. 移除旧设备 83 | session.removeInput(deviceIn) 84 | //4.3. 添加新设备 85 | session.addInput(newVideoInput) 86 | 87 | //4.4. 重新设置输出方向 88 | guard let connection = videoOutput.connection(with: .video) else { return } 89 | //6.2. 设置输出方向 90 | if connection.isVideoOrientationSupported{ 91 | connection.videoOrientation = .portrait 92 | } 93 | //6.3. 视频稳定性设置 94 | if connection.isVideoStabilizationSupported{ 95 | connection.preferredVideoStabilizationMode = .auto 96 | } 97 | 98 | //4.5. 设备解锁 99 | session.commitConfiguration() 100 | 101 | //5. 保存最新输入 102 | deviceInput = newVideoInput 103 | } 104 | } 105 | 106 | 107 | //MARK: 添加摄像头 108 | extension ScanBaseViewController { 109 | //请求相机权限 110 | fileprivate func getAuthorization(){ 111 | let videoStatus = AVCaptureDevice.authorizationStatus(for: .video) 112 | if videoStatus == .authorized || videoStatus == .notDetermined{ 113 | addScaningVideo() 114 | }else{ 115 | print("相机权限未开启") 116 | } 117 | } 118 | 119 | //添加摄像头 120 | fileprivate func addScaningVideo(){ 121 | //1.获取输入设备(摄像头) 122 | guard let device = AVCaptureDevice.default(for: .video) else { return } 123 | 124 | //2.根据输入设备创建输入对象 125 | guard let deviceIn = try? AVCaptureDeviceInput(device: device) else { return } 126 | deviceInput = deviceIn 127 | 128 | //3.设置代理监听输出对象输出的数据,在主线程中刷新 129 | videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main) 130 | 131 | //4.设置输出质量(高像素输出) 132 | session.sessionPreset = .high 133 | 134 | //5.添加输入到会话 135 | if session.canAddInput(deviceInput!) { 136 | session.addInput(deviceInput!) 137 | } 138 | 139 | //6. 添加输出到会话 140 | if session.canAddOutput(videoOutput) { 141 | session.addOutput(videoOutput) 142 | 143 | //6.1. 设置输出视频相关属性 144 | guard let connection = videoOutput.connection(with: .video) else { return } 145 | //6.2. 设置输出方向 146 | if connection.isVideoOrientationSupported{ 147 | connection.videoOrientation = .portrait 148 | } 149 | //6.3. 视频稳定性设置 150 | if connection.isVideoStabilizationSupported{ 151 | connection.preferredVideoStabilizationMode = .auto 152 | } 153 | } 154 | 155 | //7.创建预览图层 156 | previewLayer = AVCaptureVideoPreviewLayer(session: session) 157 | previewLayer.videoGravity = .resizeAspectFill 158 | previewLayer.frame = view.bounds 159 | view.layer.insertSublayer(previewLayer, at: 0) 160 | 161 | //8. 开始扫描 162 | if !session.isRunning { 163 | DispatchQueue.global().async { 164 | self.session.startRunning() 165 | } 166 | } 167 | } 168 | } 169 | 170 | 171 | extension ScanBaseViewController: AVCaptureVideoDataOutputSampleBufferDelegate { 172 | 173 | } 174 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/VisionTool/Tools/JunViewTool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JunViewTool.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/25. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Vision 11 | import AVFoundation 12 | 13 | class JunViewTool: NSObject { 14 | 15 | } 16 | 17 | extension JunViewTool{ 18 | /// 添加红框view 19 | func addRectangleView(rect: CGRect, _ position: AVCaptureDevice.Position = .back) -> UIView { 20 | // 坐标是以后摄像头为标准的, 前摄像头在后摄像头的基础上翻转了180度 21 | let x = position == .back ? rect.minX : rect.width - rect.maxX 22 | let boxView = UIView(frame: CGRect(x: x, y: rect.minY, width: rect.width, height: rect.height)) 23 | boxView.backgroundColor = UIColor.clear 24 | boxView.layer.borderColor = UIColor.red.cgColor 25 | boxView.layer.borderWidth = 2 26 | return boxView 27 | } 28 | 29 | 30 | /// 添加红框layer 31 | func addRectangleLayer(rect: CGRect) -> CALayer { 32 | let boxLayer = CALayer() 33 | boxLayer.frame = rect 34 | boxLayer.cornerRadius = 3 35 | boxLayer.borderColor = UIColor.red.cgColor 36 | boxLayer.borderWidth = 1.5 37 | return boxLayer 38 | } 39 | 40 | /// 添加眼睛imageView 41 | func addEyeImageView(rect: CGRect) -> UIImageView { 42 | let imageView = UIImageView(frame: rect) 43 | imageView.image = UIImage(named: "eyes") 44 | imageView.contentMode = .scaleAspectFit 45 | return imageView 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/VisionTool/Tools/JunVisionTool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JunVisionTool.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/24. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Vision 11 | 12 | enum JunVisionDetectType { 13 | case text 14 | case code 15 | case rectangle 16 | case staticFace 17 | case feature 18 | case hotFace 19 | case realAdd 20 | } 21 | 22 | class JunVisionTool: NSObject { 23 | typealias JunDetectHandle = ((_ bigRectArr: [CGRect]?, _ backArr: [Any]?) -> ()) 24 | 25 | } 26 | 27 | //MARK: 图片识别 28 | extension JunVisionTool { 29 | /// 识别图片(根据不同类型) 30 | func visionDetectImage(type: JunVisionDetectType, image: UIImage, _ completeBack: @escaping JunDetectHandle){ 31 | //1. 转成ciimage 32 | guard let ciImage = CIImage(image: image) else { return } 33 | 34 | //2. 创建处理request 35 | let requestHandle = VNImageRequestHandler(ciImage: ciImage, options: [:]) 36 | 37 | //3. 创建baseRequest 38 | //大多数识别请求request都继承自VNImageBasedRequest 39 | var baseRequest = VNImageBasedRequest() 40 | 41 | //4. 设置回调 42 | let completionHandle: VNRequestCompletionHandler = { request, error in 43 | let observations = request.results 44 | self.handleImageObservable(type: type, image: image, observations, completeBack) 45 | } 46 | 47 | //5. 创建识别请求 48 | switch type { 49 | case .text: 50 | baseRequest = VNDetectTextRectanglesRequest(completionHandler: completionHandle) 51 | // 设置识别具体文字 52 | baseRequest.setValue(true, forKey: "reportCharacterBoxes") 53 | case .code: 54 | let request = VNDetectBarcodesRequest(completionHandler: completionHandle) 55 | request.symbologies = VNDetectBarcodesRequest.supportedSymbologies 56 | baseRequest = request //设置可识别的条码种类 57 | case .feature: 58 | baseRequest = VNDetectFaceLandmarksRequest(completionHandler: completionHandle) 59 | case .rectangle: 60 | baseRequest = VNDetectRectanglesRequest(completionHandler: completionHandle) 61 | case .staticFace: 62 | baseRequest = VNDetectFaceRectanglesRequest(completionHandler: completionHandle) 63 | default: 64 | break 65 | } 66 | 67 | //6. 发送请求 68 | DispatchQueue.global().async { 69 | do{ 70 | try requestHandle.perform([baseRequest]) 71 | }catch{ 72 | print("Throws:\(error)") 73 | } 74 | } 75 | } 76 | 77 | /// 处理识别后的数据 78 | fileprivate func handleImageObservable(type: JunVisionDetectType, image: UIImage, _ observations: [Any]?, _ completionHandle: JunDetectHandle){ 79 | switch type { 80 | case .text: 81 | textDectect(observations, image: image, completionHandle) 82 | case .code: 83 | codeDectect(observations, image: image, completionHandle) 84 | case .feature: 85 | faceFeatureDectect(observations, image: image, completionHandle) 86 | case .rectangle: 87 | rectangleDectect(observations, image: image, completionHandle) 88 | case .staticFace: 89 | staticFaceDectect(observations, image: image, completionHandle) 90 | default: 91 | break 92 | } 93 | } 94 | } 95 | 96 | 97 | //MARK: 相机扫描 98 | extension JunVisionTool{ 99 | /// 相机扫描结果处理 100 | func visionScan(type: JunVisionDetectType, scanRect: CGRect, pixelBuffer: CVPixelBuffer, _ completionHandle: @escaping JunDetectHandle){ 101 | //1. 创建处理请求 102 | let faceHandle = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]) 103 | 104 | //2. 设置回调 105 | let completionHandle: VNRequestCompletionHandler = { request, error in 106 | let observations = request.results 107 | self.handleScanObservations(type: type, rect: scanRect, observations, completionHandle) 108 | } 109 | 110 | //3. 创建识别请求 111 | var baseRequest = VNImageBasedRequest() 112 | switch type { 113 | case .hotFace: 114 | baseRequest = VNDetectFaceRectanglesRequest(completionHandler: completionHandle) 115 | case .realAdd: 116 | baseRequest = VNDetectFaceLandmarksRequest(completionHandler: completionHandle) 117 | default: 118 | break 119 | } 120 | 121 | //4. 发送请求 122 | // 此处数据在不断地刷新, 必须在子线程执行,否则会堵塞主线程,导致app失去响应(亲自踩过的坑) 123 | DispatchQueue.global().async { 124 | do{ 125 | try faceHandle.perform([baseRequest]) 126 | }catch{ 127 | print("Throws:\(error)") 128 | } 129 | } 130 | } 131 | 132 | /// 处理扫描后的数据 133 | fileprivate func handleScanObservations(type: JunVisionDetectType, rect: CGRect, _ observations: [Any]?, _ completionHandle: JunDetectHandle){ 134 | switch type { 135 | case .hotFace: 136 | dynamicFaceScan(rect, observations, completionHandle) 137 | case .realAdd: 138 | addFaceScan(rect, observations, completionHandle) 139 | default: 140 | break 141 | } 142 | } 143 | } 144 | 145 | 146 | //MARK: 图像扫描方式 147 | extension JunVisionTool { 148 | /// 动态人脸识别 149 | fileprivate func dynamicFaceScan(_ rect: CGRect, _ observations: [Any]?, _ complecHandle: JunDetectHandle){ 150 | //1. 获取识别到的VNFaceObservation 151 | guard let boxArr = observations as? [VNFaceObservation] else { return } 152 | //2. 创建rect数组 153 | var bigRects = [CGRect](), faceArr = [FaceFeatureModel]() 154 | //3. 遍历识别结果 155 | for boxObj in boxArr { 156 | // 3.1 获取识别到的位置 157 | bigRects.append(convertRect(boxObj.boundingBox, rect)) 158 | } 159 | //4. 回调结果 160 | complecHandle(bigRects, faceArr) 161 | } 162 | 163 | /// 实时动态添加 164 | fileprivate func addFaceScan(_ rect: CGRect, _ observations: [Any]?, _ complecHandle: JunDetectHandle){ 165 | //1. 获取识别到的VNFaceObservation 166 | guard let boxArr = observations as? [VNFaceObservation] else { return } 167 | //2. 创建rect数组 168 | var faceArr = [FaceFeatureModel]() 169 | //3. 遍历识别结果 170 | for feature in boxArr { 171 | guard let landmarks = feature.landmarks else { return } 172 | let faceFeature = FaceFeatureModel(face: landmarks) 173 | faceFeature.faceObservation = feature 174 | faceArr.append(faceFeature) 175 | } 176 | //4. 回调结果 177 | complecHandle([], faceArr) 178 | } 179 | } 180 | 181 | 182 | //MARK: 图片识别方式 183 | extension JunVisionTool { 184 | /// 文字识别 185 | fileprivate func textDectect(_ observations: [Any]?, image: UIImage, _ complecHandle: JunDetectHandle){ 186 | //1. 获取识别到的VNTextObservation 187 | guard let boxArr = observations as? [VNTextObservation] else { return } 188 | 189 | //2. 创建rect数组 190 | var bigRects = [CGRect](), smallRects = [CGRect]() 191 | 192 | //3. 遍历识别结果 193 | for boxObj in boxArr { 194 | // 3.1 195 | bigRects.append(convertRect(boxObj.boundingBox, image)) 196 | //2. 获取 197 | guard let rectangleArr = boxObj.characterBoxes else { continue } 198 | for rectangle in rectangleArr{ 199 | //3. 得到每一个对象的尺寸 200 | let boundBox = rectangle.boundingBox 201 | smallRects.append(convertRect(boundBox, image)) 202 | } 203 | } 204 | 205 | //4. 回调结果 206 | complecHandle(bigRects, smallRects) 207 | } 208 | 209 | /// 条码识别 210 | fileprivate func codeDectect(_ observations: [Any]?, image: UIImage, _ complecHandle: JunDetectHandle){ 211 | //1. 获取识别到的VNRectangleObservation 212 | guard let boxArr = observations as? [VNBarcodeObservation] else { return } 213 | //2. 创建rect数组 214 | var bigRects = [CGRect](), codeArr = [CodeModel]() 215 | //3. 遍历识别结果 216 | for boxObj in boxArr { 217 | // 3.1 获取识别到的位置 218 | bigRects.append(convertRect(boxObj.boundingBox, image)) 219 | 220 | //3.2 获取每一个条码的信息 221 | codeArr.append(CodeModel(code: boxObj)) 222 | } 223 | //4. 回调结果 224 | complecHandle(bigRects, codeArr) 225 | 226 | } 227 | 228 | /// 特征识别 229 | fileprivate func faceFeatureDectect(_ observations: [Any]?, image: UIImage, _ complecHandle: JunDetectHandle){ 230 | //1. 获取识别到的VNRectangleObservation 231 | guard let boxArr = observations as? [VNFaceObservation] else { return } 232 | 233 | //2. 创建存储数组 234 | var faceArr = [FaceFeatureModel]() 235 | 236 | //3. 遍历所有特征 237 | for feature in boxArr { 238 | guard let landmarks = feature.landmarks else { return } 239 | let faceFeature = FaceFeatureModel(face: landmarks) 240 | faceFeature.faceObservation = feature 241 | faceArr.append(faceFeature) 242 | } 243 | 244 | //4. 回调 245 | complecHandle([], faceArr) 246 | } 247 | 248 | /// 矩形检测 249 | fileprivate func rectangleDectect(_ observations: [Any]?, image: UIImage, _ complecHandle: JunDetectHandle){ 250 | //1. 获取识别到的VNRectangleObservation 251 | guard let boxArr = observations as? [VNRectangleObservation] else { return } 252 | //2. 创建rect数组 253 | var bigRects = [CGRect]() 254 | //3. 遍历识别结果 255 | for boxObj in boxArr { 256 | // 3.1 257 | bigRects.append(convertRect(boxObj.boundingBox, image)) 258 | } 259 | //4. 回调结果 260 | complecHandle(bigRects, []) 261 | } 262 | 263 | /// 静态人脸识别 264 | fileprivate func staticFaceDectect(_ observations: [Any]?, image: UIImage, _ complecHandle: JunDetectHandle){ 265 | //1. 获取识别到的VNFaceObservation 266 | guard let boxArr = observations as? [VNFaceObservation] else { return } 267 | //2. 创建rect数组 268 | var bigRects = [CGRect]() 269 | //3. 遍历识别结果 270 | for boxObj in boxArr { 271 | // 3.1 272 | bigRects.append(convertRect(boxObj.boundingBox, image)) 273 | } 274 | //4. 回调结果 275 | complecHandle(bigRects, []) 276 | } 277 | 278 | } 279 | 280 | 281 | //MARK: 坐标转换和添加红框 282 | extension JunVisionTool{ 283 | /// image坐标转换 284 | fileprivate func convertRect(_ rectangleRect: CGRect, _ image: UIImage) -> CGRect { 285 | let imageSize = image.scaleImage() 286 | let w = rectangleRect.width * imageSize.width 287 | let h = rectangleRect.height * imageSize.height 288 | let x = rectangleRect.minX * imageSize.width 289 | //该Y坐标与UIView的Y坐标是相反的 290 | let y = (1 - rectangleRect.minY) * imageSize.height - h 291 | return CGRect(x: x, y: y, width: w, height: h) 292 | } 293 | 294 | /// rect坐标转换 295 | func convertRect(_ rectangleRect: CGRect, _ rect: CGRect) -> CGRect { 296 | let size = rect.size 297 | let w = rectangleRect.width * size.width 298 | let h = rectangleRect.height * size.height 299 | let x = rectangleRect.minX * size.width 300 | //该Y坐标与UIView的Y坐标是相反的 301 | let y = (1 - rectangleRect.maxY) * size.height 302 | return CGRect(x: x, y: y, width: w, height: h) 303 | } 304 | 305 | /// 正常坐标转成layer坐标 306 | func convertRect(viewRect: CGRect, layerRect: CGRect) -> CGRect{ 307 | let size = layerRect.size 308 | let w = viewRect.width / size.width 309 | let h = viewRect.height / size.height 310 | let x = viewRect.minX / size.width 311 | let y = 1 - viewRect.maxY / size.height 312 | return CGRect(x: x, y: y, width: w, height: h) 313 | } 314 | } 315 | 316 | 317 | 318 | /* 319 | * continue: 结束当前循环, 继续执行下一次循环 320 | * break: 结束所有操作, 直接跳出循环 321 | * return: 必须在函数内使用, 直接结束该函数 322 | */ 323 | 324 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/VisionTool/Tools/UIExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIExtension.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/23. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | import Vision 12 | 13 | //MARK: 全局属性 14 | /// 全局图像识别工具类 15 | let visionTool = JunVisionTool() 16 | /// 全局视图处理类 17 | let viewTool = JunViewTool() 18 | /// 屏幕的宽 19 | let kScreenWidth = UIScreen.main.bounds.size.width 20 | /// 屏幕的高 21 | let kScreenHeight = UIScreen.main.bounds.size.height 22 | /// 显示图片的imageView的宽高比 23 | let imageViewScale: CGFloat = 125 / 161 24 | 25 | 26 | 27 | 28 | //MARK: UIImage 29 | extension UIImage{ 30 | /// 图片压缩到指定大小 31 | public func scaleImage() -> CGSize { 32 | //1. 图片的宽高比 33 | let imageScale = size.width / size.height 34 | var imageWidth: CGFloat = 1 35 | var imageHeight: CGFloat = 1 36 | if imageScale >= imageViewScale { 37 | imageWidth = kScreenWidth 38 | imageHeight = imageWidth / imageScale 39 | }else{ 40 | imageHeight = kScreenWidth / imageViewScale 41 | imageWidth = imageHeight * imageScale 42 | } 43 | 44 | return CGSize(width: imageWidth, height: imageHeight) 45 | } 46 | } 47 | 48 | 49 | //MARK: String 50 | extension String { 51 | public func show() { 52 | guard let window = UIApplication.shared.keyWindow else { return } 53 | if self.isEmpty { return } 54 | 55 | for view in window.subviews where view.tag == 33 { 56 | view.removeFromSuperview() 57 | } 58 | let blackView = UIView() 59 | blackView.backgroundColor = UIColor.black 60 | blackView.layer.cornerRadius = 2 61 | blackView.layer.masksToBounds = true 62 | blackView.tag = 33 63 | window.addSubview(blackView) 64 | 65 | let textLabel = UILabel(frame: CGRect(x: 10, y: 5, width: 0, height: 0)) 66 | textLabel.text = self 67 | textLabel.numberOfLines = 0 68 | textLabel.textColor = UIColor.white 69 | textLabel.textAlignment = .center 70 | textLabel.backgroundColor = UIColor.clear 71 | textLabel.font = UIFont.systemFont(ofSize: 14) 72 | blackView.addSubview(textLabel) 73 | 74 | let size = (self as NSString).boundingRect(with: CGSize(width: kScreenWidth / 3 * 2, height: CGFloat(HUGE)), options: .usesLineFragmentOrigin, attributes: [.font: UIFont.systemFont(ofSize: 14)], context: nil).size 75 | textLabel.frame = CGRect(x: 10, y: 5, width: size.width, height: size.height) 76 | blackView.frame = CGRect(x: (kScreenWidth - textLabel.frame.width - 20) / 2, y: (kScreenHeight - textLabel.frame.height - 10) / 2, width: textLabel.frame.width + 20, height: textLabel.frame.height + 10) 77 | 78 | UIView.animate(withDuration: 0.5, delay: 3, options: .curveLinear, animations: { 79 | blackView.alpha = 0 80 | }) { (finished) in 81 | blackView.removeFromSuperview() 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/动态人脸识别/DynamicFaceViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicFaceViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/23. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | import Vision 12 | 13 | class DynamicFaceViewController: ScanBaseViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | title = "动态人脸识别" 19 | } 20 | } 21 | 22 | //处理扫描结果 23 | extension DynamicFaceViewController{ 24 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 25 | //0. 清除所有红框 26 | for subView in cleanView.subviews { 27 | subView.removeFromSuperview() 28 | } 29 | 30 | //1. 获取CVPixelBuffer对象 31 | guard let cvBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } 32 | guard let input = self.deviceInput else { "获取设备失败".show(); return } 33 | 34 | //2. 获取扫描结果 35 | visionTool.visionScan(type: .hotFace, scanRect: previewLayer.bounds, pixelBuffer: cvBuffer) { (bigArr, smallArr) in 36 | //2.1. 识别到的大区域 37 | if let rectArray = bigArr { 38 | for textRect in rectArray{ 39 | DispatchQueue.main.async { 40 | self.cleanView.addSubview(viewTool.addRectangleView(rect: textRect, input.device.position)) 41 | } 42 | } 43 | } 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/实时动态添加/RealAddViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealAddViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/23. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | import Vision 12 | 13 | class RealAddViewController: ScanBaseViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | title = "实时动态添加" 19 | } 20 | } 21 | 22 | //处理扫描结果 23 | extension RealAddViewController { 24 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 25 | //0. 清除所有红框 26 | for subView in cleanView.subviews { 27 | subView.removeFromSuperview() 28 | } 29 | 30 | //1. 获取CVPixelBuffer对象 31 | guard let cvBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } 32 | guard let input = self.deviceInput else { return } 33 | 34 | //2. 获取扫描结果 35 | visionTool.visionScan(type: .realAdd, scanRect: previewLayer.bounds, pixelBuffer: cvBuffer) { (bigArr, smallArr) in 36 | //2.1. 识别到的大区域 37 | if let faceArr = smallArr as? [FaceFeatureModel] { 38 | for facemodel in faceArr{ 39 | DispatchQueue.main.async { 40 | // 获取转换后的坐标 41 | let rect = self.getEyePoint(faceModel: facemodel, position: input.device.position) 42 | self.cleanView.addSubview(viewTool.addEyeImageView(rect: rect)) 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | 51 | //MARK: 眼睛的坐标 52 | extension RealAddViewController{ 53 | /// H偶去转换后的尺寸坐标 54 | fileprivate func getEyePoint(faceModel: FaceFeatureModel, position: AVCaptureDevice.Position) -> CGRect{ 55 | //1. 获取左右眼 56 | guard let leftEye = faceModel.leftEye else { return CGRect.zero } 57 | guard let rightEye = faceModel.rightEye else { return CGRect.zero } 58 | 59 | //2. 位置数组 60 | let leftPoint = conventPoint(landmark: leftEye, faceRect: faceModel.faceObservation.boundingBox, position: position) 61 | let rightPoint = conventPoint(landmark: rightEye, faceRect: faceModel.faceObservation.boundingBox, position: position) 62 | 63 | //3. 排序 64 | let pointXs = (leftPoint.0 + rightPoint.0).sorted() 65 | let pointYs = (leftPoint.1 + rightPoint.1).sorted() 66 | 67 | //4. 添加眼睛 68 | let image = UIImage(named: "eyes")! 69 | let imageWidth = (pointXs.last ?? 0.0) - (pointXs.first ?? 0) + 40 70 | let imageHeight = image.size.height / image.size.width * imageWidth 71 | 72 | return CGRect(x: (pointXs.first ?? 0) - 20, y: (pointYs.first ?? 0) - 5, width: imageWidth, height: imageHeight) 73 | } 74 | 75 | /// 坐标转换 76 | fileprivate func conventPoint(landmark: VNFaceLandmarkRegion2D, faceRect: CGRect, position: AVCaptureDevice.Position) -> ([CGFloat], [CGFloat]){ 77 | //1. 定义 78 | var XArray = [CGFloat](), YArray = [CGFloat]() 79 | let viewRect = previewLayer.frame 80 | 81 | //2. 遍历 82 | for i in 0..= 0.3 else { 96 | self.redView.frame = .zero 97 | return 98 | } 99 | 100 | //4. 坐标转换 101 | let newRect = newObservation.boundingBox 102 | let convertRect = visionTool.convertRect(newRect, self.previewLayer.frame) 103 | self.redView.frame = convertRect 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/文字识别/TextViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/23. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TextViewController: DectectBaseViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | title = "文字识别" 17 | } 18 | 19 | //选择图片 20 | //开始识别 21 | @objc override func startRecognitionAction(_ sender: Any) { 22 | super.startRecognitionAction(sender) 23 | 24 | guard let image = selectorImage else { return } 25 | visionTool.visionDetectImage(type: .text, image: image) { (bigRects, smallRects) in 26 | //2. 识别到的大区域(暂不显示) 27 | // guard let rectArr = bigRects else { return } 28 | // for textRect in rectArr{ 29 | // DispatchQueue.main.async { 30 | // self.cleanView.addSubview(viewTool.addRectangleView(rect: textRect)) 31 | // } 32 | // } 33 | 34 | //3. 识别到的小区域 35 | guard let smallArr = smallRects as? [CGRect] else { return } 36 | for textRect in smallArr{ 37 | DispatchQueue.main.async { 38 | self.cleanView.addSubview(viewTool.addRectangleView(rect: textRect)) 39 | } 40 | } 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/条码识别/CodeModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeModel.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/25. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Vision 11 | 12 | class CodeModel: NSObject { 13 | /// 条码类型 14 | var symbology: VNBarcodeSymbology? 15 | /// 条码数据 16 | var barcodeDescriptor: CIBarcodeDescriptor? 17 | /// 条码链接(一般是网址) 18 | var payloadStringValue: String? 19 | 20 | 21 | init(code: VNBarcodeObservation) { 22 | super.init() 23 | 24 | symbology = code.symbology 25 | barcodeDescriptor = code.barcodeDescriptor 26 | payloadStringValue = code.payloadStringValue 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/条码识别/CodeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeViewController.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/25. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CodeViewController: DectectBaseViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | title = "条码识别" 17 | } 18 | } 19 | 20 | extension CodeViewController{ 21 | override func startRecognitionAction(_ sender: Any) { 22 | super.startRecognitionAction(sender) 23 | 24 | guard let image = selectorImage else { "未获取到图片".show(); return } 25 | 26 | visionTool.visionDetectImage(type: .code, image: image) { (rectArr, dataArr) in 27 | DispatchQueue.main.async { 28 | //1. 识别到的大区域 29 | guard let rectArray = rectArr else { "未识别到条码".show(); return } 30 | for textRect in rectArray{ 31 | self.cleanView.addSubview(viewTool.addRectangleView(rect: textRect)) 32 | } 33 | 34 | //2. 识别到的条码信息 35 | guard let codeArr = dataArr as? [CodeModel] else { "未识别到条码信息".show(); return } 36 | for code in codeArr{ 37 | print(code.payloadStringValue ?? "") 38 | self.handleCodeInfo(code: code) 39 | } 40 | } 41 | } 42 | } 43 | 44 | /// 处理条码信息 45 | fileprivate func handleCodeInfo(code: CodeModel){ 46 | //1. 获取条码类型 47 | guard let type = code.symbology else { return } 48 | 49 | //2. 执行不同的操作 50 | switch type { 51 | case .QR: 52 | qrCodeHandle(barCode: code.barcodeDescriptor) 53 | default: 54 | break 55 | } 56 | } 57 | 58 | /// 二维码信息处理 59 | fileprivate func qrCodeHandle(barCode: CIBarcodeDescriptor?){ 60 | //1. 转成对应的条码对象 61 | guard let code = barCode as? CIQRCodeDescriptor else { return } 62 | 63 | //2. 解读条码信息 64 | let level = code.errorCorrectionLevel.hashValue 65 | let version = code.symbolVersion 66 | let mask = code.maskPattern 67 | let data = code.errorCorrectedPayload 68 | let dataStr = String(data: data, encoding: .utf8) 69 | print("这是二维码信息--", level, "---", version, "----", mask, "---", dataStr ?? "") 70 | } 71 | } 72 | 73 | /* 纠错等级 74 | public enum ErrorCorrectionLevel : Int { 75 | 76 | case levelL 77 | 78 | case levelM 79 | 80 | case levelQ 81 | 82 | case levelH 83 | } 84 | */ 85 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/特征识别/FaceFeatureModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FaceFeatureModel.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/25. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Vision 11 | 12 | class FaceFeatureModel: NSObject { 13 | /// 脸部轮廓 14 | var faceContour: VNFaceLandmarkRegion2D? 15 | 16 | /// 左眼, 右眼 17 | var leftEye: VNFaceLandmarkRegion2D? 18 | var rightEye: VNFaceLandmarkRegion2D? 19 | 20 | /// 左睫毛, 右睫毛 21 | var leftEyebrow: VNFaceLandmarkRegion2D? 22 | var rightEyebrow: VNFaceLandmarkRegion2D? 23 | 24 | /// 左眼瞳, 右眼瞳 25 | var leftPupil: VNFaceLandmarkRegion2D? 26 | var rightPupil: VNFaceLandmarkRegion2D? 27 | 28 | /// 鼻子, 鼻嵴, 正中线 29 | var nose: VNFaceLandmarkRegion2D? 30 | var noseCrest: VNFaceLandmarkRegion2D? 31 | var medianLine: VNFaceLandmarkRegion2D? 32 | 33 | /// 外唇, 内唇 34 | var outerLips: VNFaceLandmarkRegion2D? 35 | var innerLips: VNFaceLandmarkRegion2D? 36 | 37 | /// 所有属性数组 38 | var landmarkArr = [VNFaceLandmarkRegion2D?]() 39 | 40 | /// face对象 41 | var faceObservation = VNFaceObservation() 42 | 43 | 44 | 45 | /// 初始化方法 46 | init(face: VNFaceLandmarks2D) { 47 | super.init() 48 | 49 | faceContour = face.faceContour 50 | 51 | leftEye = face.leftEye 52 | rightEye = face.rightEye 53 | 54 | leftEyebrow = face.leftEyebrow 55 | rightEyebrow = face.rightEyebrow 56 | 57 | leftPupil = face.leftPupil 58 | rightPupil = face.rightPupil 59 | 60 | nose = face.nose 61 | noseCrest = face.noseCrest 62 | medianLine = face.medianLine 63 | 64 | outerLips = face.outerLips 65 | innerLips = face.innerLips 66 | 67 | //添加到数组中 68 | landmarkArr.append(faceContour) 69 | 70 | landmarkArr.append(leftEye) 71 | landmarkArr.append(rightEye) 72 | 73 | landmarkArr.append(leftEyebrow) 74 | landmarkArr.append(rightEyebrow) 75 | 76 | landmarkArr.append(leftPupil) 77 | landmarkArr.append(rightPupil) 78 | 79 | landmarkArr.append(nose) 80 | landmarkArr.append(noseCrest) 81 | landmarkArr.append(medianLine) 82 | 83 | landmarkArr.append(outerLips) 84 | landmarkArr.append(innerLips) 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFace/特征识别/FaceFeatureView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FaceFeatureView.swift 3 | // JunVisionFace 4 | // 5 | // Created by iOS_Tian on 2017/11/25. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class FaceFeatureView: UIView { 12 | var faceArr: [FaceFeatureModel]! 13 | 14 | init(frame: CGRect, faceArr: [FaceFeatureModel]) { 15 | super.init(frame: frame) 16 | 17 | self.faceArr = faceArr 18 | 19 | backgroundColor = UIColor.clear 20 | } 21 | 22 | required init?(coder aDecoder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | override func draw(_ rect: CGRect) { 27 | super.draw(rect) 28 | 29 | //0. 遍历所有人脸对象 30 | for faceModel in faceArr { 31 | //1. 获取当前图片和face对象 32 | let faceObser = faceModel.faceObservation 33 | 34 | //3. 获取脸部尺寸 35 | let faceRect = faceObser.boundingBox 36 | 37 | //4. 遍历所有特征 38 | for landmark in faceModel.landmarkArr{ 39 | // 4.1 获取VNFaceLandmarkRegion2D对象 40 | guard let landmark2D = landmark else { continue } 41 | 42 | //4.2 遍历所有的像素点的坐标 43 | var pointArr = [CGPoint]() 44 | for i in 0.. 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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFaceTests/JunVisionFaceTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JunVisionFaceTests.swift 3 | // JunVisionFaceTests 4 | // 5 | // Created by iOS_Tian on 2017/11/22. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import JunVisionFace 11 | 12 | class JunVisionFaceTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFaceUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /JunVisionFace/JunVisionFaceUITests/JunVisionFaceUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JunVisionFaceUITests.swift 3 | // JunVisionFaceUITests 4 | // 5 | // Created by iOS_Tian on 2017/11/22. 6 | // Copyright © 2017年 CoderJun. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class JunVisionFaceUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 coderQuanjun 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JunVisionFace 2 | ## Demo支持 3 | - 文字识别 4 | - 矩形识别 5 | - 条码识别 6 | - 人脸特征识别 7 | - 静态人脸识别 8 | - 动态人脸识别 9 | - 实时动态添加 10 | - 对象检测和跟踪 11 | 12 | ##### 简书地址: [Swift之Vision 图像识别框架](http://www.jianshu.com/p/08174663d2e9) 13 | ##### CSDN博客地址: [Swift之Vision 图像识别框架](http://blog.csdn.net/ShmilyCoder/article/details/78667041) 14 | 15 | 16 | # Swift之Vision 图像识别框架 17 | 18 | - 2017年苹果大大又推出了新机型iPhone 8和iPhone 8Plus, 这还不是重点, 重点是那一款价值9000RMB的iPhone X, 虽说网上吐槽声从未停止过, 但是我觉得还是不错的哈! 19 | - 软件方面, 苹果大大也推出了iOS 11, 经本人iPhone 7手机亲测, 耗电快外加通知栏改不完的bug 20 | - 当然了随着iOS 11的推出, 也随之推出了一些新的API,如:[`ARKit`](https://developer.apple.com/documentation/arkit) 、[`Core ML`](https://developer.apple.com/documentation/coreml)、[`FileProvider`](https://developer.apple.com/documentation/fileprovider)、[`IdentityLookup`](https://developer.apple.com/documentation/identitylookup) 、[`Core NFC`](https://developer.apple.com/documentation/corenfc)、[`Vison`](https://developer.apple.com/documentation/vision) 等。 21 | - 这里我们还要说的就是Apple 在 WWDC 2017 推出的图像识别框架--`Vison`[官方文档](https://developer.apple.com/documentation/vision) 22 | - [Demo地址](https://github.com/coderQuanjun/JunVisionFace) 23 | 24 | ## 一. Vision应用场景 25 | - `Face Detection and Recognition` : 人脸检测 26 | - 支持检测笑脸、侧脸、局部遮挡脸部、戴眼镜和帽子等场景,可以标记出人脸的矩形区域 27 | - 可以标记出人脸和眼睛、眉毛、鼻子、嘴、牙齿的轮廓,以及人脸的中轴线 28 | - `Image Alignment Analysis`: 图像对比分析 29 | - `Barcode Detection`: 二维码/条形码检测 30 | - 用于查找和识别图像中的条码 31 | - 检测条形码信息 32 | - `Text Detection`: 文字检测 33 | - 查找图像中可见文本的区域 34 | - 检测文本区域的信息 35 | - `Object Detection and Tracking`: 目标跟踪 36 | - 脸部,矩形和通用模板 37 | 38 | ## 二. Vision支持的图片类型 39 | ### 1. Objective-C中 40 | - `CVPixelBufferRef` 41 | - `CGImageRef` 42 | - `CIImage` 43 | - `NSURL` 44 | - `NSData` 45 | 46 | ### 2. Swift中 47 | - `CVPixelBuffer` 48 | - `CGImage` 49 | - `CIImage` 50 | - `URL` 51 | - `Data` 52 | 53 | > 具体详情可在`Vision.framework`的`VNImageRequestHandler.h`文件中查看 54 | 55 | ## 三. Vision之API介绍 56 | - 使用在`vision`的时候,我们首先需要明确自己需要什么效果,然后根据想要的效果来选择不同的类 57 | - 给各种功能的 `Request` 提供给一个 `RequestHandler` 58 | - `Handler` 持有需要识别的图片信息,并将处理结果分发给每个 `Request` 的 `completion Block` 中 59 | - 可以从 `results` 属性中得到 `Observation` 数组 60 | - `observations`数组中的内容根据不同的request请求返回了不同的`observation` 61 | - 每种`Observation`有`boundingBox`,`landmarks`等属性,存储的是识别后物体的坐标,点位等 62 | - 我们拿到坐标后,就可以进行一些UI绘制。 63 | 64 | ### 1. `RequestHandler`处理请求对象 65 | - `VNImageRequestHandler`: 处理与单个图像有关的一个或多个图像分析请求的对象 66 | - 一般情况下都是用该类处理识别请求 67 | - 初始化方法支持`CVPixelBuffer`, `CGImage`, `CIImage`, `URL`, `Data` 68 | - `VNSequenceRequestHandler`: 处理与多个图像序列有关的图像分析请求的对象 69 | - 目前我在处理物体跟踪的时候使用该类 70 | - 初始化方法同上 71 | 72 | ### 2. VNRequest介绍 73 | - `VNRequest`: 图像分析请求的抽象类, 继承于`NSObject` 74 | - `VNBaseImageRequest`: 专注于图像的特定部分的分析请求 75 | - 具体分析请求类如下: 76 | - 77 | ![VNImageBasedRequest.png](http://upload-images.jianshu.io/upload_images/4122543-b58783bec9d07551.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 78 | 79 | ### 3. `VNObservation`检测对象 80 | - `VNObservation`: 图像分析结果的抽象类, 继承与`NSObject` 81 | - 图像检测结果的相关处理类如下: 82 | - 83 | ![VNObservation.png](http://upload-images.jianshu.io/upload_images/4122543-c0b83aa723e149ab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 84 | 85 | 86 | ## 四. 实战演练 87 | ### 1. 文本检测 88 | - 方式一: 识别出具体的每一个字体的位置信息 89 | - 方式二: 识别一行字体的位置信息 90 | - 如图效果: 91 | - 92 | ![WechatIMG3.jpeg](http://upload-images.jianshu.io/upload_images/4122543-0c09426c80013322.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300) 93 | 94 | ![WechatIMG5.jpeg](http://upload-images.jianshu.io/upload_images/4122543-8b970c464c26ffb0.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/300) 95 | 96 | #### 1.1 现将图片转成初始化`VNImageRequestHandler`对象时, 可接受的的`CIImage` 97 | 98 | ``` 99 | //1. 转成ciimage 100 | guard let ciImage = CIImage(image: image) else { return } 101 | ``` 102 | 103 | #### 1.2 创建处理请求的handle 104 | - 参数一: 图片类型 105 | - 参数二: 字典类型, 有默认值为[:] 106 | 107 | ``` 108 | let requestHandle = VNImageRequestHandler(ciImage: ciImage, options: [:]) 109 | ``` 110 | 111 | #### 1.3 创建回调闭包 112 | - 两个参数, 无返回值 113 | - `VNRequest`: 是所有请求Request的父类 114 | 115 | ``` 116 | public typealias VNRequestCompletionHandler = (VNRequest, Error?) -> Swift.Void 117 | 118 | ``` 119 | - 具体代码如下: 120 | 121 | ```objc 122 | //4. 设置回调 123 | let completionHandle: VNRequestCompletionHandler = { request, error in 124 | let observations = request.results 125 | //识别出来的对象数组 126 | } 127 | 128 | ``` 129 | 130 | #### 1.4 创建识别请求 131 | - 两种初始化方式 132 | 133 | ```objc 134 | //无参数 135 | public convenience init() 136 | 137 | //闭包参数 138 | public init(completionHandler: Vision.VNRequestCompletionHandler? = nil) 139 | 140 | ``` 141 | - 这里使用带闭包的初始化方式 142 | 143 | ``` 144 | let baseRequest = VNDetectTextRectanglesRequest(completionHandler: completionHandle) 145 | ``` 146 | 147 | - 属性设置(是否识别具体的每一个文字) 148 | 149 | ``` 150 | // 设置识别具体文字 151 | baseRequest.setValue(true, forKey: "reportCharacterBoxes") 152 | ``` 153 | - 不设置该属性, 识别出来的是一行文字 154 | 155 | #### 1.5 发送请求 156 | 157 | ``` 158 | open func perform(_ requests: [VNRequest]) throws 159 | ``` 160 | 161 | - 该方法会抛出一个异常错误 162 | - 在连续不断(摄像头扫描)发送请求过程中, 必须在子线程执行该方法, 否则会造成线程堵塞 163 | 164 | ```objc 165 | //6. 发送请求 166 | DispatchQueue.global().async { 167 | do{ 168 | try requestHandle.perform([baseRequest]) 169 | }catch{ 170 | print("Throws:\(error)") 171 | } 172 | } 173 | 174 | ``` 175 | 176 | #### 1.6 处理识别的`Observations`对象 177 | - 识别出来的`results`是`[Any]?`类型 178 | - 根据`boundingBox`属性可以获取到对应的文本区域的尺寸 179 | - 需要注意的是: 180 | - `boundingBox`得到的是相对iamge的比例尺寸, 都是小于1的 181 | - Y轴坐标于UIView坐标系是相反的 182 | 183 | ```objc 184 | //1. 获取识别到的VNTextObservation 185 | guard let boxArr = observations as? [VNTextObservation] else { return } 186 | 187 | //2. 创建rect数组 188 | var bigRects = [CGRect](), smallRects = [CGRect]() 189 | 190 | //3. 遍历识别结果 191 | for boxObj in boxArr { 192 | // 3.1尺寸转换 193 | //获取一行文本的区域位置 194 | bigRects.append(convertRect(boxObj.boundingBox, image)) 195 | 196 | //2. 获取 197 | guard let rectangleArr = boxObj.characterBoxes else { continue } 198 | for rectangle in rectangleArr{ 199 | //3. 得到每一个字体的的尺寸 200 | let boundBox = rectangle.boundingBox 201 | smallRects.append(convertRect(boundBox, image)) 202 | } 203 | } 204 | 205 | ``` 206 | 207 | > 坐标转换 208 | 209 | ```objc 210 | /// image坐标转换 211 | fileprivate func convertRect(_ rectangleRect: CGRect, _ image: UIImage) -> CGRect { 212 | //此处是将Image的实际尺寸转化成imageView的尺寸 213 | let imageSize = image.scaleImage() 214 | let w = rectangleRect.width * imageSize.width 215 | let h = rectangleRect.height * imageSize.height 216 | let x = rectangleRect.minX * imageSize.width 217 | //该Y坐标与UIView的Y坐标是相反的 218 | let y = (1 - rectangleRect.minY) * imageSize.height - h 219 | return CGRect(x: x, y: y, width: w, height: h) 220 | } 221 | 222 | ``` 223 | 224 | ### 2. 矩形识别和静态人脸识别 225 | - 识别图像中的矩形 226 | - 227 | ![1511935758595.jpg](http://upload-images.jianshu.io/upload_images/4122543-05e6a9cc6c193b1d.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/400) 228 | 229 | - 静态人脸识别 230 | - 231 | ![1511936019734.jpg](http://upload-images.jianshu.io/upload_images/4122543-e5faf93cebae945e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/400) 232 | 233 | - 主要核心代码 234 | - 235 | 236 | ``` 237 | //1. 转成ciimage 238 | guard let ciImage = CIImage(image: image) else { return } 239 | 240 | //2. 创建处理request 241 | let requestHandle = VNImageRequestHandler(ciImage: ciImage, options: [:]) 242 | 243 | //3. 创建baseRequest 244 | //大多数识别请求request都继承自VNImageBasedRequest 245 | var baseRequest = VNImageBasedRequest() 246 | 247 | //4. 设置回调 248 | let completionHandle: VNRequestCompletionHandler = { request, error in 249 | let observations = request.results 250 | self.handleImageObservable(type: type, image: image, observations, completeBack) 251 | } 252 | 253 | //5. 创建识别请求 254 | switch type { 255 | case .rectangle: 256 | baseRequest = VNDetectRectanglesRequest(completionHandler: completionHandle) 257 | case .staticFace: 258 | baseRequest = VNDetectFaceRectanglesRequest(completionHandler: completionHandle) 259 | default: 260 | break 261 | } 262 | 263 | ``` 264 | 265 | - 处理识别的observation 266 | 267 | ```objc 268 | /// 矩形检测 269 | fileprivate func rectangleDectect(_ observations: [Any]?, image: UIImage, _ complecHandle: JunDetectHandle){ 270 | //1. 获取识别到的VNRectangleObservation 271 | guard let boxArr = observations as? [VNRectangleObservation] else { return } 272 | //2. 创建rect数组 273 | var bigRects = [CGRect]() 274 | //3. 遍历识别结果 275 | for boxObj in boxArr { 276 | // 3.1 277 | bigRects.append(convertRect(boxObj.boundingBox, image)) 278 | } 279 | //4. 回调结果 280 | complecHandle(bigRects, []) 281 | } 282 | 283 | ``` 284 | 285 | - 静态人脸识别需要将`observation`转成`VNFaceObservation` 286 | 287 | ``` 288 | guard let boxArr = observations as? [VNFaceObservation] else { return } 289 | ``` 290 | 291 | ### 3. 条码识别 292 | 293 | ![1511936988374.jpg](http://upload-images.jianshu.io/upload_images/4122543-9f199a027f186a5c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/400) 294 | 295 | - 这里请求的步骤与矩形识别相同, 这里不再赘述 296 | - 需要注意的是,在初始化request的时候需要设一个置可识别的条码类型参数 297 | - 这里先看一下`VNDetectBarcodesRequest`的两个参数 298 | 299 | ``` 300 | //支持的可识别的条码类型(需要直接用class调用) 301 | open class var supportedSymbologies: [VNBarcodeSymbology] { get } 302 | 303 | //设置可识别的条码类型 304 | open var symbologies: [VNBarcodeSymbology] 305 | ``` 306 | 307 | - 此处设置可识别到的条码类型为, 该请求支持是别的所有类型, 如下 308 | - 注意`supportedSymbologies`参数的调用方法 309 | 310 | ```objc 311 | let request = VNDetectBarcodesRequest(completionHandler: completionHandle) 312 | request.symbologies = VNDetectBarcodesRequest.supportedSymbologies 313 | ``` 314 | 315 | - 条码识别不但能识别条码的位置信息, 还可以识别出条码的相关信息, 这里以二维码为例 316 | - 这里需要将识别的`observations`转成`[VNBarcodeObservation]` 317 | - `VNBarcodeObservation`有三个属性 318 | 319 | ```objc 320 | //条码类型: qr, code128....等等 321 | open var symbology: VNBarcodeSymbology { get } 322 | 323 | //条码的相关信息 324 | open var barcodeDescriptor: CIBarcodeDescriptor? { get } 325 | 326 | //如果是二维码, 则是二维码的网址链接 327 | open var payloadStringValue: String? { get } 328 | ``` 329 | 330 | - 如上述图片识别出来的`payloadStringValue`参数则是小编的[简书地址](http://www.jianshu.com/u/5bd5e9ed569e) 331 | - 下面是以上述图片的二维码为例处理的`CIBarcodeDescriptor`对象 332 | - 有兴趣的可以仔细研究研究 333 | 334 | ```objc 335 | /// 二维码信息处理 336 | fileprivate func qrCodeHandle(barCode: CIBarcodeDescriptor?){ 337 | //1. 转成对应的条码对象 338 | guard let code = barCode as? CIQRCodeDescriptor else { return } 339 | 340 | //2. 解读条码信息 341 | let level = code.errorCorrectionLevel.hashValue 342 | let version = code.symbolVersion 343 | let mask = code.maskPattern 344 | let data = code.errorCorrectedPayload 345 | let dataStr = String(data: data, encoding: .utf8) 346 | print("这是二维码信息--", level, "---", version, "----", mask, "---", dataStr ?? "") 347 | } 348 | 349 | ``` 350 | 351 | ### 4. 人脸特征识别 352 | - 可识别出人脸的轮廓, 眼睛, 鼻子, 嘴巴等具体位置 353 | - 354 | ![1511944652200.jpg](http://upload-images.jianshu.io/upload_images/4122543-895670df5fd8e2c9.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/400) 355 | 356 | 357 | - `VNFaceLandmarks2D`介绍 358 | - 359 | 360 | ```objc 361 | /// 脸部轮廓 362 | var faceContour: VNFaceLandmarkRegion2D? 363 | 364 | /// 左眼, 右眼 365 | var leftEye: VNFaceLandmarkRegion2D? 366 | var rightEye: VNFaceLandmarkRegion2D? 367 | 368 | /// 左睫毛, 右睫毛 369 | var leftEyebrow: VNFaceLandmarkRegion2D? 370 | var rightEyebrow: VNFaceLandmarkRegion2D? 371 | 372 | /// 左眼瞳, 右眼瞳 373 | var leftPupil: VNFaceLandmarkRegion2D? 374 | var rightPupil: VNFaceLandmarkRegion2D? 375 | 376 | /// 鼻子, 鼻嵴, 正中线 377 | var nose: VNFaceLandmarkRegion2D? 378 | var noseCrest: VNFaceLandmarkRegion2D? 379 | var medianLine: VNFaceLandmarkRegion2D? 380 | 381 | /// 外唇, 内唇 382 | var outerLips: VNFaceLandmarkRegion2D? 383 | var innerLips: VNFaceLandmarkRegion2D? 384 | ``` 385 | 386 | ``` 387 | //某一部位所有的像素点 388 | @nonobjc public var normalizedPoints: [CGPoint] { get } 389 | 390 | //某一部位的所有像素点的个数 391 | open var pointCount: Int { get } 392 | ``` 393 | 394 | - 将所有的像素点坐标转换成image对应的尺寸坐标 395 | - 使用图像上下文, 对应部位画线 396 | - 在UIView中重写`func draw(_ rect: CGRect)`方法 397 | - 398 | 399 | ```objc 400 | //5.1 获取当前上下文 401 | let content = UIGraphicsGetCurrentContext() 402 | 403 | //5.2 设置填充颜色(setStroke设置描边颜色) 404 | UIColor.green.set() 405 | 406 | //5.3 设置宽度 407 | content?.setLineWidth(2) 408 | 409 | //5.4. 设置线的类型(连接处) 410 | content?.setLineJoin(.round) 411 | content?.setLineCap(.round) 412 | 413 | //5.5. 设置抗锯齿效果 414 | content?.setShouldAntialias(true) 415 | content?.setAllowsAntialiasing(true) 416 | 417 | //5.6 开始绘制 418 | content?.addLines(between: pointArr) 419 | content?.drawPath(using: .stroke) 420 | 421 | //5.7 结束绘制 422 | content?.strokePath() 423 | ``` 424 | 425 | ### 5. 动态人脸识别和实时动态添加 426 | > 由于真机不好录制gif图(尝试了一下, 效果不是很好, 放弃了), 想看效果的朋友[下载源码](https://github.com/coderQuanjun/JunVisionFace)真机运行吧 427 | 428 | - `request`的初始化这里就不做介绍了, 说一下`handle`的初始化方法 429 | - `CVPixelBuffer`: 扫描实时输出的对象 430 | 431 | ``` 432 | //1. 创建处理请求 433 | let faceHandle = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]) 434 | 435 | ``` 436 | 437 | - 主要强调一点, 相机扫描, 获取实时图像的过程, 必须在子线程执行, 否在会堵塞线程, 整个app失去响应, 亲自踩过的坑 438 | 439 | ``` 440 | DispatchQueue.global().async { 441 | do{ 442 | try faceHandle.perform([baseRequest]) 443 | }catch{ 444 | print("Throws:\(error)") 445 | } 446 | } 447 | ``` 448 | 449 | #### 扫描结果处理 450 | - 动态人脸识别和静态人脸识别不同的地方就是, 动态实时刷新, 更新UI, 所以处理结果的方法相同 451 | - 动态添加: 这里处理方式是添加一个眼镜效果 452 | - 这里需要获取到两只眼睛的位置和宽度 453 | - 先获取到左右眼的所有的像素点和像素点的个数 454 | - 遍历所有的像素点, 转换成合适的坐标 455 | - 将左右眼的所有的point, 分别获取X和Y坐标放到不同的数组 456 | - 将数组有小到大排序, 得到X的最大和最小的差值, Y的最大和最小的差值 457 | - 具体代码如下 458 | 459 | ```objc 460 | /// H偶去转换后的尺寸坐标 461 | fileprivate func getEyePoint(faceModel: FaceFeatureModel, position: AVCaptureDevice.Position) -> CGRect{ 462 | //1. 获取左右眼 463 | guard let leftEye = faceModel.leftEye else { return CGRect.zero } 464 | guard let rightEye = faceModel.rightEye else { return CGRect.zero } 465 | 466 | //2. 位置数组 467 | let leftPoint = conventPoint(landmark: leftEye, faceRect: faceModel.faceObservation.boundingBox, position: position) 468 | let rightPoint = conventPoint(landmark: rightEye, faceRect: faceModel.faceObservation.boundingBox, position: position) 469 | 470 | //3. 排序 471 | let pointXs = (leftPoint.0 + rightPoint.0).sorted() 472 | let pointYs = (leftPoint.1 + rightPoint.1).sorted() 473 | 474 | //4. 添加眼睛 475 | let image = UIImage(named: "eyes")! 476 | let imageWidth = (pointXs.last ?? 0.0) - (pointXs.first ?? 0) + 40 477 | let imageHeight = image.size.height / image.size.width * imageWidth 478 | 479 | return CGRect(x: (pointXs.first ?? 0) - 20, y: (pointYs.first ?? 0) - 5, width: imageWidth, height: imageHeight) 480 | } 481 | 482 | ``` 483 | 484 | - 每一只眼睛的坐标处理 485 | 486 | ```objc 487 | /// 坐标转换 488 | fileprivate func conventPoint(landmark: VNFaceLandmarkRegion2D, faceRect: CGRect, position: AVCaptureDevice.Position) -> ([CGFloat], [CGFloat]){ 489 | //1. 定义 490 | var XArray = [CGFloat](), YArray = [CGFloat]() 491 | let viewRect = previewLayer.frame 492 | 493 | //2. 遍历 494 | for i in 0.. 以上就是iOS 11的新框架Vision在Swift中的所有使用的情况 576 | - 文中所列的内容可能有点空洞, 也稍微有点乱 577 | - 小编也是刚接触Vision, 文中如有解释不全, 或者错误的地方, 还请不吝赐教 578 | 579 | 580 | --- 581 | 582 | ### GitHub--[Demo地址](https://github.com/coderQuanjun/JunVisionFace) 583 | 584 | - 注意: 585 | - 这里只是列出了主要的核心代码,具体的代码逻辑请参考demo 586 | - 文中相关介绍有的地方如果有不是很详细或者有更好建议的,欢迎联系小编 587 | - 如果方便的话, 还望star一下 588 | 589 | 590 | --- 591 | 592 | ### 其他相关文章 593 | - [Swift之二维码的生成、识别和扫描](http://www.jianshu.com/p/0a30d1af8335) 594 | - [iOS黑科技之(CoreImage)静态人脸识别(一)](http://www.jianshu.com/p/168007f6f8b4) 595 | - [iOS黑科技之(AVFoundation)动态人脸识别(二)](http://www.jianshu.com/p/5e624dc68a64) 596 | - [Swift之Vision 图像识别框架](http://www.jianshu.com/p/08174663d2e9) --------------------------------------------------------------------------------