├── .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 |
76 |
77 |
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 |
--------------------------------------------------------------------------------