jenkins-bot has submitted this change and it was merged.

Change subject: un-static face detector
......................................................................


un-static face detector

We were reusing the face face detector (and its state) across all image
objects. This is probably what caused the crash, but at the very least
this will remove an unnecessarily-persistent piece of state and prevent
threading issues.

Bug: T106025
Change-Id: I863a7f49939afd90fc7a631333dd008906a7dde4
---
M MediaWikiKit/MediaWikiKit/MWKImage.h
M MediaWikiKit/MediaWikiKit/MWKImage.m
M Wikipedia/Custom Objects/WMFFaceDetector.h
M Wikipedia/Custom Objects/WMFFaceDetector.m
4 files changed, 62 insertions(+), 73 deletions(-)

Approvals:
  Fjalapeno: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/MediaWikiKit/MediaWikiKit/MWKImage.h 
b/MediaWikiKit/MediaWikiKit/MWKImage.h
index e6a9895..e8fbf18 100644
--- a/MediaWikiKit/MediaWikiKit/MWKImage.h
+++ b/MediaWikiKit/MediaWikiKit/MWKImage.h
@@ -53,6 +53,7 @@
  *  terms of the unit rect coordinates (0…1)
  *
  *  @param normalized  Set YES to normalize to the image
+ *
  *  @return The primary focal rect
  */
 - (CGRect)primaryFocalRectNormalizedToImageSize:(BOOL)normalized;
@@ -62,11 +63,13 @@
  *  If normalized is set to YES, the rect will be normailzed
  *  to the image size. If set to NO, the rect will be in
  *  terms of the unit rect coordinates (0…1)
-
  *  @return The rect enclosing all focal rects
  */
 - (CGRect)rectEnclosingAllFocalRectsNormalizedToImageSize:(BOOL)normalized;
 
+- (BOOL)hasFaces;
+
+- (BOOL)didDetectFaces;
 
 - (void)importImageData:(NSData*)data;
 
diff --git a/MediaWikiKit/MediaWikiKit/MWKImage.m 
b/MediaWikiKit/MediaWikiKit/MWKImage.m
index 75077bf..f2d4c09 100644
--- a/MediaWikiKit/MediaWikiKit/MWKImage.m
+++ b/MediaWikiKit/MediaWikiKit/MWKImage.m
@@ -57,19 +57,21 @@
 
 #pragma mark - Focal Rects
 
+- (BOOL)didDetectFaces {
+    return self.focalRectsInUnitCoordinatesAsStrings != nil;
+}
+
+- (BOOL)hasFaces {
+    return self.focalRectsInUnitCoordinatesAsStrings.count > 0;
+}
+
 - 
