Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
UltralyticsAssistant committed Nov 13, 2024
1 parent a86b0f0 commit bc4ad36
Showing 1 changed file with 158 additions and 156 deletions.
314 changes: 158 additions & 156 deletions YOLO/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ class ViewController: UIViewController {
var t3 = CACurrentMediaTime() // FPS start
var t4 = 0.0 // FPS dt smoothed
// var cameraOutput: AVCapturePhotoOutput!
var longSide: CGFloat = 3
var shortSide: CGFloat = 4
var frameSizeCaptured = false
var longSide: CGFloat = 3
var shortSide: CGFloat = 4
var frameSizeCaptured = false

// Developer mode
let developerMode = UserDefaults.standard.bool(forKey: "developer_mode") // developer mode selected in settings
Expand Down Expand Up @@ -130,7 +130,7 @@ class ViewController: UIViewController {

@objc func orientationDidChange() {
videoCapture.updateVideoOrientation()
// frameSizeCaptured = false
// frameSizeCaptured = false
}

@IBAction func vibrate(_ sender: Any) {
Expand Down Expand Up @@ -283,28 +283,28 @@ class ViewController: UIViewController {
let maxBoundingBoxViews = 100
var boundingBoxViews = [BoundingBoxView]()
var colors: [String: UIColor] = [:]
let ultralyticsColorsolors: [UIColor] = [
UIColor(red: 4/255, green: 42/255, blue: 255/255, alpha: 0.6), // #042AFF
UIColor(red: 11/255, green: 219/255, blue: 235/255, alpha: 0.6), // #0BDBEB
UIColor(red: 243/255, green: 243/255, blue: 243/255, alpha: 0.6), // #F3F3F3
UIColor(red: 0/255, green: 223/255, blue: 183/255, alpha: 0.6), // #00DFB7
UIColor(red: 17/255, green: 31/255, blue: 104/255, alpha: 0.6), // #111F68
UIColor(red: 255/255, green: 111/255, blue: 221/255, alpha: 0.6), // #FF6FDD
UIColor(red: 255/255, green: 68/255, blue: 79/255, alpha: 0.6), // #FF444F
UIColor(red: 204/255, green: 237/255, blue: 0/255, alpha: 0.6), // #CCED00
UIColor(red: 0/255, green: 243/255, blue: 68/255, alpha: 0.6), // #00F344
UIColor(red: 189/255, green: 0/255, blue: 255/255, alpha: 0.6), // #BD00FF
UIColor(red: 0/255, green: 180/255, blue: 255/255, alpha: 0.6), // #00B4FF
UIColor(red: 221/255, green: 0/255, blue: 186/255, alpha: 0.6), // #DD00BA
UIColor(red: 0/255, green: 255/255, blue: 255/255, alpha: 0.6), // #00FFFF
UIColor(red: 38/255, green: 192/255, blue: 0/255, alpha: 0.6), // #26C000
UIColor(red: 1/255, green: 255/255, blue: 179/255, alpha: 0.6), // #01FFB3
UIColor(red: 125/255, green: 36/255, blue: 255/255, alpha: 0.6), // #7D24FF
UIColor(red: 123/255, green: 0/255, blue: 104/255, alpha: 0.6), // #7B0068
UIColor(red: 255/255, green: 27/255, blue: 108/255, alpha: 0.6), // #FF1B6C
UIColor(red: 252/255, green: 109/255, blue: 47/255, alpha: 0.6), // #FC6D2F
UIColor(red: 162/255, green: 255/255, blue: 11/255, alpha: 0.6) // #A2FF0B
]
let ultralyticsColorsolors: [UIColor] = [
UIColor(red: 4 / 255, green: 42 / 255, blue: 255 / 255, alpha: 0.6), // #042AFF
UIColor(red: 11 / 255, green: 219 / 255, blue: 235 / 255, alpha: 0.6), // #0BDBEB
UIColor(red: 243 / 255, green: 243 / 255, blue: 243 / 255, alpha: 0.6), // #F3F3F3
UIColor(red: 0 / 255, green: 223 / 255, blue: 183 / 255, alpha: 0.6), // #00DFB7
UIColor(red: 17 / 255, green: 31 / 255, blue: 104 / 255, alpha: 0.6), // #111F68
UIColor(red: 255 / 255, green: 111 / 255, blue: 221 / 255, alpha: 0.6), // #FF6FDD
UIColor(red: 255 / 255, green: 68 / 255, blue: 79 / 255, alpha: 0.6), // #FF444F
UIColor(red: 204 / 255, green: 237 / 255, blue: 0 / 255, alpha: 0.6), // #CCED00
UIColor(red: 0 / 255, green: 243 / 255, blue: 68 / 255, alpha: 0.6), // #00F344
UIColor(red: 189 / 255, green: 0 / 255, blue: 255 / 255, alpha: 0.6), // #BD00FF
UIColor(red: 0 / 255, green: 180 / 255, blue: 255 / 255, alpha: 0.6), // #00B4FF
UIColor(red: 221 / 255, green: 0 / 255, blue: 186 / 255, alpha: 0.6), // #DD00BA
UIColor(red: 0 / 255, green: 255 / 255, blue: 255 / 255, alpha: 0.6), // #00FFFF
UIColor(red: 38 / 255, green: 192 / 255, blue: 0 / 255, alpha: 0.6), // #26C000
UIColor(red: 1 / 255, green: 255 / 255, blue: 179 / 255, alpha: 0.6), // #01FFB3
UIColor(red: 125 / 255, green: 36 / 255, blue: 255 / 255, alpha: 0.6), // #7D24FF
UIColor(red: 123 / 255, green: 0 / 255, blue: 104 / 255, alpha: 0.6), // #7B0068
UIColor(red: 255 / 255, green: 27 / 255, blue: 108 / 255, alpha: 0.6), // #FF1B6C
UIColor(red: 252 / 255, green: 109 / 255, blue: 47 / 255, alpha: 0.6), // #FC6D2F
UIColor(red: 162 / 255, green: 255 / 255, blue: 11 / 255, alpha: 0.6), // #A2FF0B
]

func setUpBoundingBoxViews() {
// Ensure all bounding box views are initialized up to the maximum allowed.
Expand All @@ -318,14 +318,14 @@ class ViewController: UIViewController {
}

// Assign random colors to the classes.
var count = 0
for label in classLabels {
let color = ultralyticsColorsolors[count]
count += 1
if count > 19 {
count = 0
}
colors[label] = color
var count = 0
for label in classLabels {
let color = ultralyticsColorsolors[count]
count += 1
if count > 19 {
count = 0
}
colors[label] = color

}
}
Expand Down Expand Up @@ -358,11 +358,11 @@ class ViewController: UIViewController {
if currentBuffer == nil, let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
currentBuffer = pixelBuffer
if !frameSizeCaptured {
let frameWidth = CGFloat(CVPixelBufferGetWidth(pixelBuffer))
let frameHeight = CGFloat(CVPixelBufferGetHeight(pixelBuffer))
longSide = max(frameWidth, frameHeight)
shortSide = min(frameWidth, frameHeight)
frameSizeCaptured = true
let frameWidth = CGFloat(CVPixelBufferGetWidth(pixelBuffer))
let frameHeight = CGFloat(CVPixelBufferGetHeight(pixelBuffer))
longSide = max(frameWidth, frameHeight)
shortSide = min(frameWidth, frameHeight)
frameSizeCaptured = true
}
/// - Tag: MappingOrientation
// The frame is always oriented based on the camera sensor,
Expand Down Expand Up @@ -482,137 +482,139 @@ class ViewController: UIViewController {
}

func show(predictions: [VNRecognizedObjectObservation]) {
var str = ""
// date
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let seconds = calendar.component(.second, from: date)
let nanoseconds = calendar.component(.nanosecond, from: date)
let sec_day =
var str = ""
// date
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let seconds = calendar.component(.second, from: date)
let nanoseconds = calendar.component(.nanosecond, from: date)
let sec_day =
Double(hour) * 3600.0 + Double(minutes) * 60.0 + Double(seconds) + Double(nanoseconds) / 1E9 // seconds in the day
self.labelSlider.text =

self.labelSlider.text =
String(predictions.count) + " items (max " + String(Int(slider.value)) + ")"
let width = videoPreview.bounds.width // 375 pix
let height = videoPreview.bounds.height // 812 pix

if UIDevice.current.orientation == .portrait {

// ratio = videoPreview AR divided by sessionPreset AR
var ratio: CGFloat = 1.0
if videoCapture.captureSession.sessionPreset == .photo {
ratio = (height / width) / (4.0 / 3.0) // .photo
} else {
ratio = (height / width) / (16.0 / 9.0) // .hd4K3840x2160, .hd1920x1080, .hd1280x720 etc.
let width = videoPreview.bounds.width // 375 pix
let height = videoPreview.bounds.height // 812 pix

if UIDevice.current.orientation == .portrait {

// ratio = videoPreview AR divided by sessionPreset AR
var ratio: CGFloat = 1.0
if videoCapture.captureSession.sessionPreset == .photo {
ratio = (height / width) / (4.0 / 3.0) // .photo
} else {
ratio = (height / width) / (16.0 / 9.0) // .hd4K3840x2160, .hd1920x1080, .hd1280x720 etc.
}

for i in 0..<boundingBoxViews.count {
if i < predictions.count && i < Int(slider.value) {
let prediction = predictions[i]

var rect = prediction.boundingBox // normalized xywh, origin lower left
switch UIDevice.current.orientation {
case .portraitUpsideDown:
rect = CGRect(
x: 1.0 - rect.origin.x - rect.width,
y: 1.0 - rect.origin.y - rect.height,
width: rect.width,
height: rect.height)
case .landscapeLeft:
rect = CGRect(
x: rect.origin.x,
y: rect.origin.y,
width: rect.width,
height: rect.height)
case .landscapeRight:
rect = CGRect(
x: rect.origin.x,
y: rect.origin.y,
width: rect.width,
height: rect.height)
case .unknown:
print("The device orientation is unknown, the predictions may be affected")
fallthrough
default: break
}

for i in 0..<boundingBoxViews.count {
if i < predictions.count && i < Int(slider.value) {
let prediction = predictions[i]

var rect = prediction.boundingBox // normalized xywh, origin lower left
switch UIDevice.current.orientation {
case .portraitUpsideDown:
rect = CGRect(
x: 1.0 - rect.origin.x - rect.width,
y: 1.0 - rect.origin.y - rect.height,
width: rect.width,
height: rect.height)
case .landscapeLeft:
rect = CGRect(
x: rect.origin.x,
y: rect.origin.y,
width: rect.width,
height: rect.height)
case .landscapeRight:
rect = CGRect(
x: rect.origin.x,
y: rect.origin.y,
width: rect.width,
height: rect.height)
case .unknown:
print("The device orientation is unknown, the predictions may be affected")
fallthrough
default: break
}

if ratio >= 1 { // iPhone ratio = 1.218
let offset = (1 - ratio) * (0.5 - rect.minX)
let transform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: offset, y: -1)
rect = rect.applying(transform)
rect.size.width *= ratio
} else { // iPad ratio = 0.75
let offset = (ratio - 1) * (0.5 - rect.maxY)
let transform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: offset - 1)
rect = rect.applying(transform)
ratio = (height / width) / (3.0 / 4.0)
rect.size.height /= ratio
}

// Scale normalized to pixels [375, 812] [width, height]
rect = VNImageRectForNormalizedRect(rect, Int(width), Int(height))

// The labels array is a list of VNClassificationObservation objects,
// with the highest scoring class first in the list.
let bestClass = prediction.labels[0].identifier
let confidence = prediction.labels[0].confidence
// print(confidence, rect) // debug (confidence, xywh) with xywh origin top left (pixels)
let label = String(format: "%@ %.1f", bestClass, confidence * 100)
let alpha = CGFloat((confidence - 0.2) / (1.0 - 0.2) * 0.9)
// Show the bounding box.
boundingBoxViews[i].show(
frame: rect,
label: label,
color: colors[bestClass] ?? UIColor.white,
alpha: alpha) // alpha 0 (transparent) to 1 (opaque) for conf threshold 0.2 to 1.0)

if developerMode {
// Write
if save_detections {
str += String(
format: "%.3f %.3f %.3f %@ %.2f %.1f %.1f %.1f %.1f\n",
sec_day, freeSpace(), UIDevice.current.batteryLevel, bestClass, confidence,
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)
}
}
} else {
boundingBoxViews[i].hide()
}

if ratio >= 1 { // iPhone ratio = 1.218
let offset = (1 - ratio) * (0.5 - rect.minX)
let transform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: offset, y: -1)
rect = rect.applying(transform)
rect.size.width *= ratio
} else { // iPad ratio = 0.75
let offset = (ratio - 1) * (0.5 - rect.maxY)
let transform = CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: offset - 1)
rect = rect.applying(transform)
ratio = (height / width) / (3.0 / 4.0)
rect.size.height /= ratio
}

// Scale normalized to pixels [375, 812] [width, height]
rect = VNImageRectForNormalizedRect(rect, Int(width), Int(height))

// The labels array is a list of VNClassificationObservation objects,
// with the highest scoring class first in the list.
let bestClass = prediction.labels[0].identifier
let confidence = prediction.labels[0].confidence
// print(confidence, rect) // debug (confidence, xywh) with xywh origin top left (pixels)
let label = String(format: "%@ %.1f", bestClass, confidence * 100)
let alpha = CGFloat((confidence - 0.2) / (1.0 - 0.2) * 0.9)
// Show the bounding box.
boundingBoxViews[i].show(
frame: rect,
label: label,
color: colors[bestClass] ?? UIColor.white,
alpha: alpha) // alpha 0 (transparent) to 1 (opaque) for conf threshold 0.2 to 1.0)

if developerMode {
// Write
if save_detections {
str += String(
format: "%.3f %.3f %.3f %@ %.2f %.1f %.1f %.1f %.1f\n",
sec_day, freeSpace(), UIDevice.current.batteryLevel, bestClass, confidence,
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)
}
}
} else {
let frameAspectRatio = longSide / shortSide
let viewAspectRatio = width / height
var scaleX: CGFloat = 1.0
var scaleY: CGFloat = 1.0
var offsetX: CGFloat = 0.0
var offsetY: CGFloat = 0.0

if frameAspectRatio > viewAspectRatio {
scaleY = height / shortSide
scaleX = scaleY
offsetX = (longSide * scaleX - width) / 2
} else {
scaleX = width / longSide
scaleY = scaleX
offsetY = (shortSide * scaleY - height) / 2
boundingBoxViews[i].hide()
}

for i in 0..<boundingBoxViews.count {
}
} else {
let frameAspectRatio = longSide / shortSide
let viewAspectRatio = width / height
var scaleX: CGFloat = 1.0
var scaleY: CGFloat = 1.0
var offsetX: CGFloat = 0.0
var offsetY: CGFloat = 0.0

if frameAspectRatio > viewAspectRatio {
scaleY = height / shortSide
scaleX = scaleY
offsetX = (longSide * scaleX - width) / 2
} else {
scaleX = width / longSide
scaleY = scaleX
offsetY = (shortSide * scaleY - height) / 2
}

for i in 0..<boundingBoxViews.count {
if i < predictions.count {
let prediction = predictions[i]

var rect = prediction.boundingBox

rect.origin.x = rect.origin.x * longSide * scaleX - offsetX
rect.origin.y = height - (rect.origin.y * shortSide * scaleY - offsetY + rect.size.height * shortSide * scaleY)
rect.origin.y =
height
- (rect.origin.y * shortSide * scaleY - offsetY + rect.size.height * shortSide * scaleY)
rect.size.width *= longSide * scaleX
rect.size.height *= shortSide * scaleY

let bestClass = prediction.labels[0].identifier
let confidence = prediction.labels[0].confidence

let label = String(format: "%@ %.1f", bestClass, confidence * 100)
let alpha = CGFloat((confidence - 0.2) / (1.0 - 0.2) * 0.9)
// Show the bounding box.
Expand Down

0 comments on commit bc4ad36

Please sign in to comment.