I'm working on a project which converts user's face to emoji. I use Apple's ARKit in this purpose.
I need to get the most probable option. I wrote this code:
func renderer(for anchor: ARAnchor) {
guard let faceAnchor = anchor as? ARFaceAnchor else {
return
}
let shapes = faceAnchor.blendShapes
let browDownLeft = shapes[.browDownLeft]!.doubleValue
let browInnerUp = shapes[.browInnerUp]!.doubleValue
let browOuterUpLeft = shapes[.browOuterUpLeft]!.doubleValue
let leftBrowMax = max(browDownLeft, browInnerUp, browOuterUpLeft)
switch leftBrowMax {
case browDownLeft:
userFace.leftBrow = .browDown
case browInnerUp:
userFace.leftBrow = .browInnerUp
case browOuterUpLeft:
userFace.leftBrow = .browOuterUp
default:
userFace.leftBrow = .any
}
}
I need to duplicate function's body six time (for brows, eyes and mouth sides), so I want to write it in a more convenient way. Is there any options in Swift like numpy's argmax function? Also I need to specify arguments range, because arguments for mouth should not be compared with arguments for brows.
You can use something like this:
func maxBlendShape(for blendShapes: [ARFaceAnchor.BlendShapeLocation], in shape: [ARFaceAnchor.BlendShapeLocation: NSNumber]) -> Double? {
blendShapes
.compactMap { shape[$0] }
.map(\.doubleValue)
.max()
}
Usage would then be something like this:
maxBlendShape(for: [.browDownLeft, .browInnerUp, .browOuterUpLeft], in: faceAnchor.blendShapes)
Note: Nothing here is specific to ARKit, you just filter some keys from the dictionary and find their max value. A generic solution could look like this:
extension Dictionary where Value == NSNumber {
func maxDouble(for keys: [Key]) -> Double? {
keys
.compactMap({self[$0]})
.map(\.doubleValue)
.max()
}
}
faceAnchor.blendShapes.maxDouble(for: [.browInnerUp, .browDownLeft, .browOuterUpLeft])
Related
I have created enum with associated value and I want to be able to dynamically update associated value. As far as I know Swift doesn't support that at the moment.
Because of that I used following approach:
enum PersonInfo {
class EnumValue<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
// Instead of using String or Bool or any other type directly, use EnumValue wrapper
case firstName(EnumValue<String>)
case lastName(EnumValue<String>)
case isAdult(EnumValue<Bool>)
}
I want to add function that would update EnumValue.value property in following way:
func updateAssociatedValue<V>(_ updateValue: V) {
let mirror = Mirror(reflecting: self)
for associatedValue in mirror.children {
guard let value = associatedValue.value as? EnumValue<V> else {
continue
}
value.value = updateValue
}
}
Problem is that this guard statement always fails (guard let value = associatedValue.value as? EnumValue<V>) and I can't figure it out why.
On the other hand, when I write updateAssociatedValue with typed type then things work properly:
// This works
func updateAssociatedValue(_ updateValue: String) {
let mirror = Mirror(reflecting: self)
for associatedValue in mirror.children {
guard let value = associatedValue.value as? EnumValue<String> else {
continue
}
value.value = updateValue
}
}
Things compile normally but during the runtime guard statement always fails. Am I using generic value in some incorrect way? Should I use somehow updateValue.Type or updateValue.self (I tried but it didn't work).
Example of usage:
var array: [PersonInfo] = [
.firstName(PersonInfo.EnumValue("John")),
.lastName(PersonInfo.EnumValue("Doe")),
.isAdult(PersonInfo.EnumValue(false))
]
print(array)
// John, Doe, false
array.first?.updateAssociatedValue("Mike")
print(array)
// Mike, Doe, false
I can always reassign enum value in array but if possible I want to avoid that. That's the reason for asking this question.
I basically followed this great tutorial on VNRecognizeTextRequest and modified some things:
https://bendodson.com/weblog/2019/06/11/detecting-text-with-vnrecognizetextrequest-in-ios-13/
I am trying to recognise text from devices with seven-segment-style displays which seems to get a bit tricky for this framework. Often it works, but numbers with comma are hard and if there's a a gap as well. I'm wondering whether there is the possibility to "train" this recognition engine. Another possibility might be to somehow tell it to specifically look for numbers, maybe then it can focus more processing power on that instead of generically looking for text?
I use this modified code for the request:
ocrRequest = VNRecognizeTextRequest { (request, error) in
guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
for observation in observations {
guard let topCandidate = observation.topCandidates(1).first else { continue }
let topCandidateText = topCandidate.string
if let float = Float(topCandidateText), topCandidate.confidence > self.bestConfidence {
self.bestCandidate = float
self.bestConfidence = topCandidate.confidence
}
}
if self.bestConfidence >= 0.5 {
self.captureSession?.stopRunning()
DispatchQueue.main.async {
self.found(measurement: self.bestCandidate!)
}
}
}
ocrRequest.recognitionLevel = .accurate
ocrRequest.minimumTextHeight = 1/10
ocrRequest.recognitionLanguages = ["en-US", "en-GB"]
ocrRequest.usesLanguageCorrection = true
There are 3 global variables in this class regarding the text recognition:
private var ocrRequest = VNRecognizeTextRequest(completionHandler: nil)
private var bestConfidence: Float = 0
private var bestCandidate: Float?
Thanks in advance for your answers, even though this is not directly code-related, but more concept-related (i.e. "am I doing something wrong / did I overlook an important feature?" etc.).
Example image that work:
Example that half works:
(recognises 58)
Example that does not work:
(it has a very low confidence for "91" and often thinks it's just 9 or 9!)
kindly note that my question is specific to Swift 4 syntax. I have a bulky/large array of Strings and I want to filter it for getting all values in it which are started with some specific characters/substring. That means I need each String in my array which matches to started with some substring. I found different links which gives me code for Objective-C and I am unable to implement it in Swift 4 because of that methods are not available in Swift 4. I solved my question manually by iterating my array in for loop but it gives very slow result So I don't want to use any loop here, So any help will useful. Thanks in advance. See my code below:
func search() -> Void {
var dummyStringsArray:[String] = ["Hotel Restaurants","Restaurants","Certified Green Restaurant(R)","Japnies Food Restauarants","Grill Restaurants","Restaurant Equipment","Wholsale Restaurant Fixtures","American Food","Wholsale Restaurant Supplies","Veg Restaurants","Barbecue Restaurants","Non-Veg Restaurants"]
var displayDataArray:[String] = []
let searchString:NSString = (textField.text!).lowercased() as NSString
for string in self.dummyStringsArray {
let mainString:NSString = string.lowercased() as NSString
if mainString.length >= searchString.length {
let compareString = String(mainString.substring(to: searchString.length))
if searchString as String == compareString {
displayDataArray.append(string)
}
}
}
}
So if I entered text in textField as 're' then it should return displayDataArray containing values like "Restaurants", "Restaurant Equipment".
I think you can't do this without any loop because you need to go through all the elements
But I can offer you more elegant solution with filter function:
func search() -> Void {
let dummyStringsArray:[String] = ["Hotel Restaurants","Restaurants","Certified Green Restaurant(R)","Japnies Food Restauarants","Grill Restaurants","Restaurant Equipment","Wholsale Restaurant Fixtures","American Food","Wholsale Restaurant Supplies","Veg Restaurants","Barbecue Restaurants","Non-Veg Restaurants"]
let searchString: String = (textField.text!).lowercased()
let displayDataArray: [String] = dummyStringsArray.filter({ String($0.prefix(searchString.count)).lowercased() == searchString })
}
You will probably get the best performance using range(of:options:) while passing in the options of .caseInsensitive and .anchored.
func search() -> Void {
let dummyStringsArray = ["Hotel Restaurants","Restaurants","Certified Green Restaurant(R)","Japnies Food Restauarants","Grill Restaurants","Restaurant Equipment","Wholsale Restaurant Fixtures","American Food","Wholsale Restaurant Supplies","Veg Restaurants","Barbecue Restaurants","Non-Veg Restaurants"]
let searchString = textField.text!
let displayDataArray = dummyStringsArray.filter { $0.range(of: searchString, options: [ .caseInsensitive, .anchored ]) != nil }
}
The if let intensity = intensity {} else {} is repetitive. How would I create a function to replace this repetitive code? Or what other tool could I use?
I'm new to this all. Any help appreciated.
func process(filters: [String], intensity: Int? = nil) {
for filter in filters {
switch filter {
case "blue":
if let intensity = intensity {
self.blue(value: intensity)
} else {
self.blue()
}
case "contrast":
if let intensity = intensity {
self.contrast(value: intensity)
} else {
self.contrast()
}
case "blackAndWhite":
if let intensity = intensity {
self.blackAndWhite(value: intensity)
} else {
self.blackAndWhite()
}
case "halfBrightness":
if let intensity = intensity {
self.halfBrightness(value: intensity)
} else {
self.halfBrightness()
}
case "doubleBrightness":
if let intensity = intensity {
self.doubleBrightness(value: intensity)
} else {
self.doubleBrightness()
}
default:
print("The filter you specified doesn't exist.")
}
}
}
One possible option is to change all of those xxx(value:) methods so they accept an optional value. Let the implementation of each method deal with the optional value being nil as appropriate. Then each of your case statements becomes:
case "whatever":
self.someFunction(value: intensity)
Much cleaner.
You can use reflection to call the method based on the filter name, replacing all of the cases with a single block of code, with the added benefit that new filters added later will not require any change in this section of code.
Here's a starting point for you:
let selector_name = filter + ":" + (intensity != nil ? "_:" : "")
let selector: Selector = Selector(selector_name)
let method = class_getClassMethod(Test.self, selector)
let implementation = method_getImplementation(method)
typealias Function = #convention(c) (AnyObject, Selector, Int) -> Void
let function = unsafeBitCast(implementation, to: Function.self)
function(self, selector, intensity!)
This code replaces your "switch" block. This isn't complete, since it doesn't handle your intensity == nil case, and it doesn't handle not finding the method that matches the filter name. And "Test.self" needs to be replaced with whatever you class name is, with the .self suffix. This is just intended to get you started.
You will probably take a performance hit, since using reflection usually does. Unless this code is being called many times per second, it should be insignificant.
I am a swift beginner (my background is VBA, VB.NET). I first found the double optional variable (??) confusing when using the window variable on the UIApplicationDelegate (.window??) object. After some research I understand that a variable can be declared to be optional in a protocol as well as return an optional type.
One way to safely use the variable would be:
if let checkHasVar = UIApplication.sharedApplication().delegate?.window {
if let varIsSomething = checkHasVar {
//window exists and is referencing an object
}
}
Another would be:
guard let hasWindowVar = UIApplication.sharedApplication().delegate?.window, window = hasWindowVar else {
return
}
Both work fine but I would be interested to learn whether this is a sensible approach to dealing with double optionals
There're many approaches.
if let ...
if let windowProperty = UIApplication.sharedApplication().delegate?.window {
if let window = windowProperty {
print(window)
}
}
Chained if let ...
if let windowProperty = UIApplication.sharedApplication().delegate?.window,
window = windowProperty {
print(window)
}
Pattern matching ...
if case .Some(let windowProperty) = UIApplication.sharedApplication().delegate?.window,
case .Some(let window) = windowProperty {
print(window)
}
guard ...
guard let windowProperty = UIApplication.sharedApplication().delegate?.window,
window = windowProperty else {
return
}
print(window)
You can combine them ...
if let windowProperty = UIApplication.sharedApplication().delegate?.window,
case .Some(let window) = windowProperty {
print(window)
}
Both work fine but I would be interested to learn whether this is a sensible approach to dealing with double optionals
Sensible? Does it work for you? Is your code readable? Do you understand it? Pick whatever you want, you like and use it.
This type of questions is going to lead to opinionated answers, which is not good. Lot of ways to do thing A and it's up to you what you're going to choose. No one can help you with this.
guard let = if not let. With simple condition i advice you using if let, otherwise using guard let