Skip to content

Instantly share code, notes, and snippets.

@frijole
Created July 21, 2021 18:12
Show Gist options
  • Save frijole/f29956881d70fe89b08bd07358b4d702 to your computer and use it in GitHub Desktop.
Save frijole/f29956881d70fe89b08bd07358b4d702 to your computer and use it in GitHub Desktop.
from a project to scan screenshots of the FlightRadar24 app
import UIKit
import Vision
class ImageScanner: NSObject {
struct ImageSlices {
var registrationSlice: UIImage
var operatorSlice: UIImage
var flightSlice: UIImage
var originSlice: UIImage
var destinationSlice: UIImage
var equipmentSlice: UIImage
}
enum Slice {
case registration
case owner
case flight
case origin
case destination
case equipment
var cropZone: CGRect {
let deviceScale: CGFloat = 3
switch self {
case .flight:
return CGRect(x: 0,
y: 0,
width: 245 * deviceScale,
height: 19 * deviceScale)
case .owner: // operator
return CGRect(x: 0,
y: 19 * deviceScale,
width: 245 * deviceScale,
height: 12 * deviceScale)
case .equipment:
return CGRect(x: 0,
y: 91 * deviceScale,
width: 245 * deviceScale,
height: 19 * deviceScale)
case .registration:
return CGRect(x: 245 * deviceScale,
y: 91 * deviceScale,
width: 128 * deviceScale,
height: 19 * deviceScale)
case .origin:
return CGRect(x: 0,
y: 31 * deviceScale,
width: 122 * deviceScale,
height: 34 * deviceScale)
case .destination:
return CGRect(x: 123 * deviceScale,
y: 31 * deviceScale,
width: 122 * deviceScale,
height: 34 * deviceScale)
}
}
}
private func prepareImage(_ imageData: Data) -> ImageSlices {
guard let image = UIImage(data: imageData) else {
print("unable to create image from data")
fatalError()
}
let deviceScale: CGFloat = 3
let cropZone = CGRect(
x: 0,
y: image.size.height - (188 * deviceScale),
width: image.size.width,
height: 188 * deviceScale
)
guard let cutImageRef: CGImage = image.cgImage?.cropping(to:cropZone) else {
print("unable to crop image")
fatalError()
}
// let result: UIImage = UIImage(cgImage: cutImageRef)
guard let registrationImageRef: CGImage = cutImageRef.cropping(to: Slice.registration.cropZone),
let ownerImageRef: CGImage = cutImageRef.cropping(to: Slice.owner.cropZone),
let equipmentImageRef: CGImage = cutImageRef.cropping(to: Slice.equipment.cropZone),
let flightImageRef: CGImage = cutImageRef.cropping(to: Slice.flight.cropZone),
let originImageRef: CGImage = cutImageRef.cropping(to: Slice.origin.cropZone),
let destinationImageRef: CGImage = cutImageRef.cropping(to: Slice.destination.cropZone) else {
print("failed to make one of the image slices")
fatalError()
}
return ImageSlices(
registrationSlice: UIImage(cgImage: registrationImageRef),
operatorSlice: UIImage(cgImage: ownerImageRef),
flightSlice: UIImage(cgImage: flightImageRef),
originSlice: UIImage(cgImage: originImageRef),
destinationSlice: UIImage(cgImage: destinationImageRef),
equipmentSlice: UIImage(cgImage: equipmentImageRef)
)
}
private func scanImage(_ imageData: Data?) -> [String] {
guard let imageData = imageData else {
print("no image data found")
return []
}
var results = [String]()
let handler = VNImageRequestHandler(data: imageData)
let request = VNRecognizeTextRequest { (request, error) in
if error != nil {
print("vision request error: \(String(describing: error))")
}
if let requestResults = request.results as? [VNRecognizedTextObservation] {
results = requestResults.compactMap { $0.topCandidates(1).first?.string }
}
}
do {
try handler.perform([request])
} catch {
print("vision request failed: \(error)")
return []
}
return results
}
func processImage(_ imageData: Data, imageDetails: ImageDetails) -> ImageDetails? {
let slices = prepareImage(imageData)
let registrationString = scanImage(slices.registrationSlice.pngData()).first
let operatorString = scanImage(slices.operatorSlice.pngData()).first
let flightString = scanImage(slices.flightSlice.pngData()).first
let originString = scanImage(slices.originSlice.pngData()).first
let destinationString = scanImage(slices.destinationSlice.pngData()).first
let equipmentString = scanImage(slices.equipmentSlice.pngData()).first
var route = [String]()
if let origin = originString {
route.append(origin)
}
if let destination = destinationString {
route.append(destination)
}
let routeString = route.joined(separator: " - ")
return ImageDetails(
filename: imageDetails.filename,
registration: registrationString?.replacingOccurrences(of: "REG: ", with: ""),
owner: operatorString,
flight: flightString,
route: routeString,
equipment: equipmentString,
time: imageDetails.time,
asset: imageDetails.asset)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment