This project is not maintained
KVNBoundedImageView
KVNBoundedImageView attempts to keep faces visible and centered in a UIImageView. It is designed to be easy to use and extensible for different types of image detection.
From
To
With configurable detection speed, operation queues, caching, and utilizing the optimized image rendering of UIImageView (no custom drawing here), KVNBoundedImageView aims to be as fast as possible, without blocking the main thread when heavy lifting is needed. Simple image loading via a URL is also available, so you may even be able to throw away that UIImageView category you've been dragging along between projects.
Usage
KVNBoundedImageView attempts to watch as many changes as possible within the UIImageView's properties and respond appropriately to keep the features visible. However, if at any point you find the view not responding to changes, you can manually force it to update by calling fitToFeature
. See the Example project for more details on all the examples below
Creating from NIB or Storyboard
Drag a UIImageView onto the scene and change it's class to KVNBoundedImageView in the Utilities pane under Identity Inspector. You can set the reuse cache name under User Defined Runtime Attributes by setting nibImageCacheName
with a NSString value.
Creating Programically
Bare Minimum
KVNBoundedImageView *imageView = [[KVNBoundedImageView alloc] initWithFrame:aRect];
[imageView setImage:[UIImage imageNamed:@"test"] cacheName:@"test"];
[imageScrollView addSubview:imageView];
With Some Configuration
When doing custom configuration, it is advised to set the all the parameters before you set the image to be detected. Otherwise, the detection & cropping will start, and then immediately be cancelled and restarted.
KVNBoundedImageView *imageView = [[KVNBoundedImageView alloc] initWithFrame:aRect];
[imageView setBoundingBoxScheme:BoundingBoxSchemeLargest];
[imageView setBoundingPadding:10.0];
[imageView setImage:[UIImage imageNamed:@"test"] cacheName:@"test" placeholder:[UIImage imageNamed:@"placeholder"]];
[imageScrollView addSubview:imageView];
Load from a URL
KVNBoundedImageView *imageView = [[KVNBoundedImageView alloc] initWithFrame:aRect];
[imageScrollView setImageFromURL:aURL cacheName:@"test" placeholder:[UIImage imageNamed:@"placeholder"]];
Properties
boundingPadding
:CIDetector
has a thing against foreheads, it doesn't include them in the detection bounds. If you roughly know the size of the faces in your image or if you have having trouble with foreheads being cut off at the top of your image (or chins at the bottom), playing with this value might give you better results. It isn't a perfect science, though, and edge-cases abound!detectorAccuracy
: Changes theCIDetectorAccuracy
used for feature detection. Default isCIDetectorAccuracyLow
boundingBoxScheme
: How the bounding rectangle is calculated.BoundingBoxSchemeAll
: All features detected are used. A rectangle that fits all features is created and used. This is the default behaviorBoundingBoxSchemeLargest
: Uses the largest face found. Good for if you have images of crowds with a clear subject.BoundingBoxSchemeSmallest
: Uses the smallest face found. To be honest, I only threw this in because it was super easy to implement. I have no idea why you would want to use this. Maybe because everyone loves an underdog?
boundingEnabled
: Enables or disables the detection and bounding. IfNO
, the image is displayed withUIViewContentModeScaleAspectFill
animated
: To make the transition a little nicer (but only a little, there is room for improvement), this provides a short Core Animation (kCATransitionFade) when the detection has finished. Defaults toYES
.
Installation
To manually install KVNBoundedImageView, add KVNBoundedImageView.m and KVNBoundedImageView.h files to your project. Import the CoreImage framework into your project.
Installation with CocoaPods
CocoaPods is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like KVNBoundedImageView in your projects. See the "Getting Started" guide for more information.
Podfile
pod "KVNBoundedImageView"
Requirements
- CoreImage
- iOS 5.0+
Extending KVNBoundingImageView
This library is designed with extensibility in mind. It is fairly easy to implement your own detection, so long as you do the actual detection leg work yourself (IE: The Hard Part). Perhaps you have written a dog detector using OpenCV
and want to make an app focused on dogs, without pesky cats getting in the way (A noble calling). To accomplish this, all you have to do is implement boundingRectangleForImage
in your subclass and return the CGRect
that you wish to be visible. This rect needs to be in the UIView
coordinate system (origin is in the upper-left). Keep in mind that boundingRectangleForImage
may be called on a background queue, so operations that are not thread safe should be done. As a convenience to developers who may be using your subclass, you should also extend foundFeatures
and return all the rects (stored in NSValue
) that were detected in the image.
Note on Optimization and Caching
This library utilizes a NSCache to store the cropped images for fast recall. The key uses a supplied cache name along with the detection accuracy, bounding box scheme, and current view aspect ratio. This is so the image does not get reused in a view that won't properly fit. NSCache responds to OS-level memory warnings to clear space, but if you are worried about memory usage, minimize the different configuration you use or you can just use setImage:
or pass nil for a cache name and nothing will be cached. This caching designed with use in a UITableView in mind, however it hasn't been extensively tested so proceed with caution.
Memory Usage
This library uses a bit more memory then one would think, mainly around the usage of CIDetector. CIDetector seems to have a problem with unbounded memory growth. Not reusing the detector, instead instantiating one as needed, mitigates this problem but still doesn't seem to remove it entirely and is against what the documentation recommends. OpenRadar concerning this issue.
Animations
The imageview has to recrop the image with every aspect ratio change, so it is probably not the best idea to have this component enabled while animating the bounds (center, origin is fine). The recommended way:
UIImage *originalImage = imageView.originalImage;
UIImage *croppedImage = imageView.image;
[imageView setBoundingEnabled:YES];
[imageView setImage:croppedImage];
[UIView animateWithDuration:1.0 animations:^{
// Mess with bounds
} completion:^(BOOL f) {
[imageView setImage:originalImage cacheName:@"cacheName"];
[imageView setBoundingEnabled:YES];
}];
Author
Kevin Donnelly - @donnellyk
License
KVNBoundedImageView is available under the MIT license. See the LICENSE file for more info.
Sample Photos
All example photos taken from Flickr licensed under The Creative Commons. Thanks to Thomas Saito, Franki, Ableman.