├── .gitignore
├── ImagePreparation
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── ImagePreparation.entitlements
├── Model
│ ├── IMPSet.swift
│ └── Annotations.swift
├── AppConfiguration.swift
├── AppDelegate.swift
├── MLCreate.py
├── Tools
│ ├── NSImage+PhotoRect.swift
│ ├── NSImage+Tools.swift
│ └── FileHelper.swift
├── Info.plist
├── Document.swift
├── View
│ └── DrawView.swift
├── ViewController
│ ├── ViewController.swift
│ └── ViewController+Actions.swift
├── MLCreate.ipynb
└── Base.lproj
│ └── Main.storyboard
├── Podfile
├── ImagePreparation.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── vobu.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── ImagePreparationTests
├── Info.plist
└── ImagePreparationTests.swift
├── ImagePreparationUITests
├── Info.plist
└── ImagePreparationUITests.swift
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | xcshareddata
2 | xcuserdata
3 | .DS_Store
4 | docset/
5 | lib/
6 | Pods
7 | *.xcworkspace
8 | Podfile.lock
9 |
--------------------------------------------------------------------------------
/ImagePreparation/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.11'
2 |
3 | use_frameworks!
4 |
5 | target 'ImagePreparation' do
6 |
7 | pod 'SSZipArchive'
8 |
9 | end
10 |
11 |
--------------------------------------------------------------------------------
/ImagePreparation/ImagePreparation.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ImagePreparation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ImagePreparation.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ImagePreparation/Model/IMPSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WorkArea.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 Volker Bublitz. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct IMPSet {
12 | let workFolder: URL
13 | let imageFolder: URL
14 | var annotations: Annotations
15 | }
16 |
--------------------------------------------------------------------------------
/ImagePreparation.xcodeproj/xcuserdata/vobu.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ImagePreparation.xcscheme
8 |
9 | orderHint
10 | 2
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ImagePreparation/AppConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Config.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 Volker Bublitz. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct AppConfiguration {
12 | static let normalizedBaseSizeInPixels:CGFloat = 500.0
13 | static let defaultLabel = "Unknown"
14 | static let appName = "ImagePreparation"
15 | static let mlExportDirName = "MLExport"
16 | }
17 |
--------------------------------------------------------------------------------
/ImagePreparation/Model/Annotations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Annotations.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 16.09.18.
6 | // Copyright © 2018 Volker Bublitz. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | struct Annotations: Codable {
12 | var path:[String]
13 | var annotations:[Annotation]
14 | }
15 |
16 | struct Annotation: Codable {
17 | var coordinates:Coordinates
18 | var label:String
19 | }
20 |
21 | struct Coordinates: Codable {
22 | var width:Double
23 | var height:Double
24 | var x:Double
25 | var y:Double
26 | }
27 |
--------------------------------------------------------------------------------
/ImagePreparation/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | func applicationDidFinishLaunching(_ aNotification: Notification) {
15 | // Insert code here to initialize your application
16 | }
17 |
18 | func applicationWillTerminate(_ aNotification: Notification) {
19 | FileHelper.cleanApplicationSupport()
20 | }
21 |
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/ImagePreparationTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ImagePreparationUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ImagePreparation/MLCreate.py:
--------------------------------------------------------------------------------
1 | import turicreate as tc
2 | import json
3 |
4 | # # Name your model
5 | modelName = "MyModel"
6 |
7 | # # Build train JSON SFrame
8 | with open('annotations.json') as j:
9 | annotations = json.load(j)
10 |
11 | annotationData = tc.SFrame(annotations)
12 | data = tc.load_images('images/')
13 | data = data.join(annotationData)
14 | trainData, testData = data.random_split(0.8)
15 |
16 | # # Check ground truth
17 | trainData['image_with_ground_truth'] = tc.object_detector.util.draw_bounding_boxes(trainData['image'], trainData['annotations'])
18 | # trainData.explore()
19 |
20 | # # Train the model
21 | model = tc.object_detector.create(trainData, feature="image", annotations="annotations", max_iterations=20)
22 | model.save(modelName + '.model')
23 |
24 | # # Predictions
25 | predictions = model.predict(testData, confidence_threshold=0.0, verbose=True)
26 | # predictions.explore()
27 | metrics = model.evaluate(testData)
28 | print('mAP: {:.1%}'.format(metrics['mean_average_precision_50']))
29 | # metrics
30 |
31 | # # Export model
32 | model.export_coreml(modelName + '.mlmodel')
33 |
--------------------------------------------------------------------------------
/ImagePreparation/Tools/NSImage+PhotoRect.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+PhotoRect.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 16.09.18.
6 | // Copyright © 2018 Volker Bublitz. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension NSImageView {
12 |
13 | func photoReduction() -> CGFloat {
14 | guard let size = self.image?.size else {
15 | return 1.0
16 | }
17 | let iFrame = self.bounds
18 | let xRatio = NSWidth(iFrame)/size.width
19 | let yRatio = NSHeight(iFrame)/size.height
20 | return min(xRatio, yRatio)
21 | }
22 |
23 | func photoRectInImageView() -> NSRect {
24 | guard let size = self.image?.size else {
25 | return NSRect.zero
26 | }
27 | let iBounds = self.bounds
28 | let reduction = self.photoReduction()
29 | let width = size.width * reduction
30 | let height = size.height * reduction
31 | let x = (iBounds.size.width - width)/2.0
32 | let y = (iBounds.size.height - height)/2.0
33 | return NSRect(x: x, y: y, width: width, height: height)
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/ImagePreparationTests/ImagePreparationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImagePreparationTests.swift
3 | // ImagePreparationTests
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ImagePreparation
11 |
12 | class ImagePreparationTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/ImagePreparation/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # turi-annotate-od
2 | Simple Mac App to create annotations and prepare images for Object Detection training with Turi Create
3 |
4 | Purpose
5 | --------------
6 |
7 | When you need to prepare your images and add annotations for training with [Turi Create](https://github.com/apple/turicreate), you can use this little Mac App ("ImagePreparation").
8 |
9 | ## Installation
10 |
11 | Just clone this project and run ```pod install```.
12 | Open the created workspace in Xcode 10 on your Mac and build and run the ImagePreparation target.
13 |
14 | ## Usage
15 |
16 | After starting up, you'll see an empty window. You can import your images now by selecting ```File -> Import Pictures...```.
17 | For each imported picture you can now draw a bounding box and enter a label in the text field. You can save and open your ongoing work
18 | as 'mlp' files. When you're ready to go, you can select ```File -> Export ML Data...```.
19 | This will export your work in a folder called MLExport. In addition, it will add a python script and [Jupyter Notebook](http://jupyter.org) file.
20 |
21 | Note: I'm using [Anaconda](https://www.anaconda.com) with Python 3.6 and have set up a virtual environment where i installed version 5.0 of Turi Create. You can
22 | start Jupyter Notebook from your export folder and use the included script to train your model.
23 |
24 |
--------------------------------------------------------------------------------
/ImagePreparationUITests/ImagePreparationUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImagePreparationUITests.swift
3 | // ImagePreparationUITests
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class ImagePreparationUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/ImagePreparation/Tools/NSImage+Tools.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+Resize.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 16.09.18.
6 | // Copyright © 2018 Volker Bublitz. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension NSImage {
12 |
13 | func resizedImage(w: CGFloat, h: CGFloat) -> NSImage {
14 | let destSize = NSMakeSize(w, h)
15 | let newImage = NSImage(size: destSize)
16 | newImage.lockFocus()
17 | self.draw(in: NSMakeRect(0, 0, destSize.width, destSize.height), from: NSMakeRect(0, 0, self.size.width, self.size.height), operation: .destinationOver, fraction: CGFloat(1))
18 | newImage.unlockFocus()
19 | return newImage
20 | }
21 |
22 | func writeToFile(file: URL, usingType type: NSBitmapImageRep.FileType) {
23 | let properties = [NSBitmapImageRep.PropertyKey.compressionFactor: 1.0]
24 | guard
25 | let imageData = tiffRepresentation,
26 | let imageRep = NSBitmapImageRep(data: imageData),
27 | let fileData = imageRep.representation(using: type, properties: properties) else {
28 | return
29 | }
30 | try? fileData.write(to: file)
31 | }
32 |
33 | func pixelSize() -> NSSize {
34 | guard let h = representations.first?.pixelsHigh,
35 | let w = representations.first?.pixelsWide else {
36 | return size
37 | }
38 | return NSSize(width: w, height: h)
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/ImagePreparation/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDocumentTypes
8 |
9 |
10 | CFBundleTypeExtensions
11 |
12 | mlp
13 |
14 | CFBundleTypeIconFile
15 |
16 | CFBundleTypeName
17 | DocumentType
18 | CFBundleTypeOSTypes
19 |
20 | ????
21 |
22 | CFBundleTypeRole
23 | Editor
24 | NSDocumentClass
25 | $(PRODUCT_MODULE_NAME).Document
26 |
27 |
28 | CFBundleExecutable
29 | $(EXECUTABLE_NAME)
30 | CFBundleIconFile
31 |
32 | CFBundleIdentifier
33 | $(PRODUCT_BUNDLE_IDENTIFIER)
34 | CFBundleInfoDictionaryVersion
35 | 6.0
36 | CFBundleName
37 | $(PRODUCT_NAME)
38 | CFBundlePackageType
39 | APPL
40 | CFBundleShortVersionString
41 | 1.0
42 | CFBundleVersion
43 | 1
44 | LSMinimumSystemVersion
45 | $(MACOSX_DEPLOYMENT_TARGET)
46 | NSHumanReadableCopyright
47 | Copyright © 2018 vobu. All rights reserved.
48 | NSMainStoryboardFile
49 | Main
50 | NSPrincipalClass
51 | NSApplication
52 |
53 |
54 |
--------------------------------------------------------------------------------
/ImagePreparation/Tools/FileHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FileHelper.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class FileHelper: NSObject {
12 |
13 | static func workImagesUrl(workFolder: URL) -> URL {
14 | let imageFolder = workFolder.appendingPathComponent("images")
15 | assureDirectoryIsAvailable(imageFolder)
16 | return imageFolder
17 | }
18 |
19 | static func annotationsUrl(workFolder: URL) -> URL {
20 | return workFolder.appendingPathComponent("annotations.json")
21 | }
22 |
23 | static func workFolderURL() -> URL {
24 | let uuid = UUID().uuidString
25 | guard let workFolder = applicationSupportUrl()?.appendingPathComponent(uuid) else {
26 | fatalError("unable to work with application support files")
27 | }
28 | assureDirectoryIsAvailable(workFolder)
29 | return workFolder
30 | }
31 |
32 | static func cleanApplicationSupport() {
33 | guard let dir = applicationSupportUrl(),
34 | let urls = try? FileManager.default.contentsOfDirectory(at: dir, includingPropertiesForKeys: nil, options: []) else {
35 | return
36 | }
37 | urls.forEach { (url) in
38 | try? FileManager.default.removeItem(at: url)
39 | }
40 | }
41 |
42 | private static func assureDirectoryIsAvailable(_ url: URL) {
43 | let fm = FileManager.default
44 | if !fm.fileExists(atPath: url.path) {
45 | do {
46 | try fm.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
47 | }
48 | catch let error {
49 | fatalError("Stopping application - no access to working directory " + error.localizedDescription)
50 | }
51 | }
52 | }
53 |
54 | private static func applicationSupportUrl() -> URL? {
55 | if let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
56 | let appDirectory = url.appendingPathComponent(Bundle.main.bundleIdentifier ?? AppConfiguration.appName)
57 | return appDirectory
58 | }
59 | return nil
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/ImagePreparation/Document.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Document.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SSZipArchive
11 |
12 | class Document: NSDocument {
13 |
14 | var impSet:IMPSet
15 |
16 | override init() {
17 | let workFolder = FileHelper.workFolderURL()
18 | let imageFolder = FileHelper.workImagesUrl(workFolder: workFolder)
19 | impSet = IMPSet(workFolder: workFolder, imageFolder: imageFolder, annotations: Annotations(path: [], annotations: []))
20 | super.init()
21 | }
22 |
23 | override class var autosavesInPlace: Bool {
24 | return true
25 | }
26 |
27 | override func makeWindowControllers() {
28 | // Returns the Storyboard that contains your Document window.
29 | let storyboard = NSStoryboard(name: "Main", bundle: nil)
30 | let windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as! NSWindowController
31 | self.addWindowController(windowController)
32 | // Set represented object of ViewController
33 | if let viewController: ViewController = windowController.contentViewController as! ViewController? {
34 | viewController.representedObject = self
35 | viewController.select(index: 0)
36 | }
37 | }
38 |
39 | override func write(to url: URL, ofType typeName: String) throws {
40 | try JSONEncoder().encode(impSet.annotations).write(to: FileHelper.annotationsUrl(workFolder: impSet.workFolder))
41 | SSZipArchive.createZipFile(atPath: url.path, withContentsOfDirectory: impSet.workFolder.path)
42 | }
43 |
44 | override func read(from url: URL, ofType typeName: String) throws {
45 | SSZipArchive.unzipFile(atPath: url.path, toDestination: impSet.workFolder.path)
46 | guard FileManager.default.fileExists(atPath: impSet.imageFolder.path) else {
47 | try? FileManager.default.removeItem(at: impSet.workFolder)
48 | throw NSError(domain: NSCocoaErrorDomain, code: NSFileReadUnsupportedSchemeError, userInfo: nil)
49 | }
50 | let jsonUrl = FileHelper.annotationsUrl(workFolder: impSet.workFolder)
51 | let annotations:Annotations = try JSONDecoder().decode(Annotations.self, from: Data(contentsOf: jsonUrl))
52 | impSet.annotations = annotations
53 | }
54 |
55 | override func close() {
56 | super.close()
57 | try? FileManager.default.removeItem(at: impSet.workFolder)
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/ImagePreparation/View/DrawView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DrawView.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 16.09.18.
6 | // Copyright © 2018 Volker Bublitz. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | protocol DrawViewDelegate {
12 | func drawView(_ drawView: DrawView, didDrawRect rect: NSRect)
13 | func drawViewShouldStartDrawing(_ drawView: DrawView) -> Bool
14 | }
15 |
16 | class DrawView: NSView {
17 |
18 | var delegate: DrawViewDelegate?
19 | var startingPoint = NSPoint.zero
20 | var endPoint = NSPoint.zero
21 |
22 | var path: NSBezierPath = NSBezierPath()
23 | var rect: NSRect = NSRect.zero
24 |
25 | func drawMLRect(rect: NSRect) {
26 | startingPoint = rect.origin
27 | endPoint = NSPoint(x: rect.origin.x + rect.size.width, y: rect.origin.y + rect.size.height)
28 | updateMLRect()
29 | }
30 |
31 | override func mouseDown(with event: NSEvent) {
32 | guard delegate?.drawViewShouldStartDrawing(self) ?? false else {
33 | return
34 | }
35 | startingPoint = convert(event.locationInWindow, from: nil)
36 | updateMLRect()
37 | }
38 |
39 | override func mouseDragged(with event: NSEvent) {
40 | guard delegate?.drawViewShouldStartDrawing(self) ?? false else {
41 | return
42 | }
43 | endPoint = convert(event.locationInWindow, from: nil)
44 | updateMLRect()
45 | }
46 |
47 | override func mouseUp(with event: NSEvent) {
48 | guard delegate?.drawViewShouldStartDrawing(self) ?? false else {
49 | return
50 | }
51 | let originX = min(startingPoint.x, endPoint.x)
52 | let originY = min(startingPoint.y, endPoint.y)
53 | let width = abs(startingPoint.x - endPoint.x)
54 | let height = abs(startingPoint.y - endPoint.y)
55 | delegate?.drawView(self, didDrawRect: NSRect(x: originX, y: originY, width: width, height: height))
56 | }
57 |
58 | override func draw(_ dirtyRect: NSRect) {
59 | super.draw(dirtyRect)
60 |
61 | NSColor.black.set()
62 |
63 | path.lineJoinStyle = .round
64 | path.lineCapStyle = .round
65 | path.lineWidth = 2.0
66 | path.stroke()
67 | }
68 |
69 | private func updateMLRect() {
70 | path = NSBezierPath()
71 | path.move(to: startingPoint)
72 | path.line(to: NSPoint(x: startingPoint.x, y: endPoint.y))
73 | path.line(to: NSPoint(x: endPoint.x, y: endPoint.y))
74 | path.line(to: NSPoint(x: endPoint.x, y: startingPoint.y))
75 | path.line(to: NSPoint(x: startingPoint.x, y: startingPoint.y))
76 | needsDisplay = true
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/ImagePreparation/ViewController/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ViewController: NSViewController, DrawViewDelegate {
12 |
13 | var document:Document?
14 | private var currentIndex = 0
15 |
16 | @IBOutlet weak var textField: NSTextField!
17 | @IBOutlet weak var imageView: NSImageView!
18 | @IBOutlet weak var drawView: DrawView!
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | drawView.delegate = self
23 |
24 | // Do any additional setup after loading the view.
25 | }
26 |
27 | override var representedObject: Any? {
28 | didSet {
29 | document = representedObject as? Document
30 | }
31 | }
32 |
33 | private func updateUI() {
34 | guard let path = document?.impSet.annotations.path[currentIndex],
35 | let realP = realPath(mlPath: path),
36 | let image = NSImage(contentsOfFile: realP),
37 | let annotation = document?.impSet.annotations.annotations[currentIndex] else {
38 | return
39 | }
40 | imageView.image = image
41 | textField.stringValue = annotation.label
42 |
43 | let imageRect = self.imageView.photoRectInImageView()
44 | let pixelSize = image.pixelSize()
45 |
46 | let scale = Double(pixelSize.width / imageRect.size.width)
47 | let oX = annotation.coordinates.x / scale
48 | let oY = (Double(pixelSize.height) - annotation.coordinates.y) / scale
49 | let oWidth = annotation.coordinates.width / scale
50 | let oHeight = annotation.coordinates.height / scale
51 |
52 | let rectX = Double(imageRect.origin.x) + (oX - oWidth / 2.0)
53 | let rectY = Double(imageRect.origin.y) + (oY - oHeight / 2.0)
54 | let rect = NSRect(x: rectX, y: rectY, width: oWidth, height: oHeight)
55 |
56 | self.drawView.drawMLRect(rect: rect)
57 | }
58 |
59 | private func realPath(mlPath: String) -> String? {
60 | guard let basePath = document?.impSet.workFolder.path else {
61 | return nil
62 | }
63 | return basePath + "/" + mlPath
64 | }
65 |
66 | //MARK: - Actions
67 |
68 | @IBAction func nextClicked(_ sender: Any) {
69 | updateLabel()
70 | guard currentIndex < (document?.impSet.annotations.path.count ?? 0) - 1 else {
71 | currentIndex = 0
72 | updateUI()
73 | return
74 | }
75 | currentIndex = currentIndex + 1
76 | updateUI()
77 | }
78 |
79 | @IBAction func previousClicked(_ sender: Any) {
80 | updateLabel()
81 | guard currentIndex > 0 else {
82 | currentIndex = (document?.impSet.annotations.path.count ?? 1) - 1
83 | updateUI()
84 | return
85 | }
86 | currentIndex = currentIndex - 1
87 | updateUI()
88 | }
89 |
90 | private func updateLabel() {
91 | if document?.impSet.annotations.annotations.count ?? 0 > currentIndex {
92 | document?.impSet.annotations.annotations[currentIndex].label = textField.stringValue
93 | }
94 | }
95 |
96 | // MARK: - Delegates
97 |
98 | func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
99 | document?.impSet.annotations.annotations[currentIndex].label = textField.stringValue
100 | return true
101 | }
102 |
103 | func drawViewShouldStartDrawing(_ drawView: DrawView) -> Bool {
104 | return document?.impSet.annotations.path.count ?? 0 > currentIndex
105 | }
106 |
107 | func drawView(_ drawView: DrawView, didDrawRect rect: NSRect) {
108 | updateLabel()
109 | guard let path = document?.impSet.annotations.path[currentIndex],
110 | let realP = realPath(mlPath: path),
111 | let image = NSImage(contentsOfFile: realP) else {
112 | return
113 | }
114 | let imageRect = imageView.photoRectInImageView()
115 | let pX = Double(rect.origin.x - imageRect.origin.x)
116 | let pY = Double(rect.origin.y - imageRect.origin.y)
117 | let pixelSize = image.pixelSize()
118 | let scale = Double(pixelSize.width / imageRect.size.width)
119 | let mlX = pX * scale
120 | let mlY = pY * scale
121 | let mlWidth = Double(rect.width) * scale
122 | let mlHeight = Double(rect.height) * scale
123 | let mlCenterX = mlX + mlWidth / 2.0
124 | let mlCenterY = mlY + mlHeight / 2.0
125 | document?.impSet.annotations.annotations[currentIndex].coordinates.height = mlHeight
126 | document?.impSet.annotations.annotations[currentIndex].coordinates.width = mlWidth
127 | document?.impSet.annotations.annotations[currentIndex].coordinates.x = mlCenterX
128 | document?.impSet.annotations.annotations[currentIndex].coordinates.y = Double(pixelSize.height) - mlCenterY
129 | }
130 |
131 | func select(index: Int) {
132 | guard document?.impSet.annotations.path.count ?? 0 > index else {
133 | return
134 | }
135 | currentIndex = index
136 | updateUI()
137 | }
138 |
139 | }
140 |
141 |
--------------------------------------------------------------------------------
/ImagePreparation/ViewController/ViewController+Actions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController+Actions.swift
3 | // ImagePreparation
4 | //
5 | // Created by Volker Bublitz on 22.09.18.
6 | // Copyright © 2018 vobu. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension ViewController {
12 |
13 | @IBAction func importImages(_ sender: Any?) {
14 | guard let window = self.view.window else {
15 | return
16 | }
17 | let openPanel = folderOpenPanel()
18 | openPanel.beginSheetModal(for: window) { (response) in
19 | switch response {
20 | case NSApplication.ModalResponse.OK:
21 | self.importImages(fromUrl: openPanel.urls.first)
22 | default:
23 | break
24 | }
25 | }
26 | }
27 |
28 | @IBAction func exportML(_ sender: Any?) {
29 | guard let window = self.view.window else {
30 | return
31 | }
32 | let openPanel = folderOpenPanel()
33 | openPanel.canCreateDirectories = true
34 | openPanel.beginSheetModal(for: window) { (response) in
35 | switch response {
36 | case NSApplication.ModalResponse.OK:
37 | self.exportML(toUrl: openPanel.urls.first)
38 | default:
39 | break
40 | }
41 | }
42 | }
43 |
44 | private func exportML(toUrl url: URL?) {
45 | guard let url = url,
46 | let impSet = document?.impSet else {
47 | return
48 | }
49 | document?.save(self)
50 | let encoder = JSONEncoder()
51 | encoder.outputFormatting = .prettyPrinted
52 | try? encoder.encode(impSet.annotations).write(to: FileHelper.annotationsUrl(workFolder: impSet.workFolder))
53 | var exportUrl = url.appendingPathComponent(AppConfiguration.mlExportDirName)
54 | var count = 2
55 | while FileManager.default.fileExists(atPath: exportUrl.path) {
56 | exportUrl = url.appendingPathComponent(String(format: "%@_%li", AppConfiguration.mlExportDirName, count))
57 | count = count + 1
58 | }
59 | try? FileManager.default.copyItem(at: impSet.workFolder, to: exportUrl)
60 | copy(resource: "MLCreate", pathExtension: "ipynb", exportURL: exportUrl)
61 | copy(resource: "MLCreate", pathExtension: "py", exportURL: exportUrl)
62 | }
63 |
64 | private func copy(resource: String, pathExtension: String, exportURL: URL) {
65 | guard let url = Bundle.main.url(forResource: resource, withExtension: pathExtension) else {
66 | return
67 | }
68 | let targetUrl = exportURL.appendingPathComponent(resource).appendingPathExtension(pathExtension)
69 | try? FileManager.default.copyItem(at: url, to: targetUrl)
70 | }
71 |
72 | private func importImages(fromUrl url: URL?) {
73 | guard let url = url,
74 | let _ = document?.impSet else {
75 | return
76 | }
77 | addNormalizedImages(url: url)
78 | if document?.impSet.annotations.path.count ?? 0 > 0 {
79 | select(index: 0)
80 | }
81 | }
82 |
83 | private func addNormalizedImages(url u: URL) {
84 | guard let urls = try? FileManager.default.contentsOfDirectory(at: u, includingPropertiesForKeys: nil, options: []) else {
85 | return
86 | }
87 |
88 | var annotationList:[Annotation] = []
89 | var mlPaths:[String] = []
90 |
91 | urls.forEach { (fileUrl) in
92 | guard let targetImageUrl = document?.impSet.imageFolder.appendingPathComponent(fileUrl.lastPathComponent),
93 | let image = NSImage(contentsOf: fileUrl),
94 | image.size.width > 0, image.size.height > 0,
95 | Double(image.size.width) < Double.infinity,
96 | Double(image.size.height) < Double.infinity else {
97 | return
98 | }
99 | let width = image.size.width
100 | let height = image.size.height
101 | let scale = max(AppConfiguration.normalizedBaseSizeInPixels / width,
102 | AppConfiguration.normalizedBaseSizeInPixels / height)
103 | let targetSize = NSSize(width: width * scale, height: height * scale)
104 | let resized = image.resizedImage(w: targetSize.width, h: targetSize.height)
105 | resized.writeToFile(file: targetImageUrl, usingType: .jpeg)
106 | let mlPath:String = targetImageUrl.pathComponents.suffix(2).joined(separator: "/")
107 | mlPaths.append(mlPath)
108 | let pixelSize = resized.pixelSize()
109 | let coordinates = Coordinates(width: Double(pixelSize.width), height: Double(pixelSize.height),
110 | x: Double(pixelSize.width) / 2.0, y: Double(pixelSize.height) / 2.0)
111 | let annotation = Annotation(coordinates: coordinates, label: AppConfiguration.defaultLabel)
112 | annotationList.append(annotation)
113 | }
114 | document?.impSet.annotations.annotations.append(contentsOf: annotationList)
115 | document?.impSet.annotations.path.append(contentsOf: mlPaths)
116 | }
117 |
118 | private func folderOpenPanel() -> NSOpenPanel {
119 | let openPanel = NSOpenPanel()
120 | openPanel.canChooseDirectories = true
121 | openPanel.canChooseFiles = false
122 | return openPanel
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/ImagePreparation/MLCreate.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import turicreate as tc"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 2,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "import json"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {},
24 | "source": [
25 | "# Name your model"
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": 3,
31 | "metadata": {},
32 | "outputs": [],
33 | "source": [
34 | "modelName = \"MyModel\""
35 | ]
36 | },
37 | {
38 | "cell_type": "markdown",
39 | "metadata": {},
40 | "source": [
41 | "# Build train JSON SFrame"
42 | ]
43 | },
44 | {
45 | "cell_type": "code",
46 | "execution_count": 4,
47 | "metadata": {},
48 | "outputs": [],
49 | "source": [
50 | "with open('annotations.json') as j:\n",
51 | " annotations = json.load(j)"
52 | ]
53 | },
54 | {
55 | "cell_type": "code",
56 | "execution_count": 5,
57 | "metadata": {},
58 | "outputs": [],
59 | "source": [
60 | "annotationData = tc.SFrame(annotations)"
61 | ]
62 | },
63 | {
64 | "cell_type": "code",
65 | "execution_count": 6,
66 | "metadata": {},
67 | "outputs": [],
68 | "source": [
69 | "data = tc.load_images('images/')"
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 7,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "data = data.join(annotationData)"
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": 8,
84 | "metadata": {},
85 | "outputs": [],
86 | "source": [
87 | "trainData, testData = data.random_split(0.8)"
88 | ]
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "metadata": {},
93 | "source": [
94 | "# Check ground truth"
95 | ]
96 | },
97 | {
98 | "cell_type": "code",
99 | "execution_count": 9,
100 | "metadata": {},
101 | "outputs": [],
102 | "source": [
103 | "trainData['image_with_ground_truth'] = \\\n",
104 | " tc.object_detector.util.draw_bounding_boxes(trainData['image'], trainData['annotations'])"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": 10,
110 | "metadata": {},
111 | "outputs": [
112 | {
113 | "data": {
114 | "text/html": [
115 | "
Materializing SFrame
"
116 | ],
117 | "text/plain": [
118 | "Materializing SFrame"
119 | ]
120 | },
121 | "metadata": {},
122 | "output_type": "display_data"
123 | }
124 | ],
125 | "source": [
126 | "trainData.explore()"
127 | ]
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "# Train the model"
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "execution_count": 11,
139 | "metadata": {},
140 | "outputs": [
141 | {
142 | "name": "stdout",
143 | "output_type": "stream",
144 | "text": [
145 | "Setting 'batch_size' to 32\n",
146 | "Using CPU to create model\n",
147 | "NOTE: If available, an AMD GPU can be leveraged on macOS 10.14+ for faster model creation\n",
148 | "+--------------+--------------+--------------+\n",
149 | "| Iteration | Loss | Elapsed Time |\n",
150 | "+--------------+--------------+--------------+\n",
151 | "| 1 | 4.544 | 10.3 |\n",
152 | "| 3 | 4.558 | 29.6 |\n",
153 | "| 5 | 4.566 | 48.6 |\n",
154 | "| 7 | 4.557 | 67.9 |\n",
155 | "| 9 | 4.558 | 87.4 |\n",
156 | "| 11 | 4.478 | 106.9 |\n",
157 | "| 13 | 4.485 | 126.2 |\n",
158 | "| 15 | 4.459 | 146.0 |\n",
159 | "| 17 | 4.378 | 165.6 |\n",
160 | "| 19 | 4.315 | 184.9 |\n",
161 | "| 21 | 4.288 | 204.5 |\n",
162 | "| 23 | 4.246 | 224.1 |\n",
163 | "| 25 | 4.206 | 244.0 |\n",
164 | "| 27 | 4.173 | 263.3 |\n",
165 | "| 29 | 4.119 | 282.7 |\n",
166 | "| 30 | 4.066 | 291.4 |\n",
167 | "+--------------+--------------+--------------+\n"
168 | ]
169 | }
170 | ],
171 | "source": [
172 | "model = tc.object_detector.create(trainData, feature=\"image\", annotations=\"annotations\", max_iterations=30)"
173 | ]
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": 12,
178 | "metadata": {},
179 | "outputs": [],
180 | "source": [
181 | "model.save(modelName + '.model')"
182 | ]
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "metadata": {},
187 | "source": [
188 | "# Predictions"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": 13,
194 | "metadata": {},
195 | "outputs": [
196 | {
197 | "name": "stdout",
198 | "output_type": "stream",
199 | "text": [
200 | "Predicting 1/14\n",
201 | "Predicting 14/14\n"
202 | ]
203 | }
204 | ],
205 | "source": [
206 | "predictions = model.predict(testData, confidence_threshold=0.0, verbose=True)"
207 | ]
208 | },
209 | {
210 | "cell_type": "code",
211 | "execution_count": 14,
212 | "metadata": {},
213 | "outputs": [
214 | {
215 | "data": {
216 | "text/html": [
217 | "Materializing SFrame
"
218 | ],
219 | "text/plain": [
220 | "Materializing SFrame"
221 | ]
222 | },
223 | "metadata": {},
224 | "output_type": "display_data"
225 | }
226 | ],
227 | "source": [
228 | "predictions.explore()"
229 | ]
230 | },
231 | {
232 | "cell_type": "code",
233 | "execution_count": 15,
234 | "metadata": {},
235 | "outputs": [
236 | {
237 | "name": "stdout",
238 | "output_type": "stream",
239 | "text": [
240 | "Predicting 1/14\n",
241 | "Predicting 14/14\n"
242 | ]
243 | }
244 | ],
245 | "source": [
246 | "metrics = model.evaluate(testData)"
247 | ]
248 | },
249 | {
250 | "cell_type": "code",
251 | "execution_count": 16,
252 | "metadata": {},
253 | "outputs": [
254 | {
255 | "name": "stdout",
256 | "output_type": "stream",
257 | "text": [
258 | "mAP: 30.6%\n"
259 | ]
260 | }
261 | ],
262 | "source": [
263 | "print('mAP: {:.1%}'.format(metrics['mean_average_precision_50']))"
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "execution_count": 17,
269 | "metadata": {},
270 | "outputs": [
271 | {
272 | "data": {
273 | "text/plain": [
274 | "{'average_precision_50': {'Feder': 0.30599078264015506},\n",
275 | " 'mean_average_precision_50': 0.30599078264015506}"
276 | ]
277 | },
278 | "execution_count": 17,
279 | "metadata": {},
280 | "output_type": "execute_result"
281 | }
282 | ],
283 | "source": [
284 | "metrics"
285 | ]
286 | },
287 | {
288 | "cell_type": "markdown",
289 | "metadata": {},
290 | "source": [
291 | "# Export model"
292 | ]
293 | },
294 | {
295 | "cell_type": "code",
296 | "execution_count": 18,
297 | "metadata": {},
298 | "outputs": [],
299 | "source": [
300 | "model.export_coreml(modelName + '.mlmodel')"
301 | ]
302 | },
303 | {
304 | "cell_type": "code",
305 | "execution_count": null,
306 | "metadata": {},
307 | "outputs": [],
308 | "source": []
309 | }
310 | ],
311 | "metadata": {
312 | "kernelspec": {
313 | "display_name": "Python 3",
314 | "language": "python",
315 | "name": "python3"
316 | },
317 | "language_info": {
318 | "codemirror_mode": {
319 | "name": "ipython",
320 | "version": 3
321 | },
322 | "file_extension": ".py",
323 | "mimetype": "text/x-python",
324 | "name": "python",
325 | "nbconvert_exporter": "python",
326 | "pygments_lexer": "ipython3",
327 | "version": "3.6.5"
328 | }
329 | },
330 | "nbformat": 4,
331 | "nbformat_minor": 2
332 | }
333 |
--------------------------------------------------------------------------------
/ImagePreparation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | DA24DA9D21569932006E3FE0 /* FileHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA24DA9C21569932006E3FE0 /* FileHelper.swift */; };
11 | DA24DA9F2156C838006E3FE0 /* ViewController+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA24DA9E2156C838006E3FE0 /* ViewController+Actions.swift */; };
12 | DA24DAA5215781E4006E3FE0 /* MLCreate.ipynb in Resources */ = {isa = PBXBuildFile; fileRef = DA24DAA3215781E3006E3FE0 /* MLCreate.ipynb */; };
13 | DA24DAA6215781E4006E3FE0 /* MLCreate.py in Resources */ = {isa = PBXBuildFile; fileRef = DA24DAA4215781E3006E3FE0 /* MLCreate.py */; };
14 | DA4E7D4A21568CA500A8F73C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D4921568CA500A8F73C /* AppDelegate.swift */; };
15 | DA4E7D4C21568CA500A8F73C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D4B21568CA500A8F73C /* ViewController.swift */; };
16 | DA4E7D4E21568CA500A8F73C /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D4D21568CA500A8F73C /* Document.swift */; };
17 | DA4E7D5021568CA700A8F73C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA4E7D4F21568CA700A8F73C /* Assets.xcassets */; };
18 | DA4E7D5321568CA700A8F73C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA4E7D5121568CA700A8F73C /* Main.storyboard */; };
19 | DA4E7D5F21568CA700A8F73C /* ImagePreparationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D5E21568CA700A8F73C /* ImagePreparationTests.swift */; };
20 | DA4E7D6A21568CA700A8F73C /* ImagePreparationUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D6921568CA700A8F73C /* ImagePreparationUITests.swift */; };
21 | DA4E7D7D21568D8D00A8F73C /* DrawView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D7C21568D8D00A8F73C /* DrawView.swift */; };
22 | DA4E7D8121568DA200A8F73C /* NSImage+PhotoRect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D7F21568DA200A8F73C /* NSImage+PhotoRect.swift */; };
23 | DA4E7D8221568DA200A8F73C /* NSImage+Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D8021568DA200A8F73C /* NSImage+Tools.swift */; };
24 | DA4E7D8421568DB100A8F73C /* Annotations.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D8321568DB100A8F73C /* Annotations.swift */; };
25 | DA4E7D8621568DB800A8F73C /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D8521568DB700A8F73C /* AppConfiguration.swift */; };
26 | DA4E7D882156915300A8F73C /* IMPSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4E7D872156915300A8F73C /* IMPSet.swift */; };
27 | E4979CFF6DEEFC3A2B714BE0 /* Pods_ImagePreparation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37519BFE4C9B578E38132C2A /* Pods_ImagePreparation.framework */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXContainerItemProxy section */
31 | DA4E7D5B21568CA700A8F73C /* PBXContainerItemProxy */ = {
32 | isa = PBXContainerItemProxy;
33 | containerPortal = DA4E7D3E21568CA500A8F73C /* Project object */;
34 | proxyType = 1;
35 | remoteGlobalIDString = DA4E7D4521568CA500A8F73C;
36 | remoteInfo = ImagePreparation;
37 | };
38 | DA4E7D6621568CA700A8F73C /* PBXContainerItemProxy */ = {
39 | isa = PBXContainerItemProxy;
40 | containerPortal = DA4E7D3E21568CA500A8F73C /* Project object */;
41 | proxyType = 1;
42 | remoteGlobalIDString = DA4E7D4521568CA500A8F73C;
43 | remoteInfo = ImagePreparation;
44 | };
45 | /* End PBXContainerItemProxy section */
46 |
47 | /* Begin PBXFileReference section */
48 | 1C6ADD0C5EF32D27108AB089 /* Pods-ImagePreparation.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImagePreparation.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImagePreparation/Pods-ImagePreparation.debug.xcconfig"; sourceTree = ""; };
49 | 37519BFE4C9B578E38132C2A /* Pods_ImagePreparation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ImagePreparation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
50 | ACEE2D56CD1B20C25B5E668A /* Pods-ImagePreparation.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImagePreparation.release.xcconfig"; path = "Pods/Target Support Files/Pods-ImagePreparation/Pods-ImagePreparation.release.xcconfig"; sourceTree = ""; };
51 | DA24DA9C21569932006E3FE0 /* FileHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileHelper.swift; sourceTree = ""; };
52 | DA24DA9E2156C838006E3FE0 /* ViewController+Actions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewController+Actions.swift"; sourceTree = ""; };
53 | DA24DAA3215781E3006E3FE0 /* MLCreate.ipynb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MLCreate.ipynb; sourceTree = ""; };
54 | DA24DAA4215781E3006E3FE0 /* MLCreate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = MLCreate.py; sourceTree = ""; };
55 | DA4E7D4621568CA500A8F73C /* ImagePreparation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ImagePreparation.app; sourceTree = BUILT_PRODUCTS_DIR; };
56 | DA4E7D4921568CA500A8F73C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
57 | DA4E7D4B21568CA500A8F73C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
58 | DA4E7D4D21568CA500A8F73C /* Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Document.swift; sourceTree = ""; };
59 | DA4E7D4F21568CA700A8F73C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
60 | DA4E7D5221568CA700A8F73C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
61 | DA4E7D5421568CA700A8F73C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
62 | DA4E7D5521568CA700A8F73C /* ImagePreparation.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ImagePreparation.entitlements; sourceTree = ""; };
63 | DA4E7D5A21568CA700A8F73C /* ImagePreparationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImagePreparationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
64 | DA4E7D5E21568CA700A8F73C /* ImagePreparationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePreparationTests.swift; sourceTree = ""; };
65 | DA4E7D6021568CA700A8F73C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
66 | DA4E7D6521568CA700A8F73C /* ImagePreparationUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImagePreparationUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
67 | DA4E7D6921568CA700A8F73C /* ImagePreparationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePreparationUITests.swift; sourceTree = ""; };
68 | DA4E7D6B21568CA700A8F73C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
69 | DA4E7D7C21568D8D00A8F73C /* DrawView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawView.swift; sourceTree = ""; };
70 | DA4E7D7F21568DA200A8F73C /* NSImage+PhotoRect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+PhotoRect.swift"; sourceTree = ""; };
71 | DA4E7D8021568DA200A8F73C /* NSImage+Tools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+Tools.swift"; sourceTree = ""; };
72 | DA4E7D8321568DB100A8F73C /* Annotations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Annotations.swift; sourceTree = ""; };
73 | DA4E7D8521568DB700A8F73C /* AppConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConfiguration.swift; sourceTree = ""; };
74 | DA4E7D872156915300A8F73C /* IMPSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IMPSet.swift; sourceTree = ""; };
75 | /* End PBXFileReference section */
76 |
77 | /* Begin PBXFrameworksBuildPhase section */
78 | DA4E7D4321568CA500A8F73C /* Frameworks */ = {
79 | isa = PBXFrameworksBuildPhase;
80 | buildActionMask = 2147483647;
81 | files = (
82 | E4979CFF6DEEFC3A2B714BE0 /* Pods_ImagePreparation.framework in Frameworks */,
83 | );
84 | runOnlyForDeploymentPostprocessing = 0;
85 | };
86 | DA4E7D5721568CA700A8F73C /* Frameworks */ = {
87 | isa = PBXFrameworksBuildPhase;
88 | buildActionMask = 2147483647;
89 | files = (
90 | );
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | DA4E7D6221568CA700A8F73C /* Frameworks */ = {
94 | isa = PBXFrameworksBuildPhase;
95 | buildActionMask = 2147483647;
96 | files = (
97 | );
98 | runOnlyForDeploymentPostprocessing = 0;
99 | };
100 | /* End PBXFrameworksBuildPhase section */
101 |
102 | /* Begin PBXGroup section */
103 | 6F4ECD81E2E1840690BD7416 /* Frameworks */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 37519BFE4C9B578E38132C2A /* Pods_ImagePreparation.framework */,
107 | );
108 | name = Frameworks;
109 | sourceTree = "";
110 | };
111 | C3030F0A78F27F5F4D90A9A1 /* Pods */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 1C6ADD0C5EF32D27108AB089 /* Pods-ImagePreparation.debug.xcconfig */,
115 | ACEE2D56CD1B20C25B5E668A /* Pods-ImagePreparation.release.xcconfig */,
116 | );
117 | name = Pods;
118 | sourceTree = "";
119 | };
120 | DA4E7D3D21568CA500A8F73C = {
121 | isa = PBXGroup;
122 | children = (
123 | DA4E7D4821568CA500A8F73C /* ImagePreparation */,
124 | DA4E7D5D21568CA700A8F73C /* ImagePreparationTests */,
125 | DA4E7D6821568CA700A8F73C /* ImagePreparationUITests */,
126 | DA4E7D4721568CA500A8F73C /* Products */,
127 | C3030F0A78F27F5F4D90A9A1 /* Pods */,
128 | 6F4ECD81E2E1840690BD7416 /* Frameworks */,
129 | );
130 | sourceTree = "";
131 | };
132 | DA4E7D4721568CA500A8F73C /* Products */ = {
133 | isa = PBXGroup;
134 | children = (
135 | DA4E7D4621568CA500A8F73C /* ImagePreparation.app */,
136 | DA4E7D5A21568CA700A8F73C /* ImagePreparationTests.xctest */,
137 | DA4E7D6521568CA700A8F73C /* ImagePreparationUITests.xctest */,
138 | );
139 | name = Products;
140 | sourceTree = "";
141 | };
142 | DA4E7D4821568CA500A8F73C /* ImagePreparation */ = {
143 | isa = PBXGroup;
144 | children = (
145 | DA4E7D5121568CA700A8F73C /* Main.storyboard */,
146 | DA4E7D4921568CA500A8F73C /* AppDelegate.swift */,
147 | DA4E7D4D21568CA500A8F73C /* Document.swift */,
148 | DA4E7D8521568DB700A8F73C /* AppConfiguration.swift */,
149 | DA4E7D7B21568D6900A8F73C /* ViewController */,
150 | DA4E7D7A21568D6500A8F73C /* View */,
151 | DA4E7D7921568D5C00A8F73C /* Model */,
152 | DA4E7D7E21568D9000A8F73C /* Tools */,
153 | DA4E7D4F21568CA700A8F73C /* Assets.xcassets */,
154 | DA4E7D5421568CA700A8F73C /* Info.plist */,
155 | DA24DAA3215781E3006E3FE0 /* MLCreate.ipynb */,
156 | DA24DAA4215781E3006E3FE0 /* MLCreate.py */,
157 | DA4E7D5521568CA700A8F73C /* ImagePreparation.entitlements */,
158 | );
159 | path = ImagePreparation;
160 | sourceTree = "";
161 | };
162 | DA4E7D5D21568CA700A8F73C /* ImagePreparationTests */ = {
163 | isa = PBXGroup;
164 | children = (
165 | DA4E7D5E21568CA700A8F73C /* ImagePreparationTests.swift */,
166 | DA4E7D6021568CA700A8F73C /* Info.plist */,
167 | );
168 | path = ImagePreparationTests;
169 | sourceTree = "";
170 | };
171 | DA4E7D6821568CA700A8F73C /* ImagePreparationUITests */ = {
172 | isa = PBXGroup;
173 | children = (
174 | DA4E7D6921568CA700A8F73C /* ImagePreparationUITests.swift */,
175 | DA4E7D6B21568CA700A8F73C /* Info.plist */,
176 | );
177 | path = ImagePreparationUITests;
178 | sourceTree = "";
179 | };
180 | DA4E7D7921568D5C00A8F73C /* Model */ = {
181 | isa = PBXGroup;
182 | children = (
183 | DA4E7D8321568DB100A8F73C /* Annotations.swift */,
184 | DA4E7D872156915300A8F73C /* IMPSet.swift */,
185 | );
186 | path = Model;
187 | sourceTree = "";
188 | };
189 | DA4E7D7A21568D6500A8F73C /* View */ = {
190 | isa = PBXGroup;
191 | children = (
192 | DA4E7D7C21568D8D00A8F73C /* DrawView.swift */,
193 | );
194 | path = View;
195 | sourceTree = "";
196 | };
197 | DA4E7D7B21568D6900A8F73C /* ViewController */ = {
198 | isa = PBXGroup;
199 | children = (
200 | DA4E7D4B21568CA500A8F73C /* ViewController.swift */,
201 | DA24DA9E2156C838006E3FE0 /* ViewController+Actions.swift */,
202 | );
203 | path = ViewController;
204 | sourceTree = "";
205 | };
206 | DA4E7D7E21568D9000A8F73C /* Tools */ = {
207 | isa = PBXGroup;
208 | children = (
209 | DA4E7D7F21568DA200A8F73C /* NSImage+PhotoRect.swift */,
210 | DA4E7D8021568DA200A8F73C /* NSImage+Tools.swift */,
211 | DA24DA9C21569932006E3FE0 /* FileHelper.swift */,
212 | );
213 | path = Tools;
214 | sourceTree = "";
215 | };
216 | /* End PBXGroup section */
217 |
218 | /* Begin PBXNativeTarget section */
219 | DA4E7D4521568CA500A8F73C /* ImagePreparation */ = {
220 | isa = PBXNativeTarget;
221 | buildConfigurationList = DA4E7D6E21568CA700A8F73C /* Build configuration list for PBXNativeTarget "ImagePreparation" */;
222 | buildPhases = (
223 | 703C6BACDD9327458467302B /* [CP] Check Pods Manifest.lock */,
224 | DA4E7D4221568CA500A8F73C /* Sources */,
225 | DA4E7D4321568CA500A8F73C /* Frameworks */,
226 | DA4E7D4421568CA500A8F73C /* Resources */,
227 | FEBFB7FC06554A23FD79FF61 /* [CP] Embed Pods Frameworks */,
228 | );
229 | buildRules = (
230 | );
231 | dependencies = (
232 | );
233 | name = ImagePreparation;
234 | productName = ImagePreparation;
235 | productReference = DA4E7D4621568CA500A8F73C /* ImagePreparation.app */;
236 | productType = "com.apple.product-type.application";
237 | };
238 | DA4E7D5921568CA700A8F73C /* ImagePreparationTests */ = {
239 | isa = PBXNativeTarget;
240 | buildConfigurationList = DA4E7D7121568CA700A8F73C /* Build configuration list for PBXNativeTarget "ImagePreparationTests" */;
241 | buildPhases = (
242 | DA4E7D5621568CA700A8F73C /* Sources */,
243 | DA4E7D5721568CA700A8F73C /* Frameworks */,
244 | DA4E7D5821568CA700A8F73C /* Resources */,
245 | );
246 | buildRules = (
247 | );
248 | dependencies = (
249 | DA4E7D5C21568CA700A8F73C /* PBXTargetDependency */,
250 | );
251 | name = ImagePreparationTests;
252 | productName = ImagePreparationTests;
253 | productReference = DA4E7D5A21568CA700A8F73C /* ImagePreparationTests.xctest */;
254 | productType = "com.apple.product-type.bundle.unit-test";
255 | };
256 | DA4E7D6421568CA700A8F73C /* ImagePreparationUITests */ = {
257 | isa = PBXNativeTarget;
258 | buildConfigurationList = DA4E7D7421568CA700A8F73C /* Build configuration list for PBXNativeTarget "ImagePreparationUITests" */;
259 | buildPhases = (
260 | DA4E7D6121568CA700A8F73C /* Sources */,
261 | DA4E7D6221568CA700A8F73C /* Frameworks */,
262 | DA4E7D6321568CA700A8F73C /* Resources */,
263 | );
264 | buildRules = (
265 | );
266 | dependencies = (
267 | DA4E7D6721568CA700A8F73C /* PBXTargetDependency */,
268 | );
269 | name = ImagePreparationUITests;
270 | productName = ImagePreparationUITests;
271 | productReference = DA4E7D6521568CA700A8F73C /* ImagePreparationUITests.xctest */;
272 | productType = "com.apple.product-type.bundle.ui-testing";
273 | };
274 | /* End PBXNativeTarget section */
275 |
276 | /* Begin PBXProject section */
277 | DA4E7D3E21568CA500A8F73C /* Project object */ = {
278 | isa = PBXProject;
279 | attributes = {
280 | LastSwiftUpdateCheck = 0940;
281 | LastUpgradeCheck = 0940;
282 | ORGANIZATIONNAME = vobu;
283 | TargetAttributes = {
284 | DA4E7D4521568CA500A8F73C = {
285 | CreatedOnToolsVersion = 9.4;
286 | LastSwiftMigration = 1000;
287 | };
288 | DA4E7D5921568CA700A8F73C = {
289 | CreatedOnToolsVersion = 9.4;
290 | LastSwiftMigration = 1000;
291 | TestTargetID = DA4E7D4521568CA500A8F73C;
292 | };
293 | DA4E7D6421568CA700A8F73C = {
294 | CreatedOnToolsVersion = 9.4;
295 | LastSwiftMigration = 1000;
296 | TestTargetID = DA4E7D4521568CA500A8F73C;
297 | };
298 | };
299 | };
300 | buildConfigurationList = DA4E7D4121568CA500A8F73C /* Build configuration list for PBXProject "ImagePreparation" */;
301 | compatibilityVersion = "Xcode 9.3";
302 | developmentRegion = en;
303 | hasScannedForEncodings = 0;
304 | knownRegions = (
305 | en,
306 | Base,
307 | );
308 | mainGroup = DA4E7D3D21568CA500A8F73C;
309 | productRefGroup = DA4E7D4721568CA500A8F73C /* Products */;
310 | projectDirPath = "";
311 | projectRoot = "";
312 | targets = (
313 | DA4E7D4521568CA500A8F73C /* ImagePreparation */,
314 | DA4E7D5921568CA700A8F73C /* ImagePreparationTests */,
315 | DA4E7D6421568CA700A8F73C /* ImagePreparationUITests */,
316 | );
317 | };
318 | /* End PBXProject section */
319 |
320 | /* Begin PBXResourcesBuildPhase section */
321 | DA4E7D4421568CA500A8F73C /* Resources */ = {
322 | isa = PBXResourcesBuildPhase;
323 | buildActionMask = 2147483647;
324 | files = (
325 | DA4E7D5021568CA700A8F73C /* Assets.xcassets in Resources */,
326 | DA4E7D5321568CA700A8F73C /* Main.storyboard in Resources */,
327 | DA24DAA5215781E4006E3FE0 /* MLCreate.ipynb in Resources */,
328 | DA24DAA6215781E4006E3FE0 /* MLCreate.py in Resources */,
329 | );
330 | runOnlyForDeploymentPostprocessing = 0;
331 | };
332 | DA4E7D5821568CA700A8F73C /* Resources */ = {
333 | isa = PBXResourcesBuildPhase;
334 | buildActionMask = 2147483647;
335 | files = (
336 | );
337 | runOnlyForDeploymentPostprocessing = 0;
338 | };
339 | DA4E7D6321568CA700A8F73C /* Resources */ = {
340 | isa = PBXResourcesBuildPhase;
341 | buildActionMask = 2147483647;
342 | files = (
343 | );
344 | runOnlyForDeploymentPostprocessing = 0;
345 | };
346 | /* End PBXResourcesBuildPhase section */
347 |
348 | /* Begin PBXShellScriptBuildPhase section */
349 | 703C6BACDD9327458467302B /* [CP] Check Pods Manifest.lock */ = {
350 | isa = PBXShellScriptBuildPhase;
351 | buildActionMask = 2147483647;
352 | files = (
353 | );
354 | inputPaths = (
355 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
356 | "${PODS_ROOT}/Manifest.lock",
357 | );
358 | name = "[CP] Check Pods Manifest.lock";
359 | outputPaths = (
360 | "$(DERIVED_FILE_DIR)/Pods-ImagePreparation-checkManifestLockResult.txt",
361 | );
362 | runOnlyForDeploymentPostprocessing = 0;
363 | shellPath = /bin/sh;
364 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
365 | showEnvVarsInLog = 0;
366 | };
367 | FEBFB7FC06554A23FD79FF61 /* [CP] Embed Pods Frameworks */ = {
368 | isa = PBXShellScriptBuildPhase;
369 | buildActionMask = 2147483647;
370 | files = (
371 | );
372 | inputPaths = (
373 | "${SRCROOT}/Pods/Target Support Files/Pods-ImagePreparation/Pods-ImagePreparation-frameworks.sh",
374 | "${BUILT_PRODUCTS_DIR}/SSZipArchive/SSZipArchive.framework",
375 | );
376 | name = "[CP] Embed Pods Frameworks";
377 | outputPaths = (
378 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SSZipArchive.framework",
379 | );
380 | runOnlyForDeploymentPostprocessing = 0;
381 | shellPath = /bin/sh;
382 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ImagePreparation/Pods-ImagePreparation-frameworks.sh\"\n";
383 | showEnvVarsInLog = 0;
384 | };
385 | /* End PBXShellScriptBuildPhase section */
386 |
387 | /* Begin PBXSourcesBuildPhase section */
388 | DA4E7D4221568CA500A8F73C /* Sources */ = {
389 | isa = PBXSourcesBuildPhase;
390 | buildActionMask = 2147483647;
391 | files = (
392 | DA4E7D8621568DB800A8F73C /* AppConfiguration.swift in Sources */,
393 | DA4E7D4C21568CA500A8F73C /* ViewController.swift in Sources */,
394 | DA4E7D7D21568D8D00A8F73C /* DrawView.swift in Sources */,
395 | DA4E7D8421568DB100A8F73C /* Annotations.swift in Sources */,
396 | DA4E7D8121568DA200A8F73C /* NSImage+PhotoRect.swift in Sources */,
397 | DA4E7D4A21568CA500A8F73C /* AppDelegate.swift in Sources */,
398 | DA4E7D8221568DA200A8F73C /* NSImage+Tools.swift in Sources */,
399 | DA24DA9F2156C838006E3FE0 /* ViewController+Actions.swift in Sources */,
400 | DA4E7D4E21568CA500A8F73C /* Document.swift in Sources */,
401 | DA4E7D882156915300A8F73C /* IMPSet.swift in Sources */,
402 | DA24DA9D21569932006E3FE0 /* FileHelper.swift in Sources */,
403 | );
404 | runOnlyForDeploymentPostprocessing = 0;
405 | };
406 | DA4E7D5621568CA700A8F73C /* Sources */ = {
407 | isa = PBXSourcesBuildPhase;
408 | buildActionMask = 2147483647;
409 | files = (
410 | DA4E7D5F21568CA700A8F73C /* ImagePreparationTests.swift in Sources */,
411 | );
412 | runOnlyForDeploymentPostprocessing = 0;
413 | };
414 | DA4E7D6121568CA700A8F73C /* Sources */ = {
415 | isa = PBXSourcesBuildPhase;
416 | buildActionMask = 2147483647;
417 | files = (
418 | DA4E7D6A21568CA700A8F73C /* ImagePreparationUITests.swift in Sources */,
419 | );
420 | runOnlyForDeploymentPostprocessing = 0;
421 | };
422 | /* End PBXSourcesBuildPhase section */
423 |
424 | /* Begin PBXTargetDependency section */
425 | DA4E7D5C21568CA700A8F73C /* PBXTargetDependency */ = {
426 | isa = PBXTargetDependency;
427 | target = DA4E7D4521568CA500A8F73C /* ImagePreparation */;
428 | targetProxy = DA4E7D5B21568CA700A8F73C /* PBXContainerItemProxy */;
429 | };
430 | DA4E7D6721568CA700A8F73C /* PBXTargetDependency */ = {
431 | isa = PBXTargetDependency;
432 | target = DA4E7D4521568CA500A8F73C /* ImagePreparation */;
433 | targetProxy = DA4E7D6621568CA700A8F73C /* PBXContainerItemProxy */;
434 | };
435 | /* End PBXTargetDependency section */
436 |
437 | /* Begin PBXVariantGroup section */
438 | DA4E7D5121568CA700A8F73C /* Main.storyboard */ = {
439 | isa = PBXVariantGroup;
440 | children = (
441 | DA4E7D5221568CA700A8F73C /* Base */,
442 | );
443 | name = Main.storyboard;
444 | sourceTree = "";
445 | };
446 | /* End PBXVariantGroup section */
447 |
448 | /* Begin XCBuildConfiguration section */
449 | DA4E7D6C21568CA700A8F73C /* Debug */ = {
450 | isa = XCBuildConfiguration;
451 | buildSettings = {
452 | ALWAYS_SEARCH_USER_PATHS = NO;
453 | CLANG_ANALYZER_NONNULL = YES;
454 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
455 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
456 | CLANG_CXX_LIBRARY = "libc++";
457 | CLANG_ENABLE_MODULES = YES;
458 | CLANG_ENABLE_OBJC_ARC = YES;
459 | CLANG_ENABLE_OBJC_WEAK = YES;
460 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
461 | CLANG_WARN_BOOL_CONVERSION = YES;
462 | CLANG_WARN_COMMA = YES;
463 | CLANG_WARN_CONSTANT_CONVERSION = YES;
464 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
465 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
466 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
467 | CLANG_WARN_EMPTY_BODY = YES;
468 | CLANG_WARN_ENUM_CONVERSION = YES;
469 | CLANG_WARN_INFINITE_RECURSION = YES;
470 | CLANG_WARN_INT_CONVERSION = YES;
471 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
472 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
473 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
474 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
475 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
476 | CLANG_WARN_STRICT_PROTOTYPES = YES;
477 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
478 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
479 | CLANG_WARN_UNREACHABLE_CODE = YES;
480 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
481 | CODE_SIGN_IDENTITY = "Mac Developer";
482 | COPY_PHASE_STRIP = NO;
483 | DEBUG_INFORMATION_FORMAT = dwarf;
484 | ENABLE_STRICT_OBJC_MSGSEND = YES;
485 | ENABLE_TESTABILITY = YES;
486 | GCC_C_LANGUAGE_STANDARD = gnu11;
487 | GCC_DYNAMIC_NO_PIC = NO;
488 | GCC_NO_COMMON_BLOCKS = YES;
489 | GCC_OPTIMIZATION_LEVEL = 0;
490 | GCC_PREPROCESSOR_DEFINITIONS = (
491 | "DEBUG=1",
492 | "$(inherited)",
493 | );
494 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
495 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
496 | GCC_WARN_UNDECLARED_SELECTOR = YES;
497 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
498 | GCC_WARN_UNUSED_FUNCTION = YES;
499 | GCC_WARN_UNUSED_VARIABLE = YES;
500 | MACOSX_DEPLOYMENT_TARGET = 10.13;
501 | MTL_ENABLE_DEBUG_INFO = YES;
502 | ONLY_ACTIVE_ARCH = YES;
503 | SDKROOT = macosx;
504 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
505 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
506 | };
507 | name = Debug;
508 | };
509 | DA4E7D6D21568CA700A8F73C /* Release */ = {
510 | isa = XCBuildConfiguration;
511 | buildSettings = {
512 | ALWAYS_SEARCH_USER_PATHS = NO;
513 | CLANG_ANALYZER_NONNULL = YES;
514 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
515 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
516 | CLANG_CXX_LIBRARY = "libc++";
517 | CLANG_ENABLE_MODULES = YES;
518 | CLANG_ENABLE_OBJC_ARC = YES;
519 | CLANG_ENABLE_OBJC_WEAK = YES;
520 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
521 | CLANG_WARN_BOOL_CONVERSION = YES;
522 | CLANG_WARN_COMMA = YES;
523 | CLANG_WARN_CONSTANT_CONVERSION = YES;
524 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
525 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
526 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
527 | CLANG_WARN_EMPTY_BODY = YES;
528 | CLANG_WARN_ENUM_CONVERSION = YES;
529 | CLANG_WARN_INFINITE_RECURSION = YES;
530 | CLANG_WARN_INT_CONVERSION = YES;
531 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
532 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
533 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
534 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
535 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
536 | CLANG_WARN_STRICT_PROTOTYPES = YES;
537 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
538 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
539 | CLANG_WARN_UNREACHABLE_CODE = YES;
540 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
541 | CODE_SIGN_IDENTITY = "Mac Developer";
542 | COPY_PHASE_STRIP = NO;
543 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
544 | ENABLE_NS_ASSERTIONS = NO;
545 | ENABLE_STRICT_OBJC_MSGSEND = YES;
546 | GCC_C_LANGUAGE_STANDARD = gnu11;
547 | GCC_NO_COMMON_BLOCKS = YES;
548 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
549 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
550 | GCC_WARN_UNDECLARED_SELECTOR = YES;
551 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
552 | GCC_WARN_UNUSED_FUNCTION = YES;
553 | GCC_WARN_UNUSED_VARIABLE = YES;
554 | MACOSX_DEPLOYMENT_TARGET = 10.13;
555 | MTL_ENABLE_DEBUG_INFO = NO;
556 | SDKROOT = macosx;
557 | SWIFT_COMPILATION_MODE = wholemodule;
558 | SWIFT_OPTIMIZATION_LEVEL = "-O";
559 | };
560 | name = Release;
561 | };
562 | DA4E7D6F21568CA700A8F73C /* Debug */ = {
563 | isa = XCBuildConfiguration;
564 | baseConfigurationReference = 1C6ADD0C5EF32D27108AB089 /* Pods-ImagePreparation.debug.xcconfig */;
565 | buildSettings = {
566 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
567 | CODE_SIGN_IDENTITY = "Mac Developer";
568 | CODE_SIGN_STYLE = Automatic;
569 | COMBINE_HIDPI_IMAGES = YES;
570 | DEVELOPMENT_TEAM = 96UYVTQDND;
571 | INFOPLIST_FILE = ImagePreparation/Info.plist;
572 | LD_RUNPATH_SEARCH_PATHS = (
573 | "$(inherited)",
574 | "@executable_path/../Frameworks",
575 | );
576 | PRODUCT_BUNDLE_IDENTIFIER = de.poolzeit.ImagePreparation;
577 | PRODUCT_NAME = "$(TARGET_NAME)";
578 | PROVISIONING_PROFILE_SPECIFIER = "";
579 | SWIFT_VERSION = 4.2;
580 | };
581 | name = Debug;
582 | };
583 | DA4E7D7021568CA700A8F73C /* Release */ = {
584 | isa = XCBuildConfiguration;
585 | baseConfigurationReference = ACEE2D56CD1B20C25B5E668A /* Pods-ImagePreparation.release.xcconfig */;
586 | buildSettings = {
587 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
588 | CODE_SIGN_IDENTITY = "Mac Developer";
589 | CODE_SIGN_STYLE = Automatic;
590 | COMBINE_HIDPI_IMAGES = YES;
591 | DEVELOPMENT_TEAM = 96UYVTQDND;
592 | INFOPLIST_FILE = ImagePreparation/Info.plist;
593 | LD_RUNPATH_SEARCH_PATHS = (
594 | "$(inherited)",
595 | "@executable_path/../Frameworks",
596 | );
597 | PRODUCT_BUNDLE_IDENTIFIER = de.poolzeit.ImagePreparation;
598 | PRODUCT_NAME = "$(TARGET_NAME)";
599 | PROVISIONING_PROFILE_SPECIFIER = "";
600 | SWIFT_VERSION = 4.2;
601 | };
602 | name = Release;
603 | };
604 | DA4E7D7221568CA700A8F73C /* Debug */ = {
605 | isa = XCBuildConfiguration;
606 | buildSettings = {
607 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
608 | BUNDLE_LOADER = "$(TEST_HOST)";
609 | CODE_SIGN_STYLE = Automatic;
610 | COMBINE_HIDPI_IMAGES = YES;
611 | DEVELOPMENT_TEAM = 96UYVTQDND;
612 | INFOPLIST_FILE = ImagePreparationTests/Info.plist;
613 | LD_RUNPATH_SEARCH_PATHS = (
614 | "$(inherited)",
615 | "@executable_path/../Frameworks",
616 | "@loader_path/../Frameworks",
617 | );
618 | PRODUCT_BUNDLE_IDENTIFIER = de.poolzeit.ImagePreparationTests;
619 | PRODUCT_NAME = "$(TARGET_NAME)";
620 | SWIFT_VERSION = 4.2;
621 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ImagePreparation.app/Contents/MacOS/ImagePreparation";
622 | };
623 | name = Debug;
624 | };
625 | DA4E7D7321568CA700A8F73C /* Release */ = {
626 | isa = XCBuildConfiguration;
627 | buildSettings = {
628 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
629 | BUNDLE_LOADER = "$(TEST_HOST)";
630 | CODE_SIGN_STYLE = Automatic;
631 | COMBINE_HIDPI_IMAGES = YES;
632 | DEVELOPMENT_TEAM = 96UYVTQDND;
633 | INFOPLIST_FILE = ImagePreparationTests/Info.plist;
634 | LD_RUNPATH_SEARCH_PATHS = (
635 | "$(inherited)",
636 | "@executable_path/../Frameworks",
637 | "@loader_path/../Frameworks",
638 | );
639 | PRODUCT_BUNDLE_IDENTIFIER = de.poolzeit.ImagePreparationTests;
640 | PRODUCT_NAME = "$(TARGET_NAME)";
641 | SWIFT_VERSION = 4.2;
642 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ImagePreparation.app/Contents/MacOS/ImagePreparation";
643 | };
644 | name = Release;
645 | };
646 | DA4E7D7521568CA700A8F73C /* Debug */ = {
647 | isa = XCBuildConfiguration;
648 | buildSettings = {
649 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
650 | CODE_SIGN_STYLE = Automatic;
651 | COMBINE_HIDPI_IMAGES = YES;
652 | DEVELOPMENT_TEAM = 96UYVTQDND;
653 | INFOPLIST_FILE = ImagePreparationUITests/Info.plist;
654 | LD_RUNPATH_SEARCH_PATHS = (
655 | "$(inherited)",
656 | "@executable_path/../Frameworks",
657 | "@loader_path/../Frameworks",
658 | );
659 | PRODUCT_BUNDLE_IDENTIFIER = de.poolzeit.ImagePreparationUITests;
660 | PRODUCT_NAME = "$(TARGET_NAME)";
661 | SWIFT_VERSION = 4.2;
662 | TEST_TARGET_NAME = ImagePreparation;
663 | };
664 | name = Debug;
665 | };
666 | DA4E7D7621568CA700A8F73C /* Release */ = {
667 | isa = XCBuildConfiguration;
668 | buildSettings = {
669 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
670 | CODE_SIGN_STYLE = Automatic;
671 | COMBINE_HIDPI_IMAGES = YES;
672 | DEVELOPMENT_TEAM = 96UYVTQDND;
673 | INFOPLIST_FILE = ImagePreparationUITests/Info.plist;
674 | LD_RUNPATH_SEARCH_PATHS = (
675 | "$(inherited)",
676 | "@executable_path/../Frameworks",
677 | "@loader_path/../Frameworks",
678 | );
679 | PRODUCT_BUNDLE_IDENTIFIER = de.poolzeit.ImagePreparationUITests;
680 | PRODUCT_NAME = "$(TARGET_NAME)";
681 | SWIFT_VERSION = 4.2;
682 | TEST_TARGET_NAME = ImagePreparation;
683 | };
684 | name = Release;
685 | };
686 | /* End XCBuildConfiguration section */
687 |
688 | /* Begin XCConfigurationList section */
689 | DA4E7D4121568CA500A8F73C /* Build configuration list for PBXProject "ImagePreparation" */ = {
690 | isa = XCConfigurationList;
691 | buildConfigurations = (
692 | DA4E7D6C21568CA700A8F73C /* Debug */,
693 | DA4E7D6D21568CA700A8F73C /* Release */,
694 | );
695 | defaultConfigurationIsVisible = 0;
696 | defaultConfigurationName = Release;
697 | };
698 | DA4E7D6E21568CA700A8F73C /* Build configuration list for PBXNativeTarget "ImagePreparation" */ = {
699 | isa = XCConfigurationList;
700 | buildConfigurations = (
701 | DA4E7D6F21568CA700A8F73C /* Debug */,
702 | DA4E7D7021568CA700A8F73C /* Release */,
703 | );
704 | defaultConfigurationIsVisible = 0;
705 | defaultConfigurationName = Release;
706 | };
707 | DA4E7D7121568CA700A8F73C /* Build configuration list for PBXNativeTarget "ImagePreparationTests" */ = {
708 | isa = XCConfigurationList;
709 | buildConfigurations = (
710 | DA4E7D7221568CA700A8F73C /* Debug */,
711 | DA4E7D7321568CA700A8F73C /* Release */,
712 | );
713 | defaultConfigurationIsVisible = 0;
714 | defaultConfigurationName = Release;
715 | };
716 | DA4E7D7421568CA700A8F73C /* Build configuration list for PBXNativeTarget "ImagePreparationUITests" */ = {
717 | isa = XCConfigurationList;
718 | buildConfigurations = (
719 | DA4E7D7521568CA700A8F73C /* Debug */,
720 | DA4E7D7621568CA700A8F73C /* Release */,
721 | );
722 | defaultConfigurationIsVisible = 0;
723 | defaultConfigurationName = Release;
724 | };
725 | /* End XCConfigurationList section */
726 | };
727 | rootObject = DA4E7D3E21568CA500A8F73C /* Project object */;
728 | }
729 |
--------------------------------------------------------------------------------
/ImagePreparation/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
--------------------------------------------------------------------------------