(void)calculateFocalRectsBasedOnFaceDetectionWithImageData:(NSData*)imageData {
-    if ([self.focalRectsInUnitCoordinatesAsStrings count] == 0) {
+    if (!self.didDetectFaces) {
         if (!imageData) {
             imageData = [self asNSData];
         }
-
-        static WMFFaceDetector* faceDetector = nil;
-        if (!faceDetector) {
-            faceDetector = [[WMFFaceDetector alloc] init];
-        }
-        [faceDetector setImageWithData:imageData];
+        WMFFaceDetector* faceDetector = [[WMFFaceDetector alloc] 
initWithImageData:imageData];
         [faceDetector detectFaces];
-
         self.focalRectsInUnitCoordinatesAsStrings = [faceDetector 
allFaceBoundsAsStringsNormalizedToUnitRect];
     }
 }
@@ -82,7 +84,7 @@
 }
 
 - (CGRect)primaryFocalRectNormalizedToImageSize:(BOOL)normalized {
-    if (self.focalRectsInUnitCoordinatesAsStrings.count == 0) {
+    if (!self.hasFaces) {
         return CGRectZero;
     }
 
diff --git a/Wikipedia/Custom Objects/WMFFaceDetector.h b/Wikipedia/Custom 
Objects/WMFFaceDetector.h
index a3b1338..7a3da4b 100644
--- a/Wikipedia/Custom Objects/WMFFaceDetector.h
+++ b/Wikipedia/Custom Objects/WMFFaceDetector.h
@@ -3,24 +3,20 @@
 
 @interface WMFFaceDetector : NSObject
 
-@property (nonatomic, strong) CIImage* image;
+@property (nonatomic, strong, readonly) CIImage* image;
 
 /**
- *  Set the image property with UIImage
- *  Useful if you didn't have a CIImage before hand
- *  Will attempt to use image.CIImage first, then fallback to 
UIImagePNGRepresentation()
+ * The `CIFeature` objects representing faces detected by the receiver.
  *
- *  @param image the image to use
+ * This will be `nil` before detection is run, and a non-empty array 
afterwards.
  */
-- (void)setImageWithUIImage:(UIImage*)image;
+@property (nonatomic, copy, readonly) NSArray* faces;
 
-/**
- *  Set the image property with NSData
- *  Useful if you didn't have a CIImage before hand
- *
- *  @param data to create the image from
- */
-- (void)setImageWithData:(NSData*)data;
+- (instancetype)initWithCIImage:(CIImage*)image NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithUIImage:(UIImage*)image;
+
+- (instancetype)initWithImageData:(NSData*)data;
 
 /**
  *  Detect faces synchronously
@@ -33,13 +29,6 @@
  *  @param completion fired when face detection is completed
  */
 - (void)detectFacesWithCompletionBlock:(dispatch_block_t)completion;
-
-/**
- *  All faces
- *
- *  @return An array of CIFaceFeature
- */
-- (NSArray*)allFaces;
 
 /**
  *  Get an array of the bounds of all the faces. Each bounds will be normalized
diff --git a/Wikipedia/Custom Objects/WMFFaceDetector.m b/Wikipedia/Custom 
Objects/WMFFaceDetector.m
index 426d743..546a146 100644
--- a/Wikipedia/Custom Objects/WMFFaceDetector.m
+++ b/Wikipedia/Custom Objects/WMFFaceDetector.m
@@ -6,73 +6,68 @@
 #import "WMFGeometry.h"
 
 @interface WMFFaceDetector ()
-
-@property (strong, atomic) CIDetector* detector;
-@property (strong, atomic) NSArray* faces;
-@property (assign, atomic) BOOL faceDetectionHasRan;
-
+@property (strong, nonatomic) CIDetector* detector;
+@property (strong, nonatomic) CIImage* image;
+@property (readwrite, copy, nonatomic) NSArray* faces;
 @end
 
 @implementation WMFFaceDetector
 
++ (CIDetector*)sharedDetector {
+    static CIDetector* sharedDetector;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sharedDetector = [CIDetector detectorOfType:CIDetectorTypeFace
+                                            context:nil
+                                            options:@{
+                              CIDetectorAccuracy: CIDetectorAccuracyLow,
+                              CIDetectorMinFeatureSize: @(0.15)
+                          }];
+    });
+    return sharedDetector;
+}
+
 - (instancetype)init {
+    return [self initWithCIImage:nil];
+}
+
+- (instancetype)initWithImageData:(NSData*)data {
+    NSParameterAssert(data.length);
+    return [self initWithCIImage:[[CIImage alloc] initWithData:data]];
+}
+
+- (instancetype)initWithUIImage:(UIImage*)image {
+    return [self initWithCIImage:image.CIImage ? : [[CIImage alloc] 
initWithCGImage:image.CGImage]];
+}
+
+- (instancetype)initWithCIImage:(CIImage*)image {
+    NSParameterAssert(image);
+    if (!image) {
+        return nil;
+    }
     self = [super init];
     if (self) {
-        self.detector =
-            [CIDetector detectorOfType:CIDetectorTypeFace
-                               context:nil
-                               options:@{
-                 CIDetectorAccuracy: CIDetectorAccuracyLow,
-                 CIDetectorMinFeatureSize: @(0.15)
-             }];
+        self.detector = [[self class] sharedDetector];
+        self.image    = image;
     }
     return self;
 }
 
-- (void)setImageWithUIImage:(UIImage*)image {
-    if (image.CIImage) {
-        self.image = image.CIImage;
-    } else {
-        [self setImageWithData:UIImagePNGRepresentation(image)];
-    }
-}
-
-- (void)setImageWithData:(NSData*)data {
-    CIImage* ciImage = [[CIImage alloc] initWithData:data];
-    self.image = ciImage;
-}
-
 - (void)detectFaces {
-    if (!self.image) {
-        return;
-    }
-
-    if (!self.faceDetectionHasRan) {
-        self.faces               = [self.detector featuresInImage:self.image];
-        self.faceDetectionHasRan = YES;
+    if (!self.faces) {
+        self.faces = [self.detector featuresInImage:self.image];
     }
 }
 
 - (void)detectFacesWithCompletionBlock:(dispatch_block_t)completion {
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 
0), ^{
         [self detectFaces];
-
         if (completion) {
             dispatch_async(dispatch_get_main_queue(), ^{
                 completion();
             });
         }
     });
-}
-
-- (void)setImage:(CIImage*)image {
-    _image                   = image;
-    self.faces               = nil;
-    self.faceDetectionHasRan = NO;
-}
-
-- (NSArray*)allFaces {
-    return self.faces;
 }
 
 - (NSArray*)allFaceBoundsAsStringsNormalizedToUnitRect {

-- 
To view, visit https://gerrit.wikimedia.org/r/226649
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I863a7f49939afd90fc7a631333dd008906a7dde4
Gerrit-PatchSet: 3
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Bgerstle <bgers...@wikimedia.org>
Gerrit-Reviewer: Fjalapeno <cfl...@wikimedia.org>
Gerrit-Reviewer: Mhurd <mh...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to