Created
July 21, 2021 18:12
-
-
Save frijole/f29956881d70fe89b08bd07358b4d702 to your computer and use it in GitHub Desktop.
from a project to scan screenshots of the FlightRadar24 app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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