├── .gitignore ├── Podfile ├── README.md ├── TextDetection-VIN.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── TextDetection-VIN.xcworkspace └── contents.xcworkspacedata ├── TextDetection-VIN ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── GoogleService-Info.plist ├── Info.plist ├── VINDetectionViewController.h ├── VINDetectionViewController.m ├── ViewController.h ├── ViewController.m ├── main.m └── scanSuccess.wav └── image.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .DS_Store? 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | !default.xcworkspace 13 | xcuserdata 14 | *.moved-aside 15 | *.mobileprovision 16 | DerivedData 17 | .idea/ 18 | Pods 19 | Podfile.lock -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'TextDetection-VIN' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | # use_frameworks! 7 | 8 | # Pods for TextDetection-VIN 9 | 10 | pod 'Firebase/CoreOnly', '~> 5.17.0' 11 | pod 'Firebase/MLVision', '~> 5.17.0' 12 | pod 'Firebase/MLVisionTextModel', '~> 5.17.0' 13 | 14 | end 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 飞桨OCR识别版本详见另外一个项目:https://github.com/TheLittleBoy/TextDetection-VIN2 2 | 3 | ------ 4 | 5 | # TextDetection-VIN 6 | iOS使用Firebase文字识别SDK,实现离线扫描VIN码,免费,并且效果极佳,速度贼快。 7 | 8 | ‼️离线免费版本仅仅可以识别字母、数字。如果要想识别其它语言,请使用在线识别版本。‼️ 9 | 10 | 项目需要使用 cocoapods 安装 Firebase 组件。 11 | 12 | pod install即可 13 | 14 | 请耐心等待安装,SDK大约380M,打包之后APP增加10M左右。 15 | 16 | 初始化需要用到GoogleService-Info.plist配置文件。‼️此项目仅仅演示离线识别功能,所以文件里边的key都是随便写的‼️ 17 | 18 | 更多详细信息请参考Firebase官网:https://firebase.google.cn/docs/ml-kit/ios/recognize-text 19 | 20 | 效果图: 21 | 22 | ![](https://github.com/TheLittleBoy/TextDetection-VIN/blob/master/image.jpg) 23 | -------------------------------------------------------------------------------- /TextDetection-VIN.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 041D188D2239F0A40001166A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 041D188C2239F0A40001166A /* AppDelegate.m */; }; 11 | 041D18902239F0A40001166A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 041D188F2239F0A40001166A /* ViewController.m */; }; 12 | 041D18932239F0A40001166A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 041D18912239F0A40001166A /* Main.storyboard */; }; 13 | 041D18952239F0A50001166A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 041D18942239F0A50001166A /* Assets.xcassets */; }; 14 | 041D18982239F0A50001166A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 041D18962239F0A50001166A /* LaunchScreen.storyboard */; }; 15 | 041D189B2239F0A50001166A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 041D189A2239F0A50001166A /* main.m */; }; 16 | 04D1F5052239F398009B50F6 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 04D1F5042239F398009B50F6 /* GoogleService-Info.plist */; }; 17 | 04D1F5082239F66C009B50F6 /* VINDetectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F5072239F66C009B50F6 /* VINDetectionViewController.m */; }; 18 | 04D1F50A2239F69A009B50F6 /* scanSuccess.wav in Resources */ = {isa = PBXBuildFile; fileRef = 04D1F5092239F69A009B50F6 /* scanSuccess.wav */; }; 19 | 5F730565EFCBCF8EDEF0A75B /* libPods-TextDetection-VIN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19CD719AB921480B6439C490 /* libPods-TextDetection-VIN.a */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 041D18882239F0A40001166A /* TextDetection-VIN.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TextDetection-VIN.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 041D188B2239F0A40001166A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 25 | 041D188C2239F0A40001166A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 26 | 041D188E2239F0A40001166A /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 27 | 041D188F2239F0A40001166A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 28 | 041D18922239F0A40001166A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 041D18942239F0A50001166A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 041D18972239F0A50001166A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 041D18992239F0A50001166A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 041D189A2239F0A50001166A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 04D1F5042239F398009B50F6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 34 | 04D1F5062239F66C009B50F6 /* VINDetectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VINDetectionViewController.h; sourceTree = ""; }; 35 | 04D1F5072239F66C009B50F6 /* VINDetectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VINDetectionViewController.m; sourceTree = ""; }; 36 | 04D1F5092239F69A009B50F6 /* scanSuccess.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = scanSuccess.wav; sourceTree = ""; }; 37 | 19CD719AB921480B6439C490 /* libPods-TextDetection-VIN.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TextDetection-VIN.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 263498DB012BDE1580A0B8F5 /* Pods-TextDetection-VIN.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TextDetection-VIN.release.xcconfig"; path = "Target Support Files/Pods-TextDetection-VIN/Pods-TextDetection-VIN.release.xcconfig"; sourceTree = ""; }; 39 | BA3754E99A1E7EDA1E60DA70 /* Pods-TextDetection-VIN.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TextDetection-VIN.debug.xcconfig"; path = "Target Support Files/Pods-TextDetection-VIN/Pods-TextDetection-VIN.debug.xcconfig"; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | 041D18852239F0A40001166A /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | 5F730565EFCBCF8EDEF0A75B /* libPods-TextDetection-VIN.a in Frameworks */, 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 041D187F2239F0A40001166A = { 55 | isa = PBXGroup; 56 | children = ( 57 | 041D188A2239F0A40001166A /* TextDetection-VIN */, 58 | 041D18892239F0A40001166A /* Products */, 59 | DA4F6ECD5B746FB562016B8D /* Pods */, 60 | F413ACBBA2BE8AF827E26B7B /* Frameworks */, 61 | ); 62 | sourceTree = ""; 63 | }; 64 | 041D18892239F0A40001166A /* Products */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 041D18882239F0A40001166A /* TextDetection-VIN.app */, 68 | ); 69 | name = Products; 70 | sourceTree = ""; 71 | }; 72 | 041D188A2239F0A40001166A /* TextDetection-VIN */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 041D188B2239F0A40001166A /* AppDelegate.h */, 76 | 041D188C2239F0A40001166A /* AppDelegate.m */, 77 | 041D188E2239F0A40001166A /* ViewController.h */, 78 | 041D188F2239F0A40001166A /* ViewController.m */, 79 | 04D1F5062239F66C009B50F6 /* VINDetectionViewController.h */, 80 | 04D1F5072239F66C009B50F6 /* VINDetectionViewController.m */, 81 | 04D1F5042239F398009B50F6 /* GoogleService-Info.plist */, 82 | 041D18912239F0A40001166A /* Main.storyboard */, 83 | 041D18942239F0A50001166A /* Assets.xcassets */, 84 | 041D18962239F0A50001166A /* LaunchScreen.storyboard */, 85 | 04D1F5092239F69A009B50F6 /* scanSuccess.wav */, 86 | 041D18992239F0A50001166A /* Info.plist */, 87 | 041D189A2239F0A50001166A /* main.m */, 88 | ); 89 | path = "TextDetection-VIN"; 90 | sourceTree = ""; 91 | }; 92 | DA4F6ECD5B746FB562016B8D /* Pods */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | BA3754E99A1E7EDA1E60DA70 /* Pods-TextDetection-VIN.debug.xcconfig */, 96 | 263498DB012BDE1580A0B8F5 /* Pods-TextDetection-VIN.release.xcconfig */, 97 | ); 98 | path = Pods; 99 | sourceTree = ""; 100 | }; 101 | F413ACBBA2BE8AF827E26B7B /* Frameworks */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 19CD719AB921480B6439C490 /* libPods-TextDetection-VIN.a */, 105 | ); 106 | name = Frameworks; 107 | sourceTree = ""; 108 | }; 109 | /* End PBXGroup section */ 110 | 111 | /* Begin PBXNativeTarget section */ 112 | 041D18872239F0A40001166A /* TextDetection-VIN */ = { 113 | isa = PBXNativeTarget; 114 | buildConfigurationList = 041D189E2239F0A50001166A /* Build configuration list for PBXNativeTarget "TextDetection-VIN" */; 115 | buildPhases = ( 116 | 6D39A1FE8781361CBC6C1144 /* [CP] Check Pods Manifest.lock */, 117 | 041D18842239F0A40001166A /* Sources */, 118 | 041D18852239F0A40001166A /* Frameworks */, 119 | 041D18862239F0A40001166A /* Resources */, 120 | 560421967193B60C777B65B4 /* [CP] Copy Pods Resources */, 121 | ); 122 | buildRules = ( 123 | ); 124 | dependencies = ( 125 | ); 126 | name = "TextDetection-VIN"; 127 | productName = "TextDetection-VIN"; 128 | productReference = 041D18882239F0A40001166A /* TextDetection-VIN.app */; 129 | productType = "com.apple.product-type.application"; 130 | }; 131 | /* End PBXNativeTarget section */ 132 | 133 | /* Begin PBXProject section */ 134 | 041D18802239F0A40001166A /* Project object */ = { 135 | isa = PBXProject; 136 | attributes = { 137 | LastUpgradeCheck = 1010; 138 | ORGANIZATIONNAME = "🚗"; 139 | TargetAttributes = { 140 | 041D18872239F0A40001166A = { 141 | CreatedOnToolsVersion = 10.1; 142 | }; 143 | }; 144 | }; 145 | buildConfigurationList = 041D18832239F0A40001166A /* Build configuration list for PBXProject "TextDetection-VIN" */; 146 | compatibilityVersion = "Xcode 9.3"; 147 | developmentRegion = en; 148 | hasScannedForEncodings = 0; 149 | knownRegions = ( 150 | en, 151 | Base, 152 | ); 153 | mainGroup = 041D187F2239F0A40001166A; 154 | productRefGroup = 041D18892239F0A40001166A /* Products */; 155 | projectDirPath = ""; 156 | projectRoot = ""; 157 | targets = ( 158 | 041D18872239F0A40001166A /* TextDetection-VIN */, 159 | ); 160 | }; 161 | /* End PBXProject section */ 162 | 163 | /* Begin PBXResourcesBuildPhase section */ 164 | 041D18862239F0A40001166A /* Resources */ = { 165 | isa = PBXResourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 04D1F50A2239F69A009B50F6 /* scanSuccess.wav in Resources */, 169 | 041D18982239F0A50001166A /* LaunchScreen.storyboard in Resources */, 170 | 04D1F5052239F398009B50F6 /* GoogleService-Info.plist in Resources */, 171 | 041D18952239F0A50001166A /* Assets.xcassets in Resources */, 172 | 041D18932239F0A40001166A /* Main.storyboard in Resources */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXResourcesBuildPhase section */ 177 | 178 | /* Begin PBXShellScriptBuildPhase section */ 179 | 560421967193B60C777B65B4 /* [CP] Copy Pods Resources */ = { 180 | isa = PBXShellScriptBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | ); 184 | inputFileListPaths = ( 185 | ); 186 | inputPaths = ( 187 | "${PODS_ROOT}/Target Support Files/Pods-TextDetection-VIN/Pods-TextDetection-VIN-resources.sh", 188 | "${PODS_CONFIGURATION_BUILD_DIR}/GoogleMobileVision/GoogleMVTextDetectorResources.bundle", 189 | ); 190 | name = "[CP] Copy Pods Resources"; 191 | outputFileListPaths = ( 192 | ); 193 | outputPaths = ( 194 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMVTextDetectorResources.bundle", 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TextDetection-VIN/Pods-TextDetection-VIN-resources.sh\"\n"; 199 | showEnvVarsInLog = 0; 200 | }; 201 | 6D39A1FE8781361CBC6C1144 /* [CP] Check Pods Manifest.lock */ = { 202 | isa = PBXShellScriptBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | ); 206 | inputFileListPaths = ( 207 | ); 208 | inputPaths = ( 209 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 210 | "${PODS_ROOT}/Manifest.lock", 211 | ); 212 | name = "[CP] Check Pods Manifest.lock"; 213 | outputFileListPaths = ( 214 | ); 215 | outputPaths = ( 216 | "$(DERIVED_FILE_DIR)/Pods-TextDetection-VIN-checkManifestLockResult.txt", 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | shellPath = /bin/sh; 220 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 221 | showEnvVarsInLog = 0; 222 | }; 223 | /* End PBXShellScriptBuildPhase section */ 224 | 225 | /* Begin PBXSourcesBuildPhase section */ 226 | 041D18842239F0A40001166A /* Sources */ = { 227 | isa = PBXSourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | 041D18902239F0A40001166A /* ViewController.m in Sources */, 231 | 041D189B2239F0A50001166A /* main.m in Sources */, 232 | 04D1F5082239F66C009B50F6 /* VINDetectionViewController.m in Sources */, 233 | 041D188D2239F0A40001166A /* AppDelegate.m in Sources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | /* End PBXSourcesBuildPhase section */ 238 | 239 | /* Begin PBXVariantGroup section */ 240 | 041D18912239F0A40001166A /* Main.storyboard */ = { 241 | isa = PBXVariantGroup; 242 | children = ( 243 | 041D18922239F0A40001166A /* Base */, 244 | ); 245 | name = Main.storyboard; 246 | sourceTree = ""; 247 | }; 248 | 041D18962239F0A50001166A /* LaunchScreen.storyboard */ = { 249 | isa = PBXVariantGroup; 250 | children = ( 251 | 041D18972239F0A50001166A /* Base */, 252 | ); 253 | name = LaunchScreen.storyboard; 254 | sourceTree = ""; 255 | }; 256 | /* End PBXVariantGroup section */ 257 | 258 | /* Begin XCBuildConfiguration section */ 259 | 041D189C2239F0A50001166A /* Debug */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ALWAYS_SEARCH_USER_PATHS = NO; 263 | CLANG_ANALYZER_NONNULL = YES; 264 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 266 | CLANG_CXX_LIBRARY = "libc++"; 267 | CLANG_ENABLE_MODULES = YES; 268 | CLANG_ENABLE_OBJC_ARC = YES; 269 | CLANG_ENABLE_OBJC_WEAK = YES; 270 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 271 | CLANG_WARN_BOOL_CONVERSION = YES; 272 | CLANG_WARN_COMMA = YES; 273 | CLANG_WARN_CONSTANT_CONVERSION = YES; 274 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 275 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 276 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INFINITE_RECURSION = YES; 280 | CLANG_WARN_INT_CONVERSION = YES; 281 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 282 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 283 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 286 | CLANG_WARN_STRICT_PROTOTYPES = YES; 287 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 288 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | CODE_SIGN_IDENTITY = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = dwarf; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | ENABLE_TESTABILITY = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu11; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_NO_COMMON_BLOCKS = YES; 299 | GCC_OPTIMIZATION_LEVEL = 0; 300 | GCC_PREPROCESSOR_DEFINITIONS = ( 301 | "DEBUG=1", 302 | "$(inherited)", 303 | ); 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 311 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 312 | MTL_FAST_MATH = YES; 313 | ONLY_ACTIVE_ARCH = YES; 314 | SDKROOT = iphoneos; 315 | }; 316 | name = Debug; 317 | }; 318 | 041D189D2239F0A50001166A /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ALWAYS_SEARCH_USER_PATHS = NO; 322 | CLANG_ANALYZER_NONNULL = YES; 323 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 325 | CLANG_CXX_LIBRARY = "libc++"; 326 | CLANG_ENABLE_MODULES = YES; 327 | CLANG_ENABLE_OBJC_ARC = YES; 328 | CLANG_ENABLE_OBJC_WEAK = YES; 329 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 330 | CLANG_WARN_BOOL_CONVERSION = YES; 331 | CLANG_WARN_COMMA = YES; 332 | CLANG_WARN_CONSTANT_CONVERSION = YES; 333 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 335 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 336 | CLANG_WARN_EMPTY_BODY = YES; 337 | CLANG_WARN_ENUM_CONVERSION = YES; 338 | CLANG_WARN_INFINITE_RECURSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 341 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 345 | CLANG_WARN_STRICT_PROTOTYPES = YES; 346 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 347 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 348 | CLANG_WARN_UNREACHABLE_CODE = YES; 349 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 350 | CODE_SIGN_IDENTITY = "iPhone Developer"; 351 | COPY_PHASE_STRIP = NO; 352 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 353 | ENABLE_NS_ASSERTIONS = NO; 354 | ENABLE_STRICT_OBJC_MSGSEND = YES; 355 | GCC_C_LANGUAGE_STANDARD = gnu11; 356 | GCC_NO_COMMON_BLOCKS = YES; 357 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 358 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 359 | GCC_WARN_UNDECLARED_SELECTOR = YES; 360 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 361 | GCC_WARN_UNUSED_FUNCTION = YES; 362 | GCC_WARN_UNUSED_VARIABLE = YES; 363 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 364 | MTL_ENABLE_DEBUG_INFO = NO; 365 | MTL_FAST_MATH = YES; 366 | SDKROOT = iphoneos; 367 | VALIDATE_PRODUCT = YES; 368 | }; 369 | name = Release; 370 | }; 371 | 041D189F2239F0A50001166A /* Debug */ = { 372 | isa = XCBuildConfiguration; 373 | baseConfigurationReference = BA3754E99A1E7EDA1E60DA70 /* Pods-TextDetection-VIN.debug.xcconfig */; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CODE_SIGN_STYLE = Automatic; 377 | DEVELOPMENT_TEAM = CX9724CS5M; 378 | INFOPLIST_FILE = "TextDetection-VIN/Info.plist"; 379 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 380 | LD_RUNPATH_SEARCH_PATHS = ( 381 | "$(inherited)", 382 | "@executable_path/Frameworks", 383 | ); 384 | PRODUCT_BUNDLE_IDENTIFIER = "com.edu-edu.TextDetection-VIN"; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | TARGETED_DEVICE_FAMILY = "1,2"; 387 | }; 388 | name = Debug; 389 | }; 390 | 041D18A02239F0A50001166A /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | baseConfigurationReference = 263498DB012BDE1580A0B8F5 /* Pods-TextDetection-VIN.release.xcconfig */; 393 | buildSettings = { 394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 395 | CODE_SIGN_STYLE = Automatic; 396 | DEVELOPMENT_TEAM = CX9724CS5M; 397 | INFOPLIST_FILE = "TextDetection-VIN/Info.plist"; 398 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 399 | LD_RUNPATH_SEARCH_PATHS = ( 400 | "$(inherited)", 401 | "@executable_path/Frameworks", 402 | ); 403 | PRODUCT_BUNDLE_IDENTIFIER = "com.edu-edu.TextDetection-VIN"; 404 | PRODUCT_NAME = "$(TARGET_NAME)"; 405 | TARGETED_DEVICE_FAMILY = "1,2"; 406 | }; 407 | name = Release; 408 | }; 409 | /* End XCBuildConfiguration section */ 410 | 411 | /* Begin XCConfigurationList section */ 412 | 041D18832239F0A40001166A /* Build configuration list for PBXProject "TextDetection-VIN" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | 041D189C2239F0A50001166A /* Debug */, 416 | 041D189D2239F0A50001166A /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | defaultConfigurationName = Release; 420 | }; 421 | 041D189E2239F0A50001166A /* Build configuration list for PBXNativeTarget "TextDetection-VIN" */ = { 422 | isa = XCConfigurationList; 423 | buildConfigurations = ( 424 | 041D189F2239F0A50001166A /* Debug */, 425 | 041D18A02239F0A50001166A /* Release */, 426 | ); 427 | defaultConfigurationIsVisible = 0; 428 | defaultConfigurationName = Release; 429 | }; 430 | /* End XCConfigurationList section */ 431 | }; 432 | rootObject = 041D18802239F0A40001166A /* Project object */; 433 | } 434 | -------------------------------------------------------------------------------- /TextDetection-VIN.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TextDetection-VIN.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TextDetection-VIN/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /TextDetection-VIN/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "Firebase.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | 22 | //初始化谷歌Firebase服务。 更多详细信息请参考官网:https://firebase.google.cn/docs/ml-kit/ios/recognize-text 23 | //初始化需要用到GoogleService-Info.plist配置文件。‼️此项目仅仅演示离线识别功能,所以文件里边的key都是随便写的‼️ 24 | [FIRApp configure]; 25 | 26 | return YES; 27 | } 28 | 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application { 31 | // 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. 32 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 33 | } 34 | 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application { 37 | // 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. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application { 43 | // 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. 44 | } 45 | 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application { 48 | // 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. 49 | } 50 | 51 | 52 | - (void)applicationWillTerminate:(UIApplication *)application { 53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 54 | } 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /TextDetection-VIN/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /TextDetection-VIN/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TextDetection-VIN/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 | -------------------------------------------------------------------------------- /TextDetection-VIN/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 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /TextDetection-VIN/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | API_KEY 6 | 123 7 | GCM_SENDER_ID 8 | 123 9 | PLIST_VERSION 10 | 1 11 | BUNDLE_ID 12 | com.edu-edu.TextDetection-VIN 13 | IS_ADS_ENABLED 14 | 15 | IS_ANALYTICS_ENABLED 16 | 17 | IS_APPINVITE_ENABLED 18 | 19 | IS_GCM_ENABLED 20 | 21 | IS_SIGNIN_ENABLED 22 | 23 | GOOGLE_APP_ID 24 | 1:234:ios:123 25 | 26 | 27 | -------------------------------------------------------------------------------- /TextDetection-VIN/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | VIN识别 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | for inference 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /TextDetection-VIN/VINDetectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // VINDetectionViewController.h 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol VINDetectionViewControllerDelegate 12 | 13 | /** 14 | 识别成功之后,点击完成按钮的回调 15 | 16 | @param result VIN码 17 | */ 18 | - (void)recognitionComplete:(NSString *)result; 19 | 20 | @end 21 | 22 | /** 23 | VIN 识别 24 | */ 25 | @interface VINDetectionViewController : UIViewController 26 | 27 | @property(nonatomic, weak) id delegate; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /TextDetection-VIN/VINDetectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // VINDetectionViewController.m 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import "VINDetectionViewController.h" 10 | #import "Firebase.h" 11 | #import 12 | 13 | @interface VINDetectionViewController () 14 | { 15 | UILabel *textLabel; 16 | AVCaptureDevice *device; 17 | NSString *recognizedText; 18 | BOOL isFocus; 19 | BOOL isInference; 20 | FIRVisionTextRecognizer *textRecognizer; 21 | } 22 | @property (nonatomic, assign) CGFloat m_width; //扫描框宽度 23 | @property (nonatomic, assign) CGFloat m_higth; //扫描框高度 24 | @property (nonatomic, strong) AVCaptureSession *session; 25 | @property (nonatomic, strong) AVCaptureDeviceInput *videoInput; 26 | @property (nonatomic, strong) AVCaptureVideoDataOutput *captureVideoDataOutput; 27 | @property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; 28 | @end 29 | 30 | #define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width) 31 | #define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height) 32 | #define m_scanViewY 150.0 33 | #define m_scale [UIScreen mainScreen].scale 34 | 35 | @implementation VINDetectionViewController 36 | 37 | - (void)viewDidLoad { 38 | [super viewDidLoad]; 39 | // Do any additional setup after loading the view. 40 | 41 | self.title = @"扫一扫"; 42 | self.view.backgroundColor = [UIColor blackColor]; 43 | self.navigationController.navigationBar.translucent = NO; 44 | 45 | //给个默认值 46 | self.m_width = (SCREEN_WIDTH - 40); 47 | self.m_higth = 80.0; 48 | recognizedText = @""; 49 | 50 | //初始化识别器 51 | FIRVision *vision = [FIRVision vision]; 52 | //这里仅仅使用离线识别功能。‼️如果要想使用在线识别,请到Firebase官网注册APP,并购买相关服务‼️ 53 | textRecognizer = [vision onDeviceTextRecognizer]; 54 | 55 | //初始化摄像头 56 | [self initAVCaptureSession]; 57 | } 58 | 59 | - (void)initAVCaptureSession{ 60 | 61 | self.session = [[AVCaptureSession alloc] init]; 62 | NSError *error; 63 | 64 | device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 65 | 66 | self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; 67 | if (error) { 68 | NSLog(@"%@",error); 69 | } 70 | 71 | //输出流 72 | NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey; 73 | NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; 74 | NSDictionary* videoSettings = [NSDictionary 75 | dictionaryWithObject:value forKey:key]; 76 | self.captureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init]; 77 | [self.captureVideoDataOutput setVideoSettings:videoSettings]; 78 | 79 | dispatch_queue_t queue; 80 | queue = dispatch_queue_create("cameraQueue", NULL); 81 | [self.captureVideoDataOutput setSampleBufferDelegate:self queue:queue]; 82 | 83 | if ([self.session canAddInput:self.videoInput]) { 84 | [self.session addInput:self.videoInput]; 85 | } 86 | if ([self.session canAddOutput:self.captureVideoDataOutput]) { 87 | [self.session addOutput:self.captureVideoDataOutput]; 88 | } 89 | 90 | //输出照片铺满屏幕 91 | if ([self.session canSetSessionPreset:AVCaptureSessionPresetHigh]) { 92 | self.session.sessionPreset = AVCaptureSessionPresetHigh; 93 | } 94 | 95 | //初始化预览图层 96 | self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; 97 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 98 | if (orientation == UIInterfaceOrientationPortrait) { 99 | [[self.previewLayer connection] setVideoOrientation:AVCaptureVideoOrientationPortrait]; 100 | 101 | } 102 | else if (orientation == UIInterfaceOrientationLandscapeLeft) { 103 | [[self.previewLayer connection] setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft]; 104 | } 105 | else if (orientation == UIInterfaceOrientationLandscapeRight) { 106 | [[self.previewLayer connection] setVideoOrientation:AVCaptureVideoOrientationLandscapeRight]; 107 | } 108 | else { 109 | [[self.previewLayer connection] setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown]; 110 | } 111 | 112 | self.previewLayer.frame = CGRectMake(0,0, SCREEN_WIDTH,SCREEN_HEIGHT); 113 | 114 | [self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; 115 | 116 | self.view.layer.masksToBounds = YES; 117 | [self.view.layer addSublayer:self.previewLayer]; 118 | 119 | //扫描框 120 | [self initScanView]; 121 | 122 | //扫描结果label 123 | textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, (SCREEN_HEIGHT - 100)/2.0, SCREEN_WIDTH, 100)]; 124 | textLabel.textAlignment = NSTextAlignmentCenter; 125 | textLabel.numberOfLines = 0; 126 | 127 | textLabel.font = [UIFont systemFontOfSize:19]; 128 | 129 | textLabel.textColor = [UIColor whiteColor]; 130 | [self.view addSubview:textLabel]; 131 | 132 | //完成按钮 133 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 134 | [self.view addSubview:button]; 135 | button.frame = CGRectMake((SCREEN_WIDTH - 100)/2.0, SCREEN_HEIGHT - 164, 100, 50); 136 | [button setTitle:@"完成" forState:UIControlStateNormal]; 137 | [button addTarget:self action:@selector(clickedFinishBtn:) forControlEvents:UIControlEventTouchUpInside]; 138 | 139 | //对焦 140 | int flags =NSKeyValueObservingOptionNew; 141 | [device addObserver:self forKeyPath:@"adjustingFocus" options:flags context:nil]; 142 | } 143 | 144 | - (void)initScanView 145 | { 146 | // 中间空心洞的区域 147 | CGRect cutRect = CGRectMake((SCREEN_WIDTH - _m_width)/2.0,m_scanViewY, _m_width, _m_higth); 148 | 149 | UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0,0, SCREEN_WIDTH,SCREEN_HEIGHT)]; 150 | // 挖空心洞 显示区域 151 | UIBezierPath *cutRectPath = [UIBezierPath bezierPathWithRect:cutRect]; 152 | 153 | //将circlePath添加到path上 154 | [path appendPath:cutRectPath]; 155 | path.usesEvenOddFillRule = YES; 156 | 157 | CAShapeLayer *fillLayer = [CAShapeLayer layer]; 158 | fillLayer.path = path.CGPath; 159 | fillLayer.fillRule = kCAFillRuleEvenOdd; 160 | fillLayer.opacity = 0.6;//透明度 161 | fillLayer.backgroundColor = [UIColor blackColor].CGColor; 162 | [self.view.layer addSublayer:fillLayer]; 163 | 164 | // 边界校准线 165 | CGFloat lineWidth = 2; 166 | CGFloat lineLength = 20; 167 | UIBezierPath *linePath = [UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth, 168 | cutRect.origin.y - lineWidth, 169 | lineLength, 170 | lineWidth)]; 171 | //追加路径 172 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth, 173 | cutRect.origin.y - lineWidth, 174 | lineWidth, 175 | lineLength)]]; 176 | 177 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width - lineLength + lineWidth, 178 | cutRect.origin.y - lineWidth, 179 | lineLength, 180 | lineWidth)]]; 181 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width , 182 | cutRect.origin.y - lineWidth, 183 | lineWidth, 184 | lineLength)]]; 185 | 186 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth, 187 | cutRect.origin.y + cutRect.size.height - lineLength + lineWidth, 188 | lineWidth, 189 | lineLength)]]; 190 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x - lineWidth, 191 | cutRect.origin.y + cutRect.size.height, 192 | lineLength, 193 | lineWidth)]]; 194 | 195 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width, 196 | cutRect.origin.y + cutRect.size.height - lineLength + lineWidth, 197 | lineWidth, 198 | lineLength)]]; 199 | [linePath appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(cutRect.origin.x + cutRect.size.width - lineLength + lineWidth, 200 | cutRect.origin.y + cutRect.size.height, 201 | lineLength, 202 | lineWidth)]]; 203 | 204 | CAShapeLayer *pathLayer = [CAShapeLayer layer]; 205 | pathLayer.path = linePath.CGPath;// 从贝塞尔曲线获取到形状 206 | pathLayer.fillColor = [UIColor colorWithRed:0. green:0.655 blue:0.905 alpha:1.0].CGColor; // 闭环填充的颜色 207 | [self.view.layer addSublayer:pathLayer]; 208 | 209 | UILabel *tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, m_scanViewY - 40, SCREEN_WIDTH, 25)]; 210 | [self.view addSubview:tipLabel]; 211 | tipLabel.text = @"请对准VIN码进行扫描"; 212 | tipLabel.textAlignment = NSTextAlignmentCenter; 213 | tipLabel.textColor = [UIColor whiteColor]; 214 | } 215 | 216 | -(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context { 217 | if([keyPath isEqualToString:@"adjustingFocus"]){ 218 | BOOL adjustingFocus =[[change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1]]; 219 | isFocus = adjustingFocus; 220 | NSLog(@"Is adjusting focus? %@", adjustingFocus ?@"YES":@"NO"); 221 | } 222 | } 223 | 224 | - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { 225 | // 226 | if (!isFocus && !isInference) { 227 | isInference = YES; 228 | 229 | // Calculate the image orientation 230 | FIRVisionDetectorImageOrientation orientation; 231 | 232 | //指定使用后置摄像头 233 | AVCaptureDevicePosition devicePosition = AVCaptureDevicePositionBack; 234 | 235 | //校准图像方向 236 | UIDeviceOrientation deviceOrientation = UIDevice.currentDevice.orientation; 237 | switch (deviceOrientation) { 238 | case UIDeviceOrientationPortrait: 239 | if (devicePosition == AVCaptureDevicePositionFront) { 240 | orientation = FIRVisionDetectorImageOrientationLeftTop; 241 | } else { 242 | orientation = FIRVisionDetectorImageOrientationRightTop; 243 | } 244 | break; 245 | case UIDeviceOrientationLandscapeLeft: 246 | if (devicePosition == AVCaptureDevicePositionFront) { 247 | orientation = FIRVisionDetectorImageOrientationBottomLeft; 248 | } else { 249 | orientation = FIRVisionDetectorImageOrientationTopLeft; 250 | } 251 | break; 252 | case UIDeviceOrientationPortraitUpsideDown: 253 | if (devicePosition == AVCaptureDevicePositionFront) { 254 | orientation = FIRVisionDetectorImageOrientationRightBottom; 255 | } else { 256 | orientation = FIRVisionDetectorImageOrientationLeftBottom; 257 | } 258 | break; 259 | case UIDeviceOrientationLandscapeRight: 260 | if (devicePosition == AVCaptureDevicePositionFront) { 261 | orientation = FIRVisionDetectorImageOrientationTopRight; 262 | } else { 263 | orientation = FIRVisionDetectorImageOrientationBottomRight; 264 | } 265 | break; 266 | default: 267 | orientation = FIRVisionDetectorImageOrientationTopLeft; 268 | break; 269 | } 270 | 271 | FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; 272 | metadata.orientation = orientation; 273 | 274 | //这里不仅可以使用buffer初始化,也可以使用 image 进行初始化 275 | FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; 276 | image.metadata = metadata; 277 | 278 | //开始识别 279 | [textRecognizer processImage:image 280 | completion:^(FIRVisionText *_Nullable result, 281 | NSError *_Nullable error) { 282 | if (error == nil && result != nil) { 283 | //识别结果会包很多层:FIRVisionText——>FIRVisionTextBlock->FIRVisionTextLine->FIRVisionTextElement 284 | for (FIRVisionTextBlock *block in result.blocks) { 285 | for (FIRVisionTextLine *line in block.lines) { 286 | for (FIRVisionTextElement *element in line.elements) { 287 | NSString *elementText = element.text; 288 | //识别17位的VIN码 289 | if (elementText.length == 17) { 290 | //正则表达式,排除特殊字符 291 | NSString *regex = @"[ABCDEFGHJKLMNPRSTUVWXYZ1234567890]{17}"; 292 | NSPredicate *test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 293 | //识别成功 294 | if ([test evaluateWithObject:elementText]) { 295 | 296 | //连续两次识别结果一致,则输出最终结果 297 | if ([self->recognizedText isEqualToString:elementText]) { 298 | 299 | //停止扫描 300 | [self.session stopRunning]; 301 | 302 | //播放音效 303 | NSURL *url=[[NSBundle mainBundle]URLForResource:@"scanSuccess.wav" withExtension:nil]; 304 | SystemSoundID soundID=8787; 305 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &soundID); 306 | AudioServicesPlaySystemSound(soundID); 307 | 308 | //在屏幕上输入结果 309 | self->textLabel.text = self->recognizedText; 310 | 311 | NSLog(@"%@",self->recognizedText); 312 | }else 313 | { 314 | //马上再识别一次,对比结果对比 315 | self->recognizedText = elementText; 316 | self->isInference = NO; 317 | } 318 | return; 319 | } 320 | } 321 | } 322 | } 323 | } 324 | } 325 | //延迟100毫秒再继续识别下一次,降低CPU功耗,省电‼️ 326 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ 327 | //继续识别 328 | self->isInference = NO; 329 | }); 330 | }]; 331 | } 332 | } 333 | 334 | - (void)viewWillAppear:(BOOL)animated{ 335 | 336 | [super viewWillAppear:YES]; 337 | 338 | if (self.session) { 339 | [self.session startRunning]; 340 | } 341 | } 342 | 343 | - (void)viewDidDisappear:(BOOL)animated{ 344 | 345 | [super viewDidDisappear:YES]; 346 | 347 | if (self.session) { 348 | [self.session stopRunning]; 349 | } 350 | 351 | [device removeObserver:self forKeyPath:@"adjustingFocus" context:nil]; 352 | } 353 | 354 | /** 355 | 完成按钮点击事件 356 | 357 | @param sender 按钮 358 | */ 359 | - (void)clickedFinishBtn:(UIButton *)sender { 360 | 361 | if (self.delegate && [self.delegate respondsToSelector:@selector(recognitionComplete:)]) { 362 | [self.delegate recognitionComplete:textLabel.text]; 363 | } 364 | 365 | [self.navigationController popViewControllerAnimated:YES]; 366 | } 367 | 368 | /* 369 | #pragma mark - Navigation 370 | 371 | // In a storyboard-based application, you will often want to do a little preparation before navigation 372 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 373 | // Get the new view controller using [segue destinationViewController]. 374 | // Pass the selected object to the new view controller. 375 | } 376 | */ 377 | 378 | @end 379 | -------------------------------------------------------------------------------- /TextDetection-VIN/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /TextDetection-VIN/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "VINDetectionViewController.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view, typically from a nib. 21 | 22 | self.title = @"🚗"; 23 | } 24 | 25 | - (IBAction)startButtonAction:(id)sender { 26 | 27 | VINDetectionViewController *vinVC = [[VINDetectionViewController alloc] init]; 28 | vinVC.delegate = self; 29 | [self.navigationController pushViewController:vinVC animated:YES]; 30 | } 31 | 32 | /** 33 | 识别成功之后,点击完成按钮的回调 34 | 35 | @param result VIN码 36 | */ 37 | - (void)recognitionComplete:(NSString *)result { 38 | 39 | NSLog(@"%@",result); 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /TextDetection-VIN/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TextDetection-VIN 4 | // 5 | // Created by Mac on 2019/3/14. 6 | // Copyright © 2019 🚗. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TextDetection-VIN/scanSuccess.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLittleBoy/TextDetection-VIN/e0990c36e229587eee4e711383e14bb260b13aec/TextDetection-VIN/scanSuccess.wav -------------------------------------------------------------------------------- /image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLittleBoy/TextDetection-VIN/e0990c36e229587eee4e711383e14bb260b13aec/image.jpg --------------------------------------------------------------------------------