├── .gitignore ├── BeanCounter.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── BeanCounter ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── AppIcon_120-1.png │ │ ├── AppIcon_120.png │ │ ├── AppIcon_152.png │ │ ├── AppIcon_167.png │ │ ├── AppIcon_180.png │ │ ├── AppIcon_29.png │ │ ├── AppIcon_40.png │ │ ├── AppIcon_58-1.png │ │ ├── AppIcon_58.png │ │ ├── AppIcon_76.png │ │ ├── AppIcon_80-1.png │ │ ├── AppIcon_80.png │ │ ├── AppIcon_87.png │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Blob.cpp ├── Blob.h ├── BlobClassifier.cpp ├── BlobClassifier.h ├── BlobClassifierTraining.plist ├── BlobDescriptor.cpp ├── BlobDescriptor.h ├── BlobDetector.cpp ├── BlobDetector.h ├── CanadianDime_Heads_000.png ├── CanadianDime_Tails_000.png ├── CanadianNickel_Heads_000.png ├── CanadianNickel_Tails_000.png ├── CanadianQuarter_Heads_000.png ├── CanadianQuarter_Tails_000.png ├── CaptureViewController.h ├── CaptureViewController.m ├── Info.plist ├── Loonie_Heads_000.png ├── Loonie_Tails_000.png ├── PintoBean_000.png ├── ReviewViewController.h ├── ReviewViewController.m ├── RomanoBean_000.png ├── SwitchCamera.png ├── SwitchCamera@2x.png ├── SwitchCamera@3x.png ├── TheQueen'sBeans.jpg ├── Toonie_Heads_000.png ├── Toonie_Tails_000.png ├── VideoCamera.h ├── VideoCamera.m └── main.m ├── CoolPig.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── CoolPig ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── AppIcon_120-1.png │ │ ├── AppIcon_120.png │ │ ├── AppIcon_152.png │ │ ├── AppIcon_167.png │ │ ├── AppIcon_180.png │ │ ├── AppIcon_29.png │ │ ├── AppIcon_40.png │ │ ├── AppIcon_58-1.png │ │ ├── AppIcon_58.png │ │ ├── AppIcon_76.png │ │ ├── AppIcon_80-1.png │ │ ├── AppIcon_80.png │ │ ├── AppIcon_87.png │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Piggy.png ├── ViewController.h ├── ViewController.m └── main.m ├── ERRATA.md ├── LightWork.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── LightWork ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── AppIcon_120-1.png │ │ ├── AppIcon_120.png │ │ ├── AppIcon_152.png │ │ ├── AppIcon_167.png │ │ ├── AppIcon_180.png │ │ ├── AppIcon_29.png │ │ ├── AppIcon_40.png │ │ ├── AppIcon_58-1.png │ │ ├── AppIcon_58.png │ │ ├── AppIcon_76.png │ │ ├── AppIcon_80-1.png │ │ ├── AppIcon_80.png │ │ ├── AppIcon_87.png │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Fleur.jpg ├── Info.plist ├── SwitchCamera.png ├── SwitchCamera@2x.png ├── SwitchCamera@3x.png ├── VideoCamera.h ├── VideoCamera.m ├── ViewController.h ├── ViewController.m └── main.m ├── ManyMasks.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── ManyMasks ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── AppIcon_120-1.png │ │ ├── AppIcon_120.png │ │ ├── AppIcon_152.png │ │ ├── AppIcon_167.png │ │ ├── AppIcon_180.png │ │ ├── AppIcon_29.png │ │ ├── AppIcon_40.png │ │ ├── AppIcon_58-1.png │ │ ├── AppIcon_58.png │ │ ├── AppIcon_76.png │ │ ├── AppIcon_80-1.png │ │ ├── AppIcon_80.png │ │ ├── AppIcon_87.png │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CaptureViewController.h ├── CaptureViewController.m ├── Face.cpp ├── Face.h ├── FaceDetector.cpp ├── FaceDetector.h ├── GeomUtils.cpp ├── GeomUtils.h ├── Info.plist ├── Mask.png ├── ReviewViewController.h ├── ReviewViewController.m ├── Species.h ├── SwitchCamera.png ├── SwitchCamera@2x.png ├── SwitchCamera@3x.png ├── VideoCamera.h ├── VideoCamera.m ├── haarcascade_frontalcatface_extended.xml ├── haarcascade_frontalface_alt.xml ├── haarcascade_lefteye_2splits.xml ├── haarcascade_righteye_2splits.xml └── main.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Large files 2 | opencv2.framework 3 | 4 | ## Metafiles 5 | .DS_Store 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata 21 | 22 | ## Other 23 | *.xccheckout 24 | *.moved-aside 25 | *.xcuserstate 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | -------------------------------------------------------------------------------- /BeanCounter.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BeanCounter/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-08. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface AppDelegate : UIResponder 37 | 38 | @property (strong, nonatomic) UIWindow *window; 39 | 40 | 41 | @end 42 | 43 | -------------------------------------------------------------------------------- /BeanCounter/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-08. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "AppDelegate.h" 35 | 36 | @interface AppDelegate () 37 | 38 | @end 39 | 40 | @implementation AppDelegate 41 | 42 | 43 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 44 | // Override point for customization after application launch. 45 | return YES; 46 | } 47 | 48 | - (void)applicationWillResignActive:(UIApplication *)application { 49 | // 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. 50 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 51 | } 52 | 53 | - (void)applicationDidEnterBackground:(UIApplication *)application { 54 | // 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. 55 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 56 | } 57 | 58 | - (void)applicationWillEnterForeground:(UIApplication *)application { 59 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 60 | } 61 | 62 | - (void)applicationDidBecomeActive:(UIApplication *)application { 63 | // 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. 64 | } 65 | 66 | - (void)applicationWillTerminate:(UIApplication *)application { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png -------------------------------------------------------------------------------- /BeanCounter/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon_58.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon_87.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon_80.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "AppIcon_120.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "AppIcon_120-1.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon_180.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "AppIcon_29.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "AppIcon_58-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "AppIcon_40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "AppIcon_80-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "AppIcon_76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "AppIcon_152.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "83.5x83.5", 77 | "idiom" : "ipad", 78 | "filename" : "AppIcon_167.png", 79 | "scale" : "2x" 80 | } 81 | ], 82 | "info" : { 83 | "version" : 1, 84 | "author" : "xcode" 85 | } 86 | } -------------------------------------------------------------------------------- /BeanCounter/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 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /BeanCounter/Blob.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Blob.cpp 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-09. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "Blob.h" 35 | 36 | Blob::Blob(const cv::Mat &mat, uint32_t label) 37 | : label(label) 38 | { 39 | mat.copyTo(this->mat); 40 | } 41 | 42 | Blob::Blob() { 43 | } 44 | 45 | Blob::Blob(const Blob &other) 46 | : label(other.label) 47 | { 48 | other.mat.copyTo(mat); 49 | } 50 | 51 | bool Blob::isEmpty() const { 52 | return mat.empty(); 53 | } 54 | 55 | uint32_t Blob::getLabel() const { 56 | return label; 57 | } 58 | 59 | void Blob::setLabel(uint32_t value) { 60 | label = value; 61 | } 62 | 63 | const cv::Mat &Blob::getMat() const { 64 | return mat; 65 | } 66 | 67 | int Blob::getWidth() const { 68 | return mat.cols; 69 | } 70 | 71 | int Blob::getHeight() const { 72 | return mat.rows; 73 | } 74 | -------------------------------------------------------------------------------- /BeanCounter/Blob.h: -------------------------------------------------------------------------------- 1 | // 2 | // Blob.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-09. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef BLOB_H 35 | #define BLOB_H 36 | 37 | #include 38 | 39 | class Blob 40 | { 41 | public: 42 | Blob(const cv::Mat &mat, uint32_t label = 0ul); 43 | 44 | /** 45 | * Construct an empty blob. 46 | */ 47 | Blob(); 48 | 49 | /** 50 | * Construct a blob by copying another blob. 51 | */ 52 | Blob(const Blob &other); 53 | 54 | bool isEmpty() const; 55 | 56 | uint32_t getLabel() const; 57 | void setLabel(uint32_t value); 58 | 59 | const cv::Mat &getMat() const; 60 | int getWidth() const; 61 | int getHeight() const; 62 | 63 | private: 64 | uint32_t label; 65 | 66 | cv::Mat mat; 67 | }; 68 | 69 | #endif // BLOB_H 70 | -------------------------------------------------------------------------------- /BeanCounter/BlobClassifier.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BlobClassifier.cpp 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-10. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #include 35 | 36 | #include "BlobClassifier.h" 37 | 38 | #ifdef WITH_OPENCV_CONTRIB 39 | #include 40 | #endif 41 | 42 | const int HISTOGRAM_NUM_BINS_PER_CHANNEL = 32; 43 | const int HISTOGRAM_COMPARISON_METHOD = cv::HISTCMP_CHISQR_ALT; 44 | 45 | const float HISTOGRAM_DISTANCE_WEIGHT = 0.98f; 46 | const float KEYPOINT_MATCHING_DISTANCE_WEIGHT = 1.0f - HISTOGRAM_DISTANCE_WEIGHT; 47 | 48 | BlobClassifier::BlobClassifier() 49 | : clahe(cv::createCLAHE()) 50 | #ifdef WITH_OPENCV_CONTRIB 51 | , featureDetectorAndDescriptorExtractor(cv::xfeatures2d::SURF::create()) 52 | , descriptorMatcher(cv::DescriptorMatcher::create("FlannBased")) 53 | #else 54 | , featureDetectorAndDescriptorExtractor(cv::ORB::create()) 55 | , descriptorMatcher(cv::DescriptorMatcher::create("BruteForce-HammingLUT")) 56 | #endif 57 | { 58 | } 59 | 60 | void BlobClassifier::update(const Blob &referenceBlob) { 61 | referenceBlobDescriptors.push_back(createBlobDescriptor(referenceBlob)); 62 | } 63 | 64 | void BlobClassifier::clear() { 65 | referenceBlobDescriptors.clear(); 66 | } 67 | 68 | void BlobClassifier::classify(Blob &detectedBlob) const { 69 | BlobDescriptor detectedBlobDescriptor = createBlobDescriptor(detectedBlob); 70 | float bestDistance = FLT_MAX; 71 | uint32_t bestLabel = 0; 72 | for (const BlobDescriptor &referenceBlobDescriptor : referenceBlobDescriptors) { 73 | float distance = findDistance(detectedBlobDescriptor, referenceBlobDescriptor); 74 | if (distance < bestDistance) { 75 | bestDistance = distance; 76 | bestLabel = referenceBlobDescriptor.getLabel(); 77 | } 78 | } 79 | detectedBlob.setLabel(bestLabel); 80 | } 81 | 82 | BlobDescriptor BlobClassifier::createBlobDescriptor(const Blob &blob) const { 83 | 84 | const cv::Mat &mat = blob.getMat(); 85 | int numChannels = mat.channels(); 86 | 87 | // Calculate the histogram of the blob's image. 88 | cv::Mat histogram; 89 | int channels[] = { 0, 1, 2 }; 90 | int numBins[] = { HISTOGRAM_NUM_BINS_PER_CHANNEL, HISTOGRAM_NUM_BINS_PER_CHANNEL, HISTOGRAM_NUM_BINS_PER_CHANNEL }; 91 | float range[] = { 0.0f, 256.0f }; 92 | const float *ranges[] = { range, range, range }; 93 | cv::calcHist(&mat, 1, channels, cv::Mat(), histogram, 3, numBins, ranges); 94 | 95 | // Normalize the histogram. 96 | histogram *= (1.0f / (mat.rows * mat.cols)); 97 | 98 | // Convert the blob's image to grayscale. 99 | cv::Mat grayMat; 100 | switch (numChannels) { 101 | case 4: 102 | cv::cvtColor(mat, grayMat, cv::COLOR_BGRA2GRAY); 103 | break; 104 | default: 105 | cv::cvtColor(mat, grayMat, cv::COLOR_BGR2GRAY); 106 | break; 107 | } 108 | 109 | // Adaptively equalize the grayscale image to enhance local contrast. 110 | clahe->apply(grayMat, grayMat); 111 | 112 | // Detect features in the grayscale image. 113 | std::vector keypoints; 114 | featureDetectorAndDescriptorExtractor->detect(grayMat, keypoints); 115 | 116 | // Extract descriptors of the features. 117 | cv::Mat keypointDescriptors; 118 | featureDetectorAndDescriptorExtractor->compute(grayMat, keypoints, keypointDescriptors); 119 | 120 | return BlobDescriptor(histogram, keypointDescriptors, blob.getLabel()); 121 | } 122 | 123 | float BlobClassifier::findDistance(const BlobDescriptor &detectedBlobDescriptor, const BlobDescriptor &referenceBlobDescriptor) const { 124 | 125 | // Calculate the histogram distance. 126 | float histogramDistance = (float)cv::compareHist(detectedBlobDescriptor.getNormalizedHistogram(), referenceBlobDescriptor.getNormalizedHistogram(), HISTOGRAM_COMPARISON_METHOD); 127 | 128 | // Calculate the keypoint matching distance. 129 | float keypointMatchingDistance = 0.0f; 130 | std::vector keypointMatches; 131 | descriptorMatcher->match(detectedBlobDescriptor.getKeypointDescriptors(), referenceBlobDescriptor.getKeypointDescriptors(), keypointMatches); 132 | for (const cv::DMatch &keypointMatch : keypointMatches) { 133 | keypointMatchingDistance += keypointMatch.distance; 134 | } 135 | 136 | return histogramDistance * HISTOGRAM_DISTANCE_WEIGHT + keypointMatchingDistance * KEYPOINT_MATCHING_DISTANCE_WEIGHT; 137 | } 138 | -------------------------------------------------------------------------------- /BeanCounter/BlobClassifier.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlobClassifier.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-10. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef BLOB_CLASSIFIER_H 35 | #define BLOB_CLASSIFIER_H 36 | 37 | #import "Blob.h" 38 | #import "BlobDescriptor.h" 39 | 40 | #include 41 | 42 | class BlobClassifier 43 | { 44 | public: 45 | BlobClassifier(); 46 | 47 | /** 48 | * Add a reference blob to the classification model. 49 | */ 50 | void update(const Blob &referenceBlob); 51 | 52 | /** 53 | * Clear the classification model. 54 | */ 55 | void clear(); 56 | 57 | /** 58 | * Classify a blob that was detected in a scene. 59 | */ 60 | void classify(Blob &detectedBlob) const; 61 | 62 | private: 63 | BlobDescriptor createBlobDescriptor(const Blob &blob) const; 64 | float findDistance(const BlobDescriptor &detectedBlobDescriptor, const BlobDescriptor &referenceBlobDescriptor) const; 65 | 66 | /** 67 | * An adaptive equalizer to enhance local contrast. 68 | */ 69 | cv::Ptr clahe; 70 | 71 | /** 72 | * A feature detector and descriptor extractor. 73 | * It finds features in images. 74 | * Then, it creates descriptors of the features. 75 | */ 76 | cv::Ptr featureDetectorAndDescriptorExtractor; 77 | 78 | /** 79 | * A descriptor matcher. 80 | * It matches features based on their descriptors. 81 | */ 82 | cv::Ptr descriptorMatcher; 83 | 84 | /** 85 | * Descriptors of the reference blobs. 86 | */ 87 | std::vector referenceBlobDescriptors; 88 | }; 89 | 90 | #endif // !BLOB_CLASSIFIER_H 91 | -------------------------------------------------------------------------------- /BeanCounter/BlobClassifierTraining.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | labelDescriptions 6 | 7 | unidentified 8 | Canadian penny 9 | Canadian nickel 10 | Canadian dime 11 | Canadian quarter 12 | loonie, Canadian dollar 13 | toonie, Canadian two-dollar 14 | pinto bean 15 | romano bean 16 | 17 | blobs 18 | 19 | 20 | imageFilename 21 | CanadianNickel_Heads_000.png 22 | label 23 | 2 24 | 25 | 26 | imageFilename 27 | CanadianNickel_Tails_000.png 28 | label 29 | 2 30 | 31 | 32 | imageFilename 33 | CanadianDime_Heads_000.png 34 | label 35 | 3 36 | 37 | 38 | imageFilename 39 | CanadianDime_Tails_000.png 40 | label 41 | 3 42 | 43 | 44 | imageFilename 45 | CanadianQuarter_Heads_000.png 46 | label 47 | 4 48 | 49 | 50 | imageFilename 51 | CanadianQuarter_Tails_000.png 52 | label 53 | 4 54 | 55 | 56 | imageFilename 57 | Loonie_Heads_000.png 58 | label 59 | 5 60 | 61 | 62 | imageFilename 63 | Loonie_Tails_000.png 64 | label 65 | 5 66 | 67 | 68 | imageFilename 69 | Toonie_Heads_000.png 70 | label 71 | 6 72 | 73 | 74 | imageFilename 75 | Toonie_Tails_000.png 76 | label 77 | 6 78 | 79 | 80 | imageFilename 81 | PintoBean_000.png 82 | label 83 | 7 84 | 85 | 86 | imageFilename 87 | RomanoBean_000.png 88 | label 89 | 8 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /BeanCounter/BlobDescriptor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BlobDescriptor.cpp 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-15. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #include "BlobDescriptor.h" 35 | 36 | BlobDescriptor::BlobDescriptor(const cv::Mat &normalizedHistogram, const cv::Mat &keypointDescriptors, uint32_t label) 37 | : normalizedHistogram(normalizedHistogram) 38 | , keypointDescriptors(keypointDescriptors) 39 | , label(label) 40 | { 41 | } 42 | 43 | const cv::Mat &BlobDescriptor::getNormalizedHistogram() const { 44 | return normalizedHistogram; 45 | } 46 | 47 | const cv::Mat &BlobDescriptor::getKeypointDescriptors() const { 48 | return keypointDescriptors; 49 | } 50 | 51 | uint32_t BlobDescriptor::getLabel() const { 52 | return label; 53 | } 54 | -------------------------------------------------------------------------------- /BeanCounter/BlobDescriptor.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlobDescriptor.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-15. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef BLOB_DESCRIPTOR_H 35 | #define BLOB_DESCRIPTOR_H 36 | 37 | #include 38 | 39 | class BlobDescriptor 40 | { 41 | public: 42 | BlobDescriptor(const cv::Mat &normalizedHistogram, const cv::Mat &keypointDescriptors, uint32_t label); 43 | 44 | const cv::Mat &getNormalizedHistogram() const; 45 | const cv::Mat &getKeypointDescriptors() const; 46 | uint32_t getLabel() const; 47 | 48 | private: 49 | cv::Mat normalizedHistogram; 50 | cv::Mat keypointDescriptors; 51 | uint32_t label; 52 | }; 53 | 54 | #endif // !BLOB_DESCRIPTOR_H 55 | -------------------------------------------------------------------------------- /BeanCounter/BlobDetector.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BlobDetector.cpp 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-10. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #include 35 | 36 | #include "BlobDetector.h" 37 | 38 | const double MASK_STD_DEVS_FROM_MEAN = 1.0; 39 | const double MASK_EROSION_KERNEL_RELATIVE_SIZE_IN_IMAGE = 0.005; 40 | const int MASK_NUM_EROSION_ITERATIONS = 8; 41 | 42 | const double BLOB_RELATIVE_MIN_SIZE_IN_IMAGE = 0.05; 43 | 44 | const cv::Scalar DRAW_RECT_COLOR(0, 255, 0); // Green 45 | 46 | void BlobDetector::detect(cv::Mat &image, std::vector &blobs, double resizeFactor, bool draw) 47 | { 48 | blobs.clear(); 49 | 50 | if (resizeFactor == 1.0) { 51 | createMask(image); 52 | } else { 53 | cv::resize(image, resizedImage, cv::Size(), resizeFactor, resizeFactor, cv::INTER_AREA); 54 | createMask(resizedImage); 55 | } 56 | 57 | // Find the edges in the mask. 58 | cv::Canny(mask, edges, 191, 255); 59 | 60 | // Find the contours of the edges. 61 | cv::findContours(edges, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE); 62 | 63 | std::vector rects; 64 | int blobMinSize = (int)(MIN(image.rows, image.cols) * BLOB_RELATIVE_MIN_SIZE_IN_IMAGE); 65 | for (std::vector contour : contours) { 66 | 67 | // Find the contour's bounding rectangle. 68 | cv::Rect rect = cv::boundingRect(contour); 69 | 70 | // Restore the bounding rectangle to the original scale. 71 | rect.x /= resizeFactor; 72 | rect.y /= resizeFactor; 73 | rect.width /= resizeFactor; 74 | rect.height /= resizeFactor; 75 | 76 | if (rect.width < blobMinSize || rect.height < blobMinSize) { 77 | continue; 78 | } 79 | 80 | // Create the blob from the sub-image inside the bounding rectangle. 81 | blobs.push_back(Blob(cv::Mat(image, rect))); 82 | 83 | // Remember the bounding rectangle in order to draw it later. 84 | rects.push_back(rect); 85 | } 86 | 87 | if (draw) { 88 | // Draw the bounding rectangles. 89 | for (const cv::Rect &rect : rects) { 90 | cv::rectangle(image, rect.tl(), rect.br(), DRAW_RECT_COLOR); 91 | } 92 | } 93 | } 94 | 95 | const cv::Mat &BlobDetector::getMask() const { 96 | return mask; 97 | } 98 | 99 | void BlobDetector::createMask(const cv::Mat &image) { 100 | 101 | // Find the image's mean color. 102 | // Presumably, this is the background color. 103 | // Also find the standard deviation. 104 | cv::Scalar meanColor; 105 | cv::Scalar stdDevColor; 106 | cv::meanStdDev(image, meanColor, stdDevColor); 107 | 108 | // Create a mask based on a range around the mean color. 109 | cv::Scalar halfRange = MASK_STD_DEVS_FROM_MEAN * stdDevColor; 110 | cv::Scalar lowerBound = meanColor - halfRange; 111 | cv::Scalar upperBound = meanColor + halfRange; 112 | cv::inRange(image, lowerBound, upperBound, mask); 113 | 114 | // Erode the mask to merge neighboring blobs. 115 | int kernelWidth = (int)(MIN(image.cols, image.rows) * MASK_EROSION_KERNEL_RELATIVE_SIZE_IN_IMAGE); 116 | if (kernelWidth > 0) { 117 | cv::Size kernelSize(kernelWidth, kernelWidth); 118 | cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, kernelSize); 119 | cv::erode(mask, mask, kernel, cv::Point(-1, -1), MASK_NUM_EROSION_ITERATIONS); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /BeanCounter/BlobDetector.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlobDetector.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-10. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef BLOB_DETECTOR_H 35 | #define BLOB_DETECTOR_H 36 | 37 | #include "Blob.h" 38 | 39 | class BlobDetector 40 | { 41 | public: 42 | void detect(cv::Mat &image, std::vector &blob, double resizeFactor = 1.0, bool draw = false); 43 | 44 | const cv::Mat &getMask() const; 45 | 46 | private: 47 | void createMask(const cv::Mat &image); 48 | 49 | cv::Mat resizedImage; 50 | cv::Mat mask; 51 | cv::Mat edges; 52 | std::vector> contours; 53 | std::vector hierarchy; 54 | }; 55 | 56 | #endif // !BLOB_DETECTOR_H 57 | -------------------------------------------------------------------------------- /BeanCounter/CanadianDime_Heads_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/CanadianDime_Heads_000.png -------------------------------------------------------------------------------- /BeanCounter/CanadianDime_Tails_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/CanadianDime_Tails_000.png -------------------------------------------------------------------------------- /BeanCounter/CanadianNickel_Heads_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/CanadianNickel_Heads_000.png -------------------------------------------------------------------------------- /BeanCounter/CanadianNickel_Tails_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/CanadianNickel_Tails_000.png -------------------------------------------------------------------------------- /BeanCounter/CanadianQuarter_Heads_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/CanadianQuarter_Heads_000.png -------------------------------------------------------------------------------- /BeanCounter/CanadianQuarter_Tails_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/CanadianQuarter_Tails_000.png -------------------------------------------------------------------------------- /BeanCounter/CaptureViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CaptureViewController.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-08. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface CaptureViewController : UIViewController 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /BeanCounter/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | video-camera 33 | 34 | UIRequiresFullScreen 35 | 36 | UIStatusBarHidden 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UIViewControllerBasedStatusBarAppearance 52 | 53 | NSCameraUsageDescription 54 | BeanCounter uses the camera to detect objects and take photos. 55 | NSPhotoLibraryUsageDescription 56 | BeanCounter uses the photo library to save photos. 57 | 58 | 59 | -------------------------------------------------------------------------------- /BeanCounter/Loonie_Heads_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Loonie_Heads_000.png -------------------------------------------------------------------------------- /BeanCounter/Loonie_Tails_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Loonie_Tails_000.png -------------------------------------------------------------------------------- /BeanCounter/PintoBean_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/PintoBean_000.png -------------------------------------------------------------------------------- /BeanCounter/ReviewViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewViewController.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-03-12. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface ReviewViewController : UIViewController 37 | 38 | @property UIImage *image; 39 | @property NSString *caption; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /BeanCounter/ReviewViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewViewController.m 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-03-12. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import 36 | 37 | #import "ReviewViewController.h" 38 | 39 | @interface ReviewViewController () 40 | 41 | @property IBOutlet UIImageView *imageView; 42 | @property IBOutlet UILabel *label; 43 | @property IBOutlet UIActivityIndicatorView *activityIndicatorView; 44 | @property IBOutlet UIToolbar *toolbar; 45 | 46 | - (IBAction)onDeleteButtonPressed; 47 | - (IBAction)onSaveButtonPressed; 48 | 49 | - (void)saveImage:(UIImage *)image; 50 | - (void)showSaveImageFailureAlertWithMessage:(NSString *)message; 51 | - (void)showSaveImageSuccessAlertWithImage:(UIImage *)image; 52 | - (UIAlertAction *)shareImageActionWithTitle:(NSString *)title serviceType:(NSString *)serviceType image:(UIImage *)image; 53 | - (void)startBusyMode; 54 | - (void)stopBusyMode; 55 | 56 | @end 57 | 58 | @implementation ReviewViewController 59 | 60 | - (void)viewDidLoad { 61 | [super viewDidLoad]; 62 | 63 | self.imageView.image = self.image; 64 | self.label.text = self.caption; 65 | } 66 | 67 | - (IBAction)onDeleteButtonPressed { 68 | [self dismissViewControllerAnimated:YES completion:nil]; 69 | } 70 | 71 | - (IBAction)onSaveButtonPressed { 72 | [self startBusyMode]; 73 | [self saveImage:self.image]; 74 | } 75 | 76 | - (void)saveImage:(UIImage *)image { 77 | 78 | // Try to save the image to a temporary file. 79 | NSString *outputPath = [NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.png"]; 80 | if (![UIImagePNGRepresentation(image) writeToFile:outputPath atomically:YES]) { 81 | 82 | // Show an alert describing the failure. 83 | [self showSaveImageFailureAlertWithMessage:@"The image could not be saved to the temporary directory."]; 84 | 85 | return; 86 | } 87 | 88 | // Try to add the image to the Photos library. 89 | NSURL *outputURL = [NSURL URLWithString:outputPath]; 90 | PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary]; 91 | [photoLibrary performChanges:^{ 92 | [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:outputURL]; 93 | } completionHandler:^(BOOL success, NSError *error) { 94 | if (success) { 95 | // Show an alert describing the success, with sharing options. 96 | [self showSaveImageSuccessAlertWithImage:image]; 97 | } else { 98 | // Show an alert describing the failure. 99 | [self showSaveImageFailureAlertWithMessage:error.localizedDescription]; 100 | } 101 | }]; 102 | } 103 | 104 | - (void)showSaveImageFailureAlertWithMessage:(NSString *)message { 105 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Failed to save image" message:message preferredStyle:UIAlertControllerStyleAlert]; 106 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 107 | [self stopBusyMode]; 108 | }]; 109 | [alert addAction:okAction]; 110 | [self presentViewController:alert animated:YES completion:nil]; 111 | } 112 | 113 | - (void)showSaveImageSuccessAlertWithImage:(UIImage *)image { 114 | 115 | // Create a "Saved image" alert. 116 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Saved image" message:@"The image has been added to your Photos library. Would you like to share it with your friends?" preferredStyle:UIAlertControllerStyleAlert]; 117 | 118 | // If the user has a Facebook account on this device, add a "Post on Facebook" button to the alert. 119 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) { 120 | UIAlertAction *facebookAction = [self shareImageActionWithTitle:@"Post on Facebook" serviceType:SLServiceTypeFacebook image:image]; 121 | [alert addAction:facebookAction]; 122 | } 123 | 124 | // If the user has a Twitter account on this device, add a "Tweet" button to the alert. 125 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) { 126 | UIAlertAction *twitterAction = [self shareImageActionWithTitle:@"Tweet" serviceType:SLServiceTypeTwitter image:image]; 127 | [alert addAction:twitterAction]; 128 | } 129 | 130 | // If the user has a Sina Weibo account on this device, add a "Post on Sina Weibo" button to the alert. 131 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeSinaWeibo]) { 132 | UIAlertAction *sinaWeiboAction = [self shareImageActionWithTitle:@"Post on Sina Weibo" serviceType:SLServiceTypeSinaWeibo image:image]; 133 | [alert addAction:sinaWeiboAction]; 134 | } 135 | 136 | // If the user has a Tencent Weibo account on this device, add a "Post on Tencent Weibo" button to the alert. 137 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTencentWeibo]) { 138 | UIAlertAction *tencentWeiboAction = [self shareImageActionWithTitle:@"Post on Tencent Weibo" serviceType:SLServiceTypeTencentWeibo image:image]; 139 | [alert addAction:tencentWeiboAction]; 140 | } 141 | 142 | // Add a "Do not share" button to the alert. 143 | UIAlertAction *doNotShareAction = [UIAlertAction actionWithTitle:@"Do not share" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 144 | [self stopBusyMode]; 145 | [self dismissViewControllerAnimated:YES completion:nil]; 146 | }]; 147 | [alert addAction:doNotShareAction]; 148 | 149 | // Show the alert. 150 | [self presentViewController:alert animated:YES completion:nil]; 151 | } 152 | 153 | - (UIAlertAction *)shareImageActionWithTitle:(NSString *)title serviceType:(NSString *)serviceType image:(UIImage *)image { 154 | UIAlertAction *action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 155 | SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:serviceType]; 156 | [composeViewController addImage:image]; 157 | [self presentViewController:composeViewController animated:YES completion:^{ 158 | [self stopBusyMode]; 159 | [self dismissViewControllerAnimated:YES completion:nil]; 160 | }]; 161 | }]; 162 | return action; 163 | } 164 | 165 | - (void)startBusyMode { 166 | dispatch_async(dispatch_get_main_queue(), ^{ 167 | [self.activityIndicatorView startAnimating]; 168 | for (UIBarItem *item in self.toolbar.items) { 169 | item.enabled = NO; 170 | } 171 | }); 172 | } 173 | 174 | - (void)stopBusyMode { 175 | dispatch_async(dispatch_get_main_queue(), ^{ 176 | [self.activityIndicatorView stopAnimating]; 177 | for (UIBarItem *item in self.toolbar.items) { 178 | item.enabled = YES; 179 | } 180 | }); 181 | } 182 | 183 | @end 184 | -------------------------------------------------------------------------------- /BeanCounter/RomanoBean_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/RomanoBean_000.png -------------------------------------------------------------------------------- /BeanCounter/SwitchCamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/SwitchCamera.png -------------------------------------------------------------------------------- /BeanCounter/SwitchCamera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/SwitchCamera@2x.png -------------------------------------------------------------------------------- /BeanCounter/SwitchCamera@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/SwitchCamera@3x.png -------------------------------------------------------------------------------- /BeanCounter/TheQueen'sBeans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/TheQueen'sBeans.jpg -------------------------------------------------------------------------------- /BeanCounter/Toonie_Heads_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Toonie_Heads_000.png -------------------------------------------------------------------------------- /BeanCounter/Toonie_Tails_000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/BeanCounter/Toonie_Tails_000.png -------------------------------------------------------------------------------- /BeanCounter/VideoCamera.h: -------------------------------------------------------------------------------- 1 | // 2 | // VideoCamera.h 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2015-12-11. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | 37 | @interface VideoCamera : CvVideoCamera 38 | 39 | @property BOOL letterboxPreview; 40 | 41 | - (void)setPointOfInterestInParentViewSpace:(CGPoint)point; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /BeanCounter/VideoCamera.m: -------------------------------------------------------------------------------- 1 | // 2 | // VideoCamera.m 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2015-12-11. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "VideoCamera.h" 35 | 36 | 37 | @interface VideoCamera () 38 | 39 | @property (nonatomic, retain) CALayer *customPreviewLayer; 40 | 41 | @end 42 | 43 | 44 | @implementation VideoCamera 45 | 46 | @synthesize customPreviewLayer = _customPreviewLayer; 47 | 48 | - (int)imageWidth { 49 | AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject]; 50 | NSDictionary *videoSettings = [output videoSettings]; 51 | int videoWidth = [[videoSettings objectForKey:@"Width"] intValue]; 52 | return videoWidth; 53 | } 54 | 55 | - (int)imageHeight { 56 | AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject]; 57 | NSDictionary *videoSettings = [output videoSettings]; 58 | int videoHeight = [[videoSettings objectForKey:@"Height"] intValue]; 59 | return videoHeight; 60 | } 61 | 62 | - (void)updateSize { 63 | // Do nothing. 64 | } 65 | 66 | - (void)layoutPreviewLayer { 67 | if (self.parentView != nil) { 68 | 69 | // Center the video preview. 70 | self.customPreviewLayer.position = CGPointMake(0.5 * self.parentView.frame.size.width, 0.5 * self.parentView.frame.size.height); 71 | 72 | // Find the video's aspect ratio. 73 | CGFloat videoAspectRatio = self.imageWidth / (CGFloat)self.imageHeight; 74 | 75 | // Scale the video preview while maintaining its aspect ratio. 76 | CGFloat boundsW; 77 | CGFloat boundsH; 78 | if (self.imageHeight > self.imageWidth) { 79 | if (self.letterboxPreview) { 80 | boundsH = self.parentView.frame.size.height; 81 | boundsW = boundsH * videoAspectRatio; 82 | } else { 83 | boundsW = self.parentView.frame.size.width; 84 | boundsH = boundsW / videoAspectRatio; 85 | } 86 | } else { 87 | if (self.letterboxPreview) { 88 | boundsW = self.parentView.frame.size.width; 89 | boundsH = boundsW / videoAspectRatio; 90 | } else { 91 | boundsH = self.parentView.frame.size.height; 92 | boundsW = boundsH * videoAspectRatio; 93 | } 94 | } 95 | self.customPreviewLayer.bounds = CGRectMake(0.0, 0.0, boundsW, boundsH); 96 | } 97 | } 98 | 99 | - (void)setPointOfInterestInParentViewSpace:(CGPoint)parentViewPoint { 100 | 101 | if (!self.running) { 102 | return; 103 | } 104 | 105 | // Find the current capture device. 106 | NSArray *captureDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 107 | AVCaptureDevice *captureDevice; 108 | for (captureDevice in captureDevices) { 109 | if (captureDevice.position == self.defaultAVCaptureDevicePosition) { 110 | break; 111 | } 112 | } 113 | 114 | BOOL canSetFocus = [captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus] && captureDevice.isFocusPointOfInterestSupported; 115 | 116 | BOOL canSetExposure = [captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose] && captureDevice.isExposurePointOfInterestSupported; 117 | 118 | if (!canSetFocus && ! canSetExposure) { 119 | return; 120 | } 121 | 122 | if (![captureDevice lockForConfiguration:nil]) { 123 | return; 124 | } 125 | 126 | // Find the preview's offset relative to the parent view. 127 | CGFloat offsetX = 0.5 * (self.parentView.bounds.size.width - self.customPreviewLayer.bounds.size.width); 128 | CGFloat offsetY = 0.5 * (self.parentView.bounds.size.height - self.customPreviewLayer.bounds.size.height); 129 | 130 | // Find the focus coordinates, proportional to the preview size. 131 | CGFloat focusX = (parentViewPoint.x - offsetX) / self.customPreviewLayer.bounds.size.width; 132 | CGFloat focusY = (parentViewPoint.y - offsetY) / self.customPreviewLayer.bounds.size.height; 133 | 134 | if (focusX < 0.0 || focusX > 1.0 || focusY < 0.0 || focusY > 1.0) { 135 | // The point is outside the preview. 136 | return; 137 | } 138 | 139 | // Adjust the focus coordinates based on the orientation. 140 | // They should be in the landscape-right coordinate system. 141 | switch (self.defaultAVCaptureVideoOrientation) { 142 | case AVCaptureVideoOrientationPortraitUpsideDown: { 143 | CGFloat oldFocusX = focusX; 144 | focusX = 1.0 - focusY; 145 | focusY = oldFocusX; 146 | break; 147 | } 148 | case AVCaptureVideoOrientationLandscapeLeft: { 149 | focusX = 1.0 - focusX; 150 | focusY = 1.0 - focusY; 151 | break; 152 | } 153 | case AVCaptureVideoOrientationLandscapeRight: { 154 | // Do nothing. 155 | break; 156 | } 157 | default: { // Portrait 158 | CGFloat oldFocusX = focusX; 159 | focusX = focusY; 160 | focusY = 1.0 - oldFocusX; 161 | break; 162 | } 163 | } 164 | 165 | if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { 166 | // De-mirror the X coordinate. 167 | focusX = 1.0 - focusX; 168 | } 169 | 170 | CGPoint focusPoint = CGPointMake(focusX, focusY); 171 | 172 | if (canSetFocus) { 173 | // Auto-focus on the selected point. 174 | captureDevice.focusMode = AVCaptureFocusModeAutoFocus; 175 | captureDevice.focusPointOfInterest = focusPoint; 176 | } 177 | 178 | if (canSetExposure) { 179 | // Auto-expose for the selected point. 180 | captureDevice.exposureMode = AVCaptureExposureModeAutoExpose; 181 | captureDevice.exposurePointOfInterest = focusPoint; 182 | } 183 | 184 | [captureDevice unlockForConfiguration]; 185 | } 186 | 187 | @end 188 | -------------------------------------------------------------------------------- /BeanCounter/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // BeanCounter 4 | // 5 | // Created by Joseph Howse on 2016-04-08. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import "AppDelegate.h" 36 | 37 | int main(int argc, char * argv[]) { 38 | @autoreleasepool { 39 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CoolPig.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CoolPig/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CoolPig 4 | // 5 | // Created by Joseph Howse on 2015-11-03. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface AppDelegate : UIResponder 37 | 38 | @property (strong, nonatomic) UIWindow *window; 39 | 40 | 41 | @end 42 | 43 | -------------------------------------------------------------------------------- /CoolPig/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CoolPig 4 | // 5 | // Created by Joseph Howse on 2015-11-03. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "AppDelegate.h" 35 | 36 | @interface AppDelegate () 37 | 38 | @end 39 | 40 | @implementation AppDelegate 41 | 42 | 43 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 44 | // Override point for customization after application launch. 45 | return YES; 46 | } 47 | 48 | - (void)applicationWillResignActive:(UIApplication *)application { 49 | // 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. 50 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 51 | } 52 | 53 | - (void)applicationDidEnterBackground:(UIApplication *)application { 54 | // 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. 55 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 56 | } 57 | 58 | - (void)applicationWillEnterForeground:(UIApplication *)application { 59 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 60 | } 61 | 62 | - (void)applicationDidBecomeActive:(UIApplication *)application { 63 | // 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. 64 | } 65 | 66 | - (void)applicationWillTerminate:(UIApplication *)application { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png -------------------------------------------------------------------------------- /CoolPig/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon_58.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon_87.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon_80.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "AppIcon_120.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "AppIcon_120-1.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon_180.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "AppIcon_29.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "AppIcon_58-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "AppIcon_40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "AppIcon_80-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "AppIcon_76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "AppIcon_152.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "83.5x83.5", 77 | "idiom" : "ipad", 78 | "filename" : "AppIcon_167.png", 79 | "scale" : "2x" 80 | } 81 | ], 82 | "info" : { 83 | "version" : 1, 84 | "author" : "xcode" 85 | } 86 | } -------------------------------------------------------------------------------- /CoolPig/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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /CoolPig/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 | -------------------------------------------------------------------------------- /CoolPig/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIRequiresFullScreen 34 | 35 | UIStatusBarHidden 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /CoolPig/Piggy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/CoolPig/Piggy.png -------------------------------------------------------------------------------- /CoolPig/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CoolPig 4 | // 5 | // Created by Joseph Howse on 2015-11-03. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface ViewController : UIViewController 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /CoolPig/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CoolPig 4 | // 5 | // Created by Joseph Howse on 2015-11-03. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import 36 | #import 37 | 38 | #ifdef WITH_OPENCV_CONTRIB 39 | #import 40 | #endif 41 | 42 | #import "ViewController.h" 43 | 44 | 45 | #define RAND_0_1() ((double)arc4random() / 0x100000000) 46 | 47 | 48 | @interface ViewController () { 49 | cv::Mat originalMat; 50 | cv::Mat updatedMat; 51 | } 52 | 53 | @property IBOutlet UIImageView *imageView; 54 | @property NSTimer *timer; 55 | 56 | - (void)updateImage; 57 | 58 | @end 59 | 60 | 61 | @implementation ViewController 62 | 63 | - (void)viewDidLoad { 64 | [super viewDidLoad]; 65 | 66 | // Load a UIImage from a resource file. 67 | UIImage *originalImage = [UIImage imageNamed:@"Piggy.png"]; 68 | 69 | // Convert the UIImage to a cv::Mat. 70 | UIImageToMat(originalImage, originalMat); 71 | 72 | switch (originalMat.type()) { 73 | case CV_8UC1: 74 | // The cv::Mat is in grayscale format. 75 | // Convert it to RGB format. 76 | cv::cvtColor(originalMat, originalMat, cv::COLOR_GRAY2RGB); 77 | break; 78 | case CV_8UC4: { 79 | // The cv::Mat is in RGBA format. 80 | // Convert it to RGB format. 81 | cv::cvtColor(originalMat, originalMat, cv::COLOR_RGBA2RGB); 82 | #ifdef WITH_OPENCV_CONTRIB 83 | // Adjust the white balance. 84 | cv::Ptr whiteBalancer = cv::xphoto::createGrayworldWB(); 85 | whiteBalancer->balanceWhite(originalMat, originalMat); 86 | #endif 87 | break; 88 | } 89 | case CV_8UC3: { 90 | // The cv::Mat is in RGB format. 91 | #ifdef WITH_OPENCV_CONTRIB 92 | // Adjust the white balance. 93 | cv::Ptr whiteBalancer = cv::xphoto::createGrayworldWB(); 94 | whiteBalancer->balanceWhite(originalMat, originalMat); 95 | #endif 96 | break; 97 | } 98 | default: 99 | break; 100 | } 101 | 102 | // Call an update method every 2 seconds. 103 | self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateImage) userInfo:nil repeats:YES]; 104 | 105 | // Get a notification center and queue. 106 | // These will provide notifications about application lifecycle events. 107 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 108 | NSOperationQueue *queue = [NSOperationQueue mainQueue]; 109 | 110 | // When the application enters the background, stop the update timer. 111 | [notificationCenter addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:queue usingBlock:^(NSNotification *note) { 112 | [self.timer invalidate]; 113 | self.timer = nil; 114 | }]; 115 | 116 | // When the application re-enters the foreground, restart the update timer. 117 | [notificationCenter addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:queue usingBlock:^(NSNotification *note) { 118 | self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateImage) userInfo:nil repeats:YES]; 119 | }]; 120 | } 121 | 122 | - (void)updateImage { 123 | // Generate a random color. 124 | double r = 0.5 + RAND_0_1() * 1.0; 125 | double g = 0.6 + RAND_0_1() * 0.8; 126 | double b = 0.4 + RAND_0_1() * 1.2; 127 | cv::Scalar randomColor(r, g, b); 128 | 129 | // Create an updated, tinted cv::Mat by multiplying the original cv::Mat and the random color. 130 | cv::multiply(originalMat, randomColor, updatedMat); 131 | 132 | // Convert the updated cv::Mat to a UIImage and display it in the UIImageView. 133 | self.imageView.image = MatToUIImage(updatedMat); 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /CoolPig/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CoolPig 4 | // 5 | // Created by Joseph Howse on 2015-11-03. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import "AppDelegate.h" 36 | 37 | int main(int argc, char * argv[]) { 38 | @autoreleasepool { 39 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ERRATA.md: -------------------------------------------------------------------------------- 1 | # Errata and Updates 2 | 3 | Here are the errata and updates for my book, [iOS Application Development with OpenCV 3](https://www.packtpub.com/application-development/ios-application-development-opencv). Where applicable, revisions have been applied to the source files in this repository. 4 | 5 | ## Compiler warnings about documentation in Xcode 8+ 6 | 7 | Since Xcode 8, new projects are configured by default to use the `-Wdocumentation` compiler flag. This means that the compiler raises warnings if the comments do not follow certain formatting conventions. OpenCV's headers contain many irregularly formatted comments, so you probably want to disable this flag to prevent a flood of unhelpful warnings. To disable it, go to the project's **Build Settings** pane, find the **Apple LLVM 8.0 - Warnings - All languages** section, and set the **Documentation Comments** entry to **No**. 8 | 9 | ## Additional `Info.plist` entries to support iOS 10+ 10 | 11 | Since iOS 10, if an app uses the camera and photo library, the `Info.plist` file must contain the `NSCameraUsageDescription` and `NSPhotoLibraryDescription` keys to describe the way the app uses these features. This new requirement affects the projects in Chapters 2-5. See the latest versions of the `Info.plist` files in this repository. 12 | 13 | ## Page 4-5: Additional steps to run `build_framework.py` 14 | 15 | OpenCV's build process depends on CMake. Before running `build_framework.py`, you must install CMake. You may obtain a `.dmg` installer from the [official CMake downloads page](https://cmake.org/download/). Alternatively, you may install CMake via a package manager such as MacPorts or Homebrew. 16 | 17 | Also, before running `build_framework.py`, you should run the following command to give it executable permissions: 18 | 19 | ``` 20 | $ chmod +x /platforms/ios/build_framework.py 21 | ``` 22 | 23 | When `build_framework.py` works properly, it prints either `** INSTALL SUCCEEDED **` or `** BUILD SUCCEEDED **`, depending on the version. 24 | 25 | ## Page 24-25: New white balance API in `opencv_contrib` 26 | 27 | The white balance API in `opencv_contrib` [changed on August 9, 2016](https://github.com/opencv/opencv_contrib/commit/75dedf9e589b1833d92b6bd644f64ae225795c96). The following code is updated to use the new API: 28 | 29 | ``` 30 | case CV_8UC4: { 31 | // The cv::Mat is in RGBA format. 32 | // Convert it to RGB format. 33 | cv::cvtColor(originalMat, originalMat, cv::COLOR_RGBA2RGB); 34 | #ifdef WITH_OPENCV_CONTRIB 35 | // Adjust the white balance. 36 | cv::Ptr whiteBalancer = cv::xphoto::createGrayworldWB(); 37 | whiteBalancer->balanceWhite(originalMat, originalMat); 38 | #endif 39 | break; 40 | } 41 | case CV_8UC3: { 42 | // The cv::Mat is in RGB format. 43 | #ifdef WITH_OPENCV_CONTRIB 44 | // Adjust the white balance. 45 | cv::Ptr whiteBalancer = cv::xphoto::createGrayworldWB(); 46 | whiteBalancer->balanceWhite(originalMat, originalMat); 47 | #endif 48 | break; 49 | } 50 | ``` 51 | 52 | ## Page 25: Repeating timer must be stopped 53 | 54 | When an `NSTimer` is set up to fire on a repeating basis, it must be explicitly stopped. The following code is corrected to stop the timer when the application enters the background and restart the timer when the application enters the foreground. 55 | 56 | ``` 57 | // Call an update method every 2 seconds. 58 | self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateImage) userInfo:nil repeats:YES]; 59 | 60 | // Get a notification center and queue. 61 | // These will provide notifications about application lifecycle events. 62 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 63 | NSOperationQueue *queue = [NSOperationQueue mainQueue]; 64 | 65 | // When the application enters the background, stop the update timer. 66 | [notificationCenter addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:queue usingBlock:^(NSNotification *note) { 67 | [self.timer invalidate]; 68 | self.timer = nil; 69 | }]; 70 | 71 | // When the application re-enters the foreground, restart the update timer. 72 | [notificationCenter addObserverForName:UIApplicationWillEnterForegroundNotification object:nil queue:queue usingBlock:^(NSNotification *note) { 73 | self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateImage) userInfo:nil repeats:YES]; 74 | }]; 75 | ``` 76 | 77 | ## Page 26: Mouse actions to connect an outlet 78 | 79 | The paragraph beneath the heading "Connecting an interface element to the code" gives an incorrect description of the mouse actions. The following text is corrected: 80 | 81 | > Let's connect the image view in `Main.Storyboard` to the imageView property in `ViewController.m`. Open `Main.Storyboard` in the project navigator and right-click (or *control*-click) on **View Controller** in the scene hierarchy. A dialog with a dark background appears. Inside this dialog, click on the circle beside **Outlets | imageView** and drag it to the **Piggy.png** image view in the scene hierarchy, as shown in the following screenshot: 82 | 83 | ## Page 48: Configuration of a `UIActivityIndicatorView` 84 | 85 | After you add a `UIActivityIndicatorView`, go to the **Attributes** inspector and check the **Hides When Stopped** option. 86 | 87 | ## Page 73: Closing tokens 88 | 89 | A set of closing tokens (`}];`) is missing from the code at the top of the page. The following code is corrected: 90 | 91 | ``` 92 | animated:YES completion:^{ 93 | [self stopBusyMode]; 94 | }]; 95 | }]; 96 | return action; 97 | } 98 | ``` 99 | 100 | ## Page 96: Color conversion 101 | 102 | At the end of the code excerpt, the color conversion logic fails to cover the cases where the source is already grayscale. The following code is corrected: 103 | 104 | ``` 105 | switch (convertedBlendSrcMat.channels()) { 106 | case 1: 107 | if (!self.videoCamera.grayscaleMode) { 108 | cv::cvtColor(convertedBlendSrcMat, convertedBlendSrcMat, cv::COLOR_GRAY2BGRA); 109 | } 110 | break; 111 | default: 112 | if (self.videoCamera.grayscaleMode) { 113 | cv::cvtColor(convertedBlendSrcMat, convertedBlendSrcMat, cv::COLOR_RGBA2GRAY); 114 | } else { 115 | cv::cvtColor(convertedBlendSrcMat, convertedBlendSrcMat, cv::COLOR_RGBA2BGRA); 116 | } 117 | break; 118 | } 119 | ``` 120 | 121 | ## Page 119-124: Changes in `refresh` method 122 | 123 | Generally, these pages cover the changes in the `CaptureViewController` class between the old LightWork project and the new ManyMasks project. However, the book omits the changes in the `refresh` method's implementation. The following code is the correct implementation for ManyMasks: 124 | 125 | ``` 126 | - (void)refresh { 127 | [self.videoCamera stop]; 128 | [self.videoCamera start]; 129 | } 130 | ``` 131 | 132 | ## Page 123: Redundant `if` statement 133 | 134 | The line `if (didDetectFaces) {` and the matching closing brace are mistakenly duplicated on this page. The following code is corrected to remove the redundancy: 135 | 136 | ``` 137 | BOOL didDetectFaces = (detectedFaces.size() > 0); 138 | 139 | if (didDetectFaces) { 140 | // Find the biggest face. 141 | int bestFaceIndex = 0; 142 | for (int i = 0, bestFaceArea = 0; i < detectedFaces.size(); i++) { 143 | Face &detectedFace = detectedFaces[i]; 144 | int faceArea = detectedFace.getWidth() * detectedFace.getHeight(); 145 | if (faceArea > bestFaceArea) { 146 | bestFaceIndex = i; 147 | bestFaceArea = faceArea; 148 | } 149 | } 150 | bestDetectedFace = detectedFaces[bestFaceIndex]; 151 | } 152 | ``` 153 | -------------------------------------------------------------------------------- /LightWork.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LightWork/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LightWork 4 | // 5 | // Created by Joseph Howse on 2015-12-09. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface AppDelegate : UIResponder 37 | 38 | @property (strong, nonatomic) UIWindow *window; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LightWork/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LightWork 4 | // 5 | // Created by Joseph Howse on 2015-12-09. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "AppDelegate.h" 35 | 36 | @interface AppDelegate () 37 | 38 | @end 39 | 40 | @implementation AppDelegate 41 | 42 | 43 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 44 | // Override point for customization after application launch. 45 | return YES; 46 | } 47 | 48 | - (void)applicationWillResignActive:(UIApplication *)application { 49 | // 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. 50 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 51 | } 52 | 53 | - (void)applicationDidEnterBackground:(UIApplication *)application { 54 | // 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. 55 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 56 | } 57 | 58 | - (void)applicationWillEnterForeground:(UIApplication *)application { 59 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 60 | } 61 | 62 | - (void)applicationDidBecomeActive:(UIApplication *)application { 63 | // 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. 64 | } 65 | 66 | - (void)applicationWillTerminate:(UIApplication *)application { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png -------------------------------------------------------------------------------- /LightWork/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon_58.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon_87.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon_80.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "AppIcon_120.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "AppIcon_120-1.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon_180.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "AppIcon_29.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "AppIcon_58-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "AppIcon_40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "AppIcon_80-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "AppIcon_76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "AppIcon_152.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "83.5x83.5", 77 | "idiom" : "ipad", 78 | "filename" : "AppIcon_167.png", 79 | "scale" : "2x" 80 | } 81 | ], 82 | "info" : { 83 | "version" : 1, 84 | "author" : "xcode" 85 | } 86 | } -------------------------------------------------------------------------------- /LightWork/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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /LightWork/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 | 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /LightWork/Fleur.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/Fleur.jpg -------------------------------------------------------------------------------- /LightWork/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | video-camera 33 | 34 | UIRequiresFullScreen 35 | 36 | UIStatusBarHidden 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UIViewControllerBasedStatusBarAppearance 52 | 53 | NSCameraUsageDescription 54 | LightWork uses the camera to take photos. 55 | NSPhotoLibraryUsageDescription 56 | LightWork uses the photo library to save photos. 57 | 58 | 59 | -------------------------------------------------------------------------------- /LightWork/SwitchCamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/SwitchCamera.png -------------------------------------------------------------------------------- /LightWork/SwitchCamera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/SwitchCamera@2x.png -------------------------------------------------------------------------------- /LightWork/SwitchCamera@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/LightWork/SwitchCamera@3x.png -------------------------------------------------------------------------------- /LightWork/VideoCamera.h: -------------------------------------------------------------------------------- 1 | // 2 | // VideoCamera.h 3 | // LightWork 4 | // 5 | // Created by Joseph Howse on 2015-12-11. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | 37 | @interface VideoCamera : CvVideoCamera 38 | 39 | @property BOOL letterboxPreview; 40 | 41 | - (void)setPointOfInterestInParentViewSpace:(CGPoint)point; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /LightWork/VideoCamera.m: -------------------------------------------------------------------------------- 1 | // 2 | // VideoCamera.m 3 | // LightWork 4 | // 5 | // Created by Joseph Howse on 2015-12-11. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "VideoCamera.h" 35 | 36 | 37 | @interface VideoCamera () 38 | 39 | @property (nonatomic, retain) CALayer *customPreviewLayer; 40 | 41 | @end 42 | 43 | 44 | @implementation VideoCamera 45 | 46 | @synthesize customPreviewLayer = _customPreviewLayer; 47 | 48 | - (int)imageWidth { 49 | AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject]; 50 | NSDictionary *videoSettings = [output videoSettings]; 51 | int videoWidth = [[videoSettings objectForKey:@"Width"] intValue]; 52 | return videoWidth; 53 | } 54 | 55 | - (int)imageHeight { 56 | AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject]; 57 | NSDictionary *videoSettings = [output videoSettings]; 58 | int videoHeight = [[videoSettings objectForKey:@"Height"] intValue]; 59 | return videoHeight; 60 | } 61 | 62 | - (void)updateSize { 63 | // Do nothing. 64 | } 65 | 66 | - (void)layoutPreviewLayer { 67 | if (self.parentView != nil) { 68 | 69 | // Center the video preview. 70 | self.customPreviewLayer.position = CGPointMake(0.5 * self.parentView.frame.size.width, 0.5 * self.parentView.frame.size.height); 71 | 72 | // Find the video's aspect ratio. 73 | CGFloat videoAspectRatio = self.imageWidth / (CGFloat)self.imageHeight; 74 | 75 | // Scale the video preview while maintaining its aspect ratio. 76 | CGFloat boundsW; 77 | CGFloat boundsH; 78 | if (self.imageHeight > self.imageWidth) { 79 | if (self.letterboxPreview) { 80 | boundsH = self.parentView.frame.size.height; 81 | boundsW = boundsH * videoAspectRatio; 82 | } else { 83 | boundsW = self.parentView.frame.size.width; 84 | boundsH = boundsW / videoAspectRatio; 85 | } 86 | } else { 87 | if (self.letterboxPreview) { 88 | boundsW = self.parentView.frame.size.width; 89 | boundsH = boundsW / videoAspectRatio; 90 | } else { 91 | boundsH = self.parentView.frame.size.height; 92 | boundsW = boundsH * videoAspectRatio; 93 | } 94 | } 95 | self.customPreviewLayer.bounds = CGRectMake(0.0, 0.0, boundsW, boundsH); 96 | } 97 | } 98 | 99 | - (void)setPointOfInterestInParentViewSpace:(CGPoint)parentViewPoint { 100 | 101 | if (!self.running) { 102 | return; 103 | } 104 | 105 | // Find the current capture device. 106 | NSArray *captureDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 107 | AVCaptureDevice *captureDevice; 108 | for (captureDevice in captureDevices) { 109 | if (captureDevice.position == self.defaultAVCaptureDevicePosition) { 110 | break; 111 | } 112 | } 113 | 114 | BOOL canSetFocus = [captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus] && captureDevice.isFocusPointOfInterestSupported; 115 | 116 | BOOL canSetExposure = [captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose] && captureDevice.isExposurePointOfInterestSupported; 117 | 118 | if (!canSetFocus && ! canSetExposure) { 119 | return; 120 | } 121 | 122 | if (![captureDevice lockForConfiguration:nil]) { 123 | return; 124 | } 125 | 126 | // Find the preview's offset relative to the parent view. 127 | CGFloat offsetX = 0.5 * (self.parentView.bounds.size.width - self.customPreviewLayer.bounds.size.width); 128 | CGFloat offsetY = 0.5 * (self.parentView.bounds.size.height - self.customPreviewLayer.bounds.size.height); 129 | 130 | // Find the focus coordinates, proportional to the preview size. 131 | CGFloat focusX = (parentViewPoint.x - offsetX) / self.customPreviewLayer.bounds.size.width; 132 | CGFloat focusY = (parentViewPoint.y - offsetY) / self.customPreviewLayer.bounds.size.height; 133 | 134 | if (focusX < 0.0 || focusX > 1.0 || focusY < 0.0 || focusY > 1.0) { 135 | // The point is outside the preview. 136 | return; 137 | } 138 | 139 | // Adjust the focus coordinates based on the orientation. 140 | // They should be in the landscape-right coordinate system. 141 | switch (self.defaultAVCaptureVideoOrientation) { 142 | case AVCaptureVideoOrientationPortraitUpsideDown: { 143 | CGFloat oldFocusX = focusX; 144 | focusX = 1.0 - focusY; 145 | focusY = oldFocusX; 146 | break; 147 | } 148 | case AVCaptureVideoOrientationLandscapeLeft: { 149 | focusX = 1.0 - focusX; 150 | focusY = 1.0 - focusY; 151 | break; 152 | } 153 | case AVCaptureVideoOrientationLandscapeRight: { 154 | // Do nothing. 155 | break; 156 | } 157 | default: { // Portrait 158 | CGFloat oldFocusX = focusX; 159 | focusX = focusY; 160 | focusY = 1.0 - oldFocusX; 161 | break; 162 | } 163 | } 164 | 165 | if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { 166 | // De-mirror the X coordinate. 167 | focusX = 1.0 - focusX; 168 | } 169 | 170 | CGPoint focusPoint = CGPointMake(focusX, focusY); 171 | 172 | if (canSetFocus) { 173 | // Auto-focus on the selected point. 174 | captureDevice.focusMode = AVCaptureFocusModeAutoFocus; 175 | captureDevice.focusPointOfInterest = focusPoint; 176 | } 177 | 178 | if (canSetExposure) { 179 | // Auto-expose for the selected point. 180 | captureDevice.exposureMode = AVCaptureExposureModeAutoExpose; 181 | captureDevice.exposurePointOfInterest = focusPoint; 182 | } 183 | 184 | [captureDevice unlockForConfiguration]; 185 | } 186 | 187 | @end 188 | -------------------------------------------------------------------------------- /LightWork/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LightWork 4 | // 5 | // Created by Joseph Howse on 2015-12-09. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface ViewController : UIViewController 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /LightWork/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LightWork 4 | // 5 | // Created by Joseph Howse on 2015-12-09. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import "AppDelegate.h" 36 | 37 | int main(int argc, char * argv[]) { 38 | @autoreleasepool { 39 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ManyMasks.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ManyMasks/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface AppDelegate : UIResponder 37 | 38 | @property (strong, nonatomic) UIWindow *window; 39 | 40 | 41 | @end 42 | 43 | -------------------------------------------------------------------------------- /ManyMasks/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "AppDelegate.h" 35 | 36 | @interface AppDelegate () 37 | 38 | @end 39 | 40 | @implementation AppDelegate 41 | 42 | 43 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 44 | // Override point for customization after application launch. 45 | return YES; 46 | } 47 | 48 | - (void)applicationWillResignActive:(UIApplication *)application { 49 | // 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. 50 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 51 | } 52 | 53 | - (void)applicationDidEnterBackground:(UIApplication *)application { 54 | // 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. 55 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 56 | } 57 | 58 | - (void)applicationWillEnterForeground:(UIApplication *)application { 59 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 60 | } 61 | 62 | - (void)applicationDidBecomeActive:(UIApplication *)application { 63 | // 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. 64 | } 65 | 66 | - (void)applicationWillTerminate:(UIApplication *)application { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_120-1.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_120.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_152.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_167.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_180.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_29.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_40.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_58-1.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_58.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_76.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_80-1.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_80.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Assets.xcassets/AppIcon.appiconset/AppIcon_87.png -------------------------------------------------------------------------------- /ManyMasks/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon_58.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon_87.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon_80.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "AppIcon_120.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "AppIcon_120-1.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon_180.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "AppIcon_29.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "AppIcon_58-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "AppIcon_40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "AppIcon_80-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "AppIcon_76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "AppIcon_152.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "83.5x83.5", 77 | "idiom" : "ipad", 78 | "filename" : "AppIcon_167.png", 79 | "scale" : "2x" 80 | } 81 | ], 82 | "info" : { 83 | "version" : 1, 84 | "author" : "xcode" 85 | } 86 | } -------------------------------------------------------------------------------- /ManyMasks/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 | 27 | 28 | -------------------------------------------------------------------------------- /ManyMasks/CaptureViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CaptureViewController.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface CaptureViewController : UIViewController 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /ManyMasks/Face.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Face.cpp 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #include 35 | 36 | #include "Face.h" 37 | 38 | Face::Face(Species species, const cv::Mat &mat, const cv::Point2f &leftEyeCenter, const cv::Point2f &rightEyeCenter, const cv::Point2f &noseTip) 39 | : species(species) 40 | , leftEyeCenter(leftEyeCenter) 41 | , rightEyeCenter(rightEyeCenter) 42 | , noseTip(noseTip) 43 | { 44 | mat.copyTo(this->mat); 45 | } 46 | 47 | Face::Face() { 48 | } 49 | 50 | Face::Face(const Face &other) 51 | : species(other.species) 52 | , leftEyeCenter(other.leftEyeCenter) 53 | , rightEyeCenter(other.rightEyeCenter) 54 | , noseTip(other.noseTip) 55 | { 56 | other.mat.copyTo(mat); 57 | } 58 | 59 | Face::Face(const Face &face0, const Face &face1) { 60 | if (face0.mat.total() > face1.mat.total()) { 61 | initMergedFace(face0, face1); 62 | } else { 63 | initMergedFace(face1, face0); 64 | } 65 | } 66 | 67 | bool Face::isEmpty() const { 68 | return mat.empty(); 69 | } 70 | 71 | Species Face::getSpecies() const { 72 | return species; 73 | } 74 | 75 | const cv::Mat &Face::getMat() const { 76 | return mat; 77 | } 78 | 79 | int Face::getWidth() const { 80 | return mat.cols; 81 | } 82 | 83 | int Face::getHeight() const { 84 | return mat.rows; 85 | } 86 | 87 | const cv::Point2f &Face::getLeftEyeCenter() const { 88 | return leftEyeCenter; 89 | } 90 | 91 | const cv::Point2f &Face::getRightEyeCenter() const { 92 | return rightEyeCenter; 93 | } 94 | 95 | const cv::Point2f &Face::getNoseTip() const { 96 | return noseTip; 97 | } 98 | 99 | void Face::initMergedFace(const Face &biggerFace, const Face &smallerFace) { 100 | 101 | // Determine the species of the merged face. 102 | if (biggerFace.species == Human && smallerFace.species == Human) { 103 | species = Human; 104 | } else if (biggerFace.species == Cat && smallerFace.species == Cat) { 105 | species = Cat; 106 | } else { 107 | species = Hybrid; 108 | } 109 | 110 | // Warp the smaller face to align the eyes and nose with the bigger face. 111 | cv::Point2f srcPoints[3] = { 112 | smallerFace.getLeftEyeCenter(), 113 | smallerFace.getRightEyeCenter(), 114 | smallerFace.getNoseTip() 115 | }; 116 | cv::Point2f dstPoints[3] = { 117 | biggerFace.leftEyeCenter, 118 | biggerFace.rightEyeCenter, 119 | biggerFace.noseTip 120 | }; 121 | cv::Mat affineTransform = cv::getAffineTransform(srcPoints, dstPoints); 122 | cv::Size dstSize(biggerFace.mat.cols, biggerFace.mat.rows); 123 | cv::warpAffine(smallerFace.mat, mat, affineTransform, dstSize); 124 | 125 | // Perform any necessary color conversion. 126 | // Then, blend the warped face and the original bigger face. 127 | switch (mat.channels() - biggerFace.mat.channels()) { 128 | case 3: { 129 | // The warped face is BGRA and the bigger face is grayscale. 130 | cv::Mat otherMat; 131 | cv::cvtColor(biggerFace.mat, otherMat, cv::COLOR_GRAY2BGRA); 132 | cv::multiply(mat, otherMat, mat, 1.0 / 255.0); 133 | break; 134 | } 135 | case 2: { 136 | // The warped face is BGR and the bigger face is grayscale. 137 | cv::Mat otherMat; 138 | cv::cvtColor(biggerFace.mat, otherMat, cv::COLOR_GRAY2BGR); 139 | cv::multiply(mat, otherMat, mat, 1.0 / 255.0); 140 | break; 141 | } 142 | case 1: { 143 | // The warped face is BGRA and the bigger face is BGR. 144 | cv::Mat otherMat; 145 | cv::cvtColor(biggerFace.mat, otherMat, cv::COLOR_BGR2BGRA); 146 | cv::multiply(mat, otherMat, mat, 1.0 / 255.0); 147 | break; 148 | } 149 | case -1: 150 | // The warped face is BGR and the bigger face is BGRA. 151 | cv::cvtColor(mat, mat, cv::COLOR_BGR2BGRA); 152 | cv::multiply(mat, biggerFace.mat, mat, 1.0 / 255.0); 153 | break; 154 | case -2: 155 | // The warped face is grayscale and the bigger face is BGR. 156 | cv::cvtColor(mat, mat, cv::COLOR_GRAY2BGR); 157 | cv::multiply(mat, biggerFace.mat, mat, 1.0 / 255.0); 158 | break; 159 | case -3: 160 | // The warped face is grayscale and the bigger face is BGRA. 161 | cv::cvtColor(mat, mat, cv::COLOR_GRAY2BGRA); 162 | cv::multiply(mat, biggerFace.mat, mat, 1.0 / 255.0); 163 | break; 164 | default: 165 | // The color formats are the same. 166 | cv::multiply(mat, biggerFace.mat, mat, 1.0 / 255.0); 167 | break; 168 | } 169 | 170 | // The points of interest match the original bigger face. 171 | leftEyeCenter = biggerFace.leftEyeCenter; 172 | rightEyeCenter = biggerFace.rightEyeCenter; 173 | noseTip = biggerFace.noseTip; 174 | } 175 | -------------------------------------------------------------------------------- /ManyMasks/Face.h: -------------------------------------------------------------------------------- 1 | // 2 | // Face.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef FACE_H 35 | #define FACE_H 36 | 37 | #include 38 | 39 | #include "Species.h" 40 | 41 | class Face { 42 | 43 | public: 44 | Face(Species species, const cv::Mat &mat, const cv::Point2f &leftEyeCenter, const cv::Point2f &rightEyeCenter, const cv::Point2f &noseTip); 45 | 46 | /** 47 | * Construct an empty face. 48 | */ 49 | Face(); 50 | 51 | /** 52 | * Construct a face by copying another face. 53 | */ 54 | Face(const Face &other); 55 | 56 | /** 57 | * Construct a face by merging two other faces. 58 | */ 59 | Face(const Face &face0, const Face &face1); 60 | 61 | bool isEmpty() const; 62 | 63 | Species getSpecies() const; 64 | 65 | const cv::Mat &getMat() const; 66 | int getWidth() const; 67 | int getHeight() const; 68 | 69 | const cv::Point2f &getLeftEyeCenter() const; 70 | const cv::Point2f &getRightEyeCenter() const; 71 | const cv::Point2f &getNoseTip() const; 72 | 73 | private: 74 | void initMergedFace(const Face &biggerFace, const Face &smallerFace); 75 | 76 | Species species; 77 | 78 | cv::Mat mat; 79 | 80 | cv::Point2f leftEyeCenter; 81 | cv::Point2f rightEyeCenter; 82 | cv::Point2f noseTip; 83 | }; 84 | 85 | #endif // !FACE_H 86 | -------------------------------------------------------------------------------- /ManyMasks/FaceDetector.h: -------------------------------------------------------------------------------- 1 | // 2 | // FaceDetector.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-06. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef FACE_DETECTOR_H 35 | #define FACE_DETECTOR_H 36 | 37 | #include 38 | 39 | #include "Face.h" 40 | 41 | class FaceDetector { 42 | 43 | public: 44 | FaceDetector(const std::string &humanFaceCascadePath, const std::string &catFaceCascadePath, const std::string &humanLeftEyeCascadePath, const std::string &humanRightEyeCascadePath); 45 | 46 | void detect(cv::Mat &image, std::vector &faces, double resizeFactor = 1.0, bool draw = false); 47 | 48 | private: 49 | void equalize(const cv::Mat &image); 50 | void detectInnerComponents(cv::Mat &image, std::vector &faces, double resizeFactor, bool draw, Species species, cv::Rect faceRect); 51 | 52 | cv::CascadeClassifier humanFaceClassifier; 53 | cv::CascadeClassifier catFaceClassifier; 54 | cv::CascadeClassifier humanLeftEyeClassifier; 55 | cv::CascadeClassifier humanRightEyeClassifier; 56 | 57 | #ifdef WITH_CLAHE 58 | cv::Ptr clahe; 59 | #endif 60 | 61 | cv::Mat resizedImage; 62 | cv::Mat equalizedImage; 63 | }; 64 | 65 | #endif // !FACE_DETECTOR_H 66 | -------------------------------------------------------------------------------- /ManyMasks/GeomUtils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // GeomUtils.cpp 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-12. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #include "GeomUtils.h" 35 | 36 | bool GeomUtils::intersects(const cv::Rect &rect0, const cv::Rect &rect1) 37 | { 38 | return 39 | rect0.x < rect1.x + rect1.width && 40 | rect0.x + rect0.width > rect1.x && 41 | rect0.y < rect1.y + rect1.height && 42 | rect0.y + rect0.height > rect1.y; 43 | } -------------------------------------------------------------------------------- /ManyMasks/GeomUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // GeomUtils.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-12. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef GEOM_UTILS_H 35 | #define GEOM_UTILS_H 36 | 37 | #include 38 | 39 | namespace GeomUtils { 40 | bool intersects(const cv::Rect &rect0, const cv::Rect &rect1); 41 | } 42 | 43 | #endif // !GEOM_UTILS_H 44 | -------------------------------------------------------------------------------- /ManyMasks/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | video-camera 33 | 34 | UIRequiresFullScreen 35 | 36 | UIStatusBarHidden 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UIViewControllerBasedStatusBarAppearance 52 | 53 | NSCameraUsageDescription 54 | ManyMasks uses the camera to detect faces and take photos. 55 | NSPhotoLibraryUsageDescription 56 | ManyMasks uses the photo library to save photos. 57 | 58 | 59 | -------------------------------------------------------------------------------- /ManyMasks/Mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/Mask.png -------------------------------------------------------------------------------- /ManyMasks/ReviewViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewViewController.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-12. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | @interface ReviewViewController : UIViewController 37 | 38 | @property UIImage *image; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /ManyMasks/ReviewViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ReviewViewController.m 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-12. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import 36 | 37 | #import "ReviewViewController.h" 38 | 39 | @interface ReviewViewController () 40 | 41 | @property IBOutlet UIImageView *imageView; 42 | @property IBOutlet UIActivityIndicatorView *activityIndicatorView; 43 | @property IBOutlet UIToolbar *toolbar; 44 | 45 | - (IBAction)onDeleteButtonPressed; 46 | - (IBAction)onSaveButtonPressed; 47 | 48 | - (void)saveImage:(UIImage *)image; 49 | - (void)showSaveImageFailureAlertWithMessage:(NSString *)message; 50 | - (void)showSaveImageSuccessAlertWithImage:(UIImage *)image; 51 | - (UIAlertAction *)shareImageActionWithTitle:(NSString *)title serviceType:(NSString *)serviceType image:(UIImage *)image; 52 | - (void)startBusyMode; 53 | - (void)stopBusyMode; 54 | 55 | @end 56 | 57 | @implementation ReviewViewController 58 | 59 | - (void)viewDidLoad { 60 | [super viewDidLoad]; 61 | 62 | self.imageView.image = self.image; 63 | } 64 | 65 | - (IBAction)onDeleteButtonPressed { 66 | [self dismissViewControllerAnimated:YES completion:nil]; 67 | } 68 | 69 | - (IBAction)onSaveButtonPressed { 70 | [self startBusyMode]; 71 | [self saveImage:self.image]; 72 | } 73 | 74 | - (void)saveImage:(UIImage *)image { 75 | 76 | // Try to save the image to a temporary file. 77 | NSString *outputPath = [NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.png"]; 78 | if (![UIImagePNGRepresentation(image) writeToFile:outputPath atomically:YES]) { 79 | 80 | // Show an alert describing the failure. 81 | [self showSaveImageFailureAlertWithMessage:@"The image could not be saved to the temporary directory."]; 82 | 83 | return; 84 | } 85 | 86 | // Try to add the image to the Photos library. 87 | NSURL *outputURL = [NSURL URLWithString:outputPath]; 88 | PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary]; 89 | [photoLibrary performChanges:^{ 90 | [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:outputURL]; 91 | } completionHandler:^(BOOL success, NSError *error) { 92 | if (success) { 93 | // Show an alert describing the success, with sharing options. 94 | [self showSaveImageSuccessAlertWithImage:image]; 95 | } else { 96 | // Show an alert describing the failure. 97 | [self showSaveImageFailureAlertWithMessage:error.localizedDescription]; 98 | } 99 | }]; 100 | } 101 | 102 | - (void)showSaveImageFailureAlertWithMessage:(NSString *)message { 103 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Failed to save image" message:message preferredStyle:UIAlertControllerStyleAlert]; 104 | UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 105 | [self stopBusyMode]; 106 | }]; 107 | [alert addAction:okAction]; 108 | [self presentViewController:alert animated:YES completion:nil]; 109 | } 110 | 111 | - (void)showSaveImageSuccessAlertWithImage:(UIImage *)image { 112 | 113 | // Create a "Saved image" alert. 114 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Saved image" message:@"The image has been added to your Photos library. Would you like to share it with your friends?" preferredStyle:UIAlertControllerStyleAlert]; 115 | 116 | // If the user has a Facebook account on this device, add a "Post on Facebook" button to the alert. 117 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) { 118 | UIAlertAction *facebookAction = [self shareImageActionWithTitle:@"Post on Facebook" serviceType:SLServiceTypeFacebook image:image]; 119 | [alert addAction:facebookAction]; 120 | } 121 | 122 | // If the user has a Twitter account on this device, add a "Tweet" button to the alert. 123 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) { 124 | UIAlertAction *twitterAction = [self shareImageActionWithTitle:@"Tweet" serviceType:SLServiceTypeTwitter image:image]; 125 | [alert addAction:twitterAction]; 126 | } 127 | 128 | // If the user has a Sina Weibo account on this device, add a "Post on Sina Weibo" button to the alert. 129 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeSinaWeibo]) { 130 | UIAlertAction *sinaWeiboAction = [self shareImageActionWithTitle:@"Post on Sina Weibo" serviceType:SLServiceTypeSinaWeibo image:image]; 131 | [alert addAction:sinaWeiboAction]; 132 | } 133 | 134 | // If the user has a Tencent Weibo account on this device, add a "Post on Tencent Weibo" button to the alert. 135 | if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTencentWeibo]) { 136 | UIAlertAction *tencentWeiboAction = [self shareImageActionWithTitle:@"Post on Tencent Weibo" serviceType:SLServiceTypeTencentWeibo image:image]; 137 | [alert addAction:tencentWeiboAction]; 138 | } 139 | 140 | // Add a "Do not share" button to the alert. 141 | UIAlertAction *doNotShareAction = [UIAlertAction actionWithTitle:@"Do not share" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 142 | [self stopBusyMode]; 143 | [self dismissViewControllerAnimated:YES completion:nil]; 144 | }]; 145 | [alert addAction:doNotShareAction]; 146 | 147 | // Show the alert. 148 | [self presentViewController:alert animated:YES completion:nil]; 149 | } 150 | 151 | - (UIAlertAction *)shareImageActionWithTitle:(NSString *)title serviceType:(NSString *)serviceType image:(UIImage *)image { 152 | UIAlertAction *action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 153 | SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:serviceType]; 154 | [composeViewController addImage:image]; 155 | [self presentViewController:composeViewController animated:YES completion:^{ 156 | [self stopBusyMode]; 157 | [self dismissViewControllerAnimated:YES completion:nil]; 158 | }]; 159 | }]; 160 | return action; 161 | } 162 | 163 | - (void)startBusyMode { 164 | dispatch_async(dispatch_get_main_queue(), ^{ 165 | [self.activityIndicatorView startAnimating]; 166 | for (UIBarItem *item in self.toolbar.items) { 167 | item.enabled = NO; 168 | } 169 | }); 170 | } 171 | 172 | - (void)stopBusyMode { 173 | dispatch_async(dispatch_get_main_queue(), ^{ 174 | [self.activityIndicatorView stopAnimating]; 175 | for (UIBarItem *item in self.toolbar.items) { 176 | item.enabled = YES; 177 | } 178 | }); 179 | } 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /ManyMasks/Species.h: -------------------------------------------------------------------------------- 1 | // 2 | // Species.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #ifndef SPECIES_H 35 | #define SPECIES_H 36 | 37 | enum Species { 38 | Human, 39 | Cat, 40 | Hybrid 41 | }; 42 | 43 | #endif // !SPECIES_H 44 | -------------------------------------------------------------------------------- /ManyMasks/SwitchCamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/SwitchCamera.png -------------------------------------------------------------------------------- /ManyMasks/SwitchCamera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/SwitchCamera@2x.png -------------------------------------------------------------------------------- /ManyMasks/SwitchCamera@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoeHowse/iOSWithOpenCV/0d8efb73aec481f405c2e0eb38b8327b12c7922d/ManyMasks/SwitchCamera@3x.png -------------------------------------------------------------------------------- /ManyMasks/VideoCamera.h: -------------------------------------------------------------------------------- 1 | // 2 | // VideoCamera.h 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2015-12-11. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | 36 | 37 | @interface VideoCamera : CvVideoCamera 38 | 39 | @property BOOL letterboxPreview; 40 | 41 | - (void)setPointOfInterestInParentViewSpace:(CGPoint)point; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /ManyMasks/VideoCamera.m: -------------------------------------------------------------------------------- 1 | // 2 | // VideoCamera.m 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2015-12-11. 6 | // Copyright © 2015 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import "VideoCamera.h" 35 | 36 | 37 | @interface VideoCamera () 38 | 39 | @property (nonatomic, retain) CALayer *customPreviewLayer; 40 | 41 | @end 42 | 43 | 44 | @implementation VideoCamera 45 | 46 | @synthesize customPreviewLayer = _customPreviewLayer; 47 | 48 | - (int)imageWidth { 49 | AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject]; 50 | NSDictionary *videoSettings = [output videoSettings]; 51 | int videoWidth = [[videoSettings objectForKey:@"Width"] intValue]; 52 | return videoWidth; 53 | } 54 | 55 | - (int)imageHeight { 56 | AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject]; 57 | NSDictionary *videoSettings = [output videoSettings]; 58 | int videoHeight = [[videoSettings objectForKey:@"Height"] intValue]; 59 | return videoHeight; 60 | } 61 | 62 | - (void)updateSize { 63 | // Do nothing. 64 | } 65 | 66 | - (void)layoutPreviewLayer { 67 | if (self.parentView != nil) { 68 | 69 | // Center the video preview. 70 | self.customPreviewLayer.position = CGPointMake(0.5 * self.parentView.frame.size.width, 0.5 * self.parentView.frame.size.height); 71 | 72 | // Find the video's aspect ratio. 73 | CGFloat videoAspectRatio = self.imageWidth / (CGFloat)self.imageHeight; 74 | 75 | // Scale the video preview while maintaining its aspect ratio. 76 | CGFloat boundsW; 77 | CGFloat boundsH; 78 | if (self.imageHeight > self.imageWidth) { 79 | if (self.letterboxPreview) { 80 | boundsH = self.parentView.frame.size.height; 81 | boundsW = boundsH * videoAspectRatio; 82 | } else { 83 | boundsW = self.parentView.frame.size.width; 84 | boundsH = boundsW / videoAspectRatio; 85 | } 86 | } else { 87 | if (self.letterboxPreview) { 88 | boundsW = self.parentView.frame.size.width; 89 | boundsH = boundsW / videoAspectRatio; 90 | } else { 91 | boundsH = self.parentView.frame.size.height; 92 | boundsW = boundsH * videoAspectRatio; 93 | } 94 | } 95 | self.customPreviewLayer.bounds = CGRectMake(0.0, 0.0, boundsW, boundsH); 96 | } 97 | } 98 | 99 | - (void)setPointOfInterestInParentViewSpace:(CGPoint)parentViewPoint { 100 | 101 | if (!self.running) { 102 | return; 103 | } 104 | 105 | // Find the current capture device. 106 | NSArray *captureDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 107 | AVCaptureDevice *captureDevice; 108 | for (captureDevice in captureDevices) { 109 | if (captureDevice.position == self.defaultAVCaptureDevicePosition) { 110 | break; 111 | } 112 | } 113 | 114 | BOOL canSetFocus = [captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus] && captureDevice.isFocusPointOfInterestSupported; 115 | 116 | BOOL canSetExposure = [captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose] && captureDevice.isExposurePointOfInterestSupported; 117 | 118 | if (!canSetFocus && ! canSetExposure) { 119 | return; 120 | } 121 | 122 | if (![captureDevice lockForConfiguration:nil]) { 123 | return; 124 | } 125 | 126 | // Find the preview's offset relative to the parent view. 127 | CGFloat offsetX = 0.5 * (self.parentView.bounds.size.width - self.customPreviewLayer.bounds.size.width); 128 | CGFloat offsetY = 0.5 * (self.parentView.bounds.size.height - self.customPreviewLayer.bounds.size.height); 129 | 130 | // Find the focus coordinates, proportional to the preview size. 131 | CGFloat focusX = (parentViewPoint.x - offsetX) / self.customPreviewLayer.bounds.size.width; 132 | CGFloat focusY = (parentViewPoint.y - offsetY) / self.customPreviewLayer.bounds.size.height; 133 | 134 | if (focusX < 0.0 || focusX > 1.0 || focusY < 0.0 || focusY > 1.0) { 135 | // The point is outside the preview. 136 | return; 137 | } 138 | 139 | // Adjust the focus coordinates based on the orientation. 140 | // They should be in the landscape-right coordinate system. 141 | switch (self.defaultAVCaptureVideoOrientation) { 142 | case AVCaptureVideoOrientationPortraitUpsideDown: { 143 | CGFloat oldFocusX = focusX; 144 | focusX = 1.0 - focusY; 145 | focusY = oldFocusX; 146 | break; 147 | } 148 | case AVCaptureVideoOrientationLandscapeLeft: { 149 | focusX = 1.0 - focusX; 150 | focusY = 1.0 - focusY; 151 | break; 152 | } 153 | case AVCaptureVideoOrientationLandscapeRight: { 154 | // Do nothing. 155 | break; 156 | } 157 | default: { // Portrait 158 | CGFloat oldFocusX = focusX; 159 | focusX = focusY; 160 | focusY = 1.0 - oldFocusX; 161 | break; 162 | } 163 | } 164 | 165 | if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) { 166 | // De-mirror the X coordinate. 167 | focusX = 1.0 - focusX; 168 | } 169 | 170 | CGPoint focusPoint = CGPointMake(focusX, focusY); 171 | 172 | if (canSetFocus) { 173 | // Auto-focus on the selected point. 174 | captureDevice.focusMode = AVCaptureFocusModeAutoFocus; 175 | captureDevice.focusPointOfInterest = focusPoint; 176 | } 177 | 178 | if (canSetExposure) { 179 | // Auto-expose for the selected point. 180 | captureDevice.exposureMode = AVCaptureExposureModeAutoExpose; 181 | captureDevice.exposurePointOfInterest = focusPoint; 182 | } 183 | 184 | [captureDevice unlockForConfiguration]; 185 | } 186 | 187 | @end 188 | -------------------------------------------------------------------------------- /ManyMasks/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ManyMasks 4 | // 5 | // Created by Joseph Howse on 2016-03-05. 6 | // Copyright © 2016 Nummist Media Corporation Limited. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // (1) Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // (2) Redistributions in binary form must reproduce the above copyright 15 | // notice, this list of conditions and the following disclaimer in the 16 | // documentation and/or other materials provided with the distribution. 17 | // (3) Neither the name of the copyright holder nor the names of its 18 | // contributors may be used to endorse or promote products derived from 19 | // this software without specific prior written permission. 20 | // 21 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | // 33 | 34 | #import 35 | #import "AppDelegate.h" 36 | 37 | int main(int argc, char * argv[]) { 38 | @autoreleasepool { 39 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOSWithOpenCV 2 | 3 | These are the projects for my book, [iOS Application Development with OpenCV 3](https://www.packtpub.com/application-development/ios-application-development-opencv). For full details, please read the book along with the [Errata and Updates](ERRATA.md) page. 4 | 5 | --- 6 | 7 | *☞ **I am using OpenCV 3** throughout the book and this repository. Even in OpenCV 3, the name `opencv2` still appears in header paths and in the filename `opencv2.framework`. Here, `opencv2` does not refer to the version number; it refers to the newer C++ API as opposed to the older C API.* 8 | 9 | --- 10 | 11 | ## Getting started 12 | 13 | 1. Set up an iOS development environment and OpenCV, as described in Chapter 1. If you run into difficulties in the section "Building the framework from source with extra modules", you may want to [download my build of `opencv2.framework`](https://github.com/JoeHowse/iOSWithOpenCV/releases/download/1.1.0/opencv2.framework.zip), which includes the `opencv_contrib` modules. Alternatively, some readers report that they are successfully using the [CocoaPods](https://cocoapods.org) dependency manager to obtain compatible pre-packaged builds of OpenCV (with or without the `opencv_contrib` modules). 14 | 2. Check out the repository to any path, which we will refer to as ``: 15 | 16 | $ git clone https://github.com/JoeHowse/iOSWithOpenCV.git 17 | 3. Put `opencv2.framework` in ``. 18 | 4. If your build of `opencv2.framework` does not contain the [opencv_contrib](https://github.com/Itseez/opencv_contrib) modules, edit each Xcode project's Build Settings | Preprocessor Macros to remove the `WITH_OPENCV_CONTRIB` flag. 19 | 5. Build and run the projects. Except for CoolPig, the projects use a camera, so they will work best on a real iOS device (not a simulator). 20 | 21 | ## Understanding the projects 22 | 23 | Chapter 1 introduces the CoolPig project, which is a minimal example of integration between iOS SDK and OpenCV. The app loads an image of a pig and changes its tint based on a timer. 24 | 25 | Chapters 2 and 3 iteratively develop the LightWork project, which is a photo-capture and -sharing application. Besides basic photographic features, it offers several filters to blend pairs of images. 26 | 27 | Chapter 4 steps up to the ManyMasks project, which is a face blending app that works on humans, cats, and possibly other mammals. The approach relies on cascade classifiers to detect facial elements, and a geometric transformation to align them. It is scale-invariant and it can compensate for small differences in rotation. 28 | 29 | Chapter 5 puts a capstone on the book with the BeanCounter project, which deals with object classification. The approach relies on blob detection, histogram analysis, and SURF (or ORB if SURF is unavailable). It is scale-invariant and rotation-invariant. Depending on a configuration file and a set of training images, the app could classify lots of things. Currently, it is configured to classify various Canadian coins and various beans. 30 | --------------------------------------------------------------------------------