SAM2-Demo/Common/Models.swift (137 lines of code) (raw):

// // Models.swift // SAM2-Demo // // Created by Cyril Zakka on 8/19/24. // import Foundation import SwiftUI enum SAMCategoryType: Int { case background = 0 case foreground = 1 case boxOrigin = 2 case boxEnd = 3 var description: String { switch self { case .foreground: return "Foreground" case .background: return "Background" case .boxOrigin: return "Box Origin" case .boxEnd: return "Box End" } } } struct SAMCategory: Hashable { let id: UUID = UUID() let type: SAMCategoryType let name: String let iconName: String let color: Color var typeDescription: String { type.description } static let foreground = SAMCategory( type: .foreground, name: "Foreground", iconName: "square.on.square.dashed", color: .pink ) static let background = SAMCategory( type: .background, name: "Background", iconName: "square.on.square.intersection.dashed", color: .purple ) static let boxOrigin = SAMCategory( type: .boxOrigin, name: "Box Origin", iconName: "", color: .white ) static let boxEnd = SAMCategory( type: .boxEnd, name: "Box End", iconName: "", color: .white ) } struct SAMPoint: Hashable { let id = UUID() let coordinates: CGPoint let category: SAMCategory let dateAdded = Date() } struct SAMBox: Hashable, Identifiable { let id = UUID() var startPoint: CGPoint var endPoint: CGPoint let category: SAMCategory let dateAdded = Date() var midpoint: CGPoint { return CGPoint( x: (startPoint.x + endPoint.x) / 2, y: (startPoint.y + endPoint.y) / 2 ) } } extension SAMBox { var points: [SAMPoint] { [SAMPoint(coordinates: startPoint, category: .boxOrigin), SAMPoint(coordinates: endPoint, category: .boxEnd)] } } struct SAMSegmentation: Hashable, Identifiable { let id = UUID() var image: CIImage var tintColor: Color { didSet { updateTintedImage() } } var title: String = "" var firstAppearance: Int? var isHidden: Bool = false private var tintedImage: CIImage? static let defaultColor: Color = Color(.sRGB, red: 30/255, green: 144/255, blue: 1) static let candidateColors: [Color] = [ defaultColor, Color.red, Color.green, Color.brown, Color.indigo, Color.cyan, Color.yellow, Color.purple, Color.orange, Color.teal, Color.indigo, Color.mint, Color.pink, ] init(image: CIImage, tintColor: Color = Color(.sRGB, red: 30/255, green: 144/255, blue: 1), title: String = "", firstAppearance: Int? = nil, isHidden: Bool = false) { self.image = image self.tintColor = tintColor self.title = title self.firstAppearance = firstAppearance self.isHidden = isHidden updateTintedImage() } private mutating func updateTintedImage() { let ciColor = CIColor(color: NSColor(tintColor)) let monochromeFilter = CIFilter.colorMonochrome() monochromeFilter.inputImage = image monochromeFilter.color = ciColor! monochromeFilter.intensity = 1.0 tintedImage = monochromeFilter.outputImage } static func randomCandidateColor() -> Color? { Self.candidateColors.randomElement() } var cgImage: CGImage { let context = CIContext() return context.createCGImage(tintedImage ?? image, from: (tintedImage ?? image).extent)! } } struct SAMTool: Hashable { let id: UUID = UUID() let name: String let iconName: String } // Tools let pointTool: SAMTool = SAMTool(name: "Point", iconName: "hand.point.up.left") let boundingBoxTool: SAMTool = SAMTool(name: "Bounding Box", iconName: "rectangle.dashed")