Skip to content

Commit

Permalink
Switched from using NSNumbers for each point in each glyph to using l…
Browse files Browse the repository at this point in the history
…ower-level arrays. Fixed a variety of memory leaks and wrapped core routine in an NSAutoreleasePool to prevent memory buildup
  • Loading branch information
bengotow committed Jan 27, 2013
1 parent 0375ac1 commit e3cecce
Show file tree
Hide file tree
Showing 17 changed files with 145 additions and 82 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ build/
*.mode2v3

xcuserdata

/DerivedData/
20 changes: 20 additions & 0 deletions WTMGlyph/WTMDetectionResult.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// WTMDetectionResult.h
// WTMGlyphDemo
//
// Created by Ben Gotow on 1/27/13.
// Copyright (c) 2013 torin.nguyen@2359media.com. All rights reserved.
//

#import <Foundation/Foundation.h>

@class WTMGlyph;

@interface WTMDetectionResult : NSObject

@property (nonatomic, retain) WTMGlyph * bestMatch;
@property (nonatomic, assign) float bestScore;
@property (nonatomic, retain) NSArray * allScores;
@property (nonatomic, assign) BOOL success;

@end
14 changes: 14 additions & 0 deletions WTMGlyph/WTMDetectionResult.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// WTMDetectionResult.m
// WTMGlyphDemo
//
// Created by Ben Gotow on 1/27/13.
// Copyright (c) 2013 torin.nguyen@2359media.com. All rights reserved.
//

#import "WTMDetectionResult.h"
#import "WTMGlyph.h"

@implementation WTMDetectionResult

@end
Empty file modified WTMGlyph/WTMGlyph.h
100644 → 100755
Empty file.
30 changes: 15 additions & 15 deletions WTMGlyph/WTMGlyph.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ @implementation WTMGlyph

#pragma mark - Lifecycle

- (void)dealloc {
- (void)dealloc
{
[name release];
[strokes release];
[strokeOrders release];
Expand All @@ -34,10 +35,11 @@ - (void)dealloc {
- (id)init {
if ((self = [super init])) {
self.strokes = [NSMutableArray array];
strokeOrders = [NSMutableArray array];
permutedStrokeOrders = [NSMutableArray array];
unistrokes = [NSMutableArray array];
self.templates = [NSMutableArray array];

strokeOrders = [[NSMutableArray alloc] init];
permutedStrokeOrders = [[NSMutableArray alloc] init];
unistrokes = [[NSMutableArray alloc] init];
}
return self;
}
Expand Down Expand Up @@ -71,8 +73,8 @@ - (void)createTemplates {

// actually create the templates from unistrokes
for (int i = 0; i < [unistrokes count]; i++) {
WTMGlyphTemplate *newTemplate = [[WTMGlyphTemplate alloc] initWithName:self.name
points:[unistrokes objectAtIndex:i]];
WTMGlyphTemplate *newTemplate = [[[WTMGlyphTemplate alloc] initWithName:self.name
points:[unistrokes objectAtIndex:i]] autorelease];
[self.templates addObject:newTemplate];
}
DebugLog(@"Templates %@", self.templates);
Expand All @@ -81,30 +83,28 @@ - (void)createTemplates {

- (void)createTemplatesFromJSONData:(NSData *)jsonData {
NSError *error = nil;
NSArray *arr = [[CJSONDeserializer deserializer] deserializeAsArray:jsonData
error:&error];
NSArray *arr = [[CJSONDeserializer deserializer] deserializeAsArray:jsonData error:&error];
DebugLog(@"json data %@", arr);
int i = 0;
for (NSArray *strokePoints in arr) {
WTMGlyphStroke *stroke = [[WTMGlyphStroke alloc] init];
for (NSArray *pointArray in strokePoints) {
WTMGlyphStroke *stroke = [[[WTMGlyphStroke alloc] init] autorelease];
for (NSArray *pointArray in strokePoints)
[stroke addPoint:CGPointMake([[pointArray objectAtIndex:0] floatValue], [[pointArray objectAtIndex:1] floatValue])];
}
DebugLog(@"Adding stroke to initial strokes %@", [stroke points]);

[self.strokes addObject:stroke];
[strokeOrders addObject:[NSNumber numberWithInt:i]];
i++;
}

DebugLog(@"Strokes %@", self.strokes);
DebugLog(@"Strokes %@", self.strokes);
DebugLog(@"Initial stroke orders %@", strokeOrders);

[self createTemplates];
}

- (void)permuteStrokeOrders:(int)count {
if (count == 1) {
[permutedStrokeOrders addObject:[strokeOrders copy]];
[permutedStrokeOrders addObject: [[strokeOrders copy] autorelease]];
} else {
for (int i = 0; i < count; i++) {
[self permuteStrokeOrders:(count-1)];
Expand Down Expand Up @@ -143,7 +143,7 @@ - (void)createUnistrokes {

int strokeIndex = [[strokeOrder objectAtIndex:i] intValue];
stroke = [self.strokes objectAtIndex:strokeIndex];
copyOfStrokePoints = [NSMutableArray arrayWithArray:[[stroke points] copy]];
copyOfStrokePoints = [NSMutableArray arrayWithArray: [[[stroke points] copy] autorelease]];

if (((b >> i) & 1) == 1) {
points = [[copyOfStrokePoints reverseObjectEnumerator] allObjects];
Expand Down
Empty file modified WTMGlyph/WTMGlyphDefaults.h
100644 → 100755
Empty file.
Empty file modified WTMGlyph/WTMGlyphDefaults.m
100644 → 100755
Empty file.
Empty file modified WTMGlyph/WTMGlyphDelegate.h
100644 → 100755
Empty file.
6 changes: 4 additions & 2 deletions WTMGlyph/WTMGlyphDetector.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#import <Foundation/Foundation.h>
#import "WTMGlyph.h"
#import "WTMGlyphDelegate.h"

#import "WTMDetectionResult.h"

@interface WTMGlyphDetector : NSObject {

Expand Down Expand Up @@ -41,7 +41,9 @@
- (void)addPoint:(CGPoint)point;
- (void)removeAllPoints;
- (void)removeAllGlyphs;
- (void)detectGlyph;

- (WTMDetectionResult*)detectGlyph;

- (NSArray *)resample:(NSArray *)_points;
- (NSArray *)translate:(NSArray *)_points;
- (NSArray *)vectorize:(NSArray *)_points;
Expand Down
76 changes: 48 additions & 28 deletions WTMGlyph/WTMGlyphDetector.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,24 @@ @implementation WTMGlyphDetector

#pragma mark - Lifecycle

+ (id)detector {
WTMGlyphDetector *detector = [[WTMGlyphDetector alloc] init];
+ (id)detector
{
WTMGlyphDetector *detector = [[[WTMGlyphDetector alloc] init] autorelease];
return detector;
}

+ (id)defaultDetector {
WTMGlyphDetector *detector = [[WTMGlyphDetector alloc] initWithDefaultGlyphs];
+ (id)defaultDetector
{
WTMGlyphDetector *detector = [[[WTMGlyphDetector alloc] initWithDefaultGlyphs] autorelease];
return detector;
}

- (id)init {
- (id)init
{
if ((self = [super init])) {
self.points = [[NSMutableArray alloc] init];
self.glyphs = [[NSMutableArray alloc] init];
self.timeoutSeconds = WTMGlyphDefaultTimeoutSeconds;
points = [[NSMutableArray alloc] init];
glyphs = [[NSMutableArray alloc] init];
timeoutSeconds = WTMGlyphDefaultTimeoutSeconds;
lastPointTime = [[NSDate date] timeIntervalSince1970];
}
return self;
Expand All @@ -46,24 +49,28 @@ - (id)initWithGlyphs:(NSArray *)_glyphs {
return self;
}

- (id)initWithDefaultGlyphs {
- (id)initWithDefaultGlyphs
{
[self init];

NSData *jsonData;
NSArray *fileNames = [NSArray arrayWithObjects: @"D", @"T", @"N", @"P", nil];

for (int i = 0; i < fileNames.count; i++) {
NSString *name = [fileNames objectAtIndex:i];
NSAutoreleasePool * p = [[NSAutoreleasePool alloc] init];
jsonData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:@"json"]];
if (jsonData) {
[self addGlyphFromJSON:jsonData name:name];
}
[p release];
}

return self;
}

- (void)dealloc {
- (void)dealloc
{
[points release];
[glyphs release];

Expand All @@ -72,20 +79,24 @@ - (void)dealloc {

#pragma mark - Glyph Templates

- (void)addGlyph:(WTMGlyph *)glyph {
- (void)addGlyph:(WTMGlyph *)glyph
{
if (!self.glyphs)
self.glyphs = [NSMutableArray arrayWithCapacity:1];

[self.glyphs addObject:glyph];
}


- (void)addGlyphFromJSON:(NSData *)jsonData name:(NSString *)name {
- (void)addGlyphFromJSON:(NSData *)jsonData name:(NSString *)name
{
WTMGlyph *t = [[WTMGlyph alloc] initWithName:name JSONData:jsonData];
[self addGlyph:t];
[t release];
}

- (void)removeGlyphByName:(NSString *)name {
- (void)removeGlyphByName:(NSString *)name
{
NSEnumerator *eachGlyph = [self.glyphs objectEnumerator];
WTMGlyph *glyph;

Expand All @@ -96,15 +107,16 @@ - (void)removeGlyphByName:(NSString *)name {
}
}

- (void)removeAllGlyphs {
- (void)removeAllGlyphs
{
[self.glyphs removeAllObjects];
}


#pragma mark - Detection

- (void)addPoint:(CGPoint)point {
//DebugLog(@"Adding point to detector: %@", [NSValue valueWithCGPoint:point]);
DebugLog(@"Adding point to detector: %@", [NSValue valueWithCGPoint:point]);

lastPointTime = [[NSDate date] timeIntervalSince1970];

Expand All @@ -115,22 +127,27 @@ - (void)removeAllPoints {
[self.points removeAllObjects];
}

- (void)detectGlyph {
- (WTMDetectionResult*)detectGlyph {

// Take the captured points and make a Template
// Compare the template against existing templates and find the best match.
// If the best match is within a threshold, consider it a true match.

WTMDetectionResult * d = [[WTMDetectionResult alloc] init];
d.allScores = nil;
d.bestMatch = nil;

if (![self hasEnoughPoints]) {
return;
d.success = NO;
return d;
}

if (self.glyphs.count < 1) {
return;
d.success = NO;
return d;
}

WTMGlyphTemplate *inputTemplate = [[WTMGlyphTemplate alloc] initWithName:@"Input" points:self.points];
WTMGlyph *glyph;
WTMGlyphTemplate *inputTemplate = [[[WTMGlyphTemplate alloc] initWithName:@"Input" points:self.points] autorelease];
WTMGlyph *glyph = nil;
NSEnumerator *eachGlyph = [self.glyphs objectEnumerator];
WTMGlyph *bestMatch;
float highestScore = 0;
Expand All @@ -140,7 +157,7 @@ - (void)detectGlyph {

while ((glyph = (WTMGlyph *)[eachGlyph nextObject])) {
float score = 1 / [glyph recognize:inputTemplate];
DebugLog(@"Glyph: %@ Score: %f", glyph.name, score);
NSLog(@"Glyph: %@ Score: %f", glyph.name, score);
result = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:glyph.name, [NSNumber numberWithFloat:score], nil]
forKeys:[NSArray arrayWithObjects:@"name", @"score", nil]];
[results addObject:result];
Expand All @@ -150,13 +167,16 @@ - (void)detectGlyph {
bestMatch = glyph;
}
}
DebugLog(@"Best Glyph: %@ with a Score of: %f", bestMatch.name, highestScore);
NSLog(@"Best Glyph: %@ with a Score of: %f", bestMatch.name, highestScore);

NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"score" ascending:NO] autorelease];
NSArray *sortedResults = [results sortedArrayUsingDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];

[delegate glyphDetected:bestMatch withScore:highestScore];
[delegate glyphResults:sortedResults];
d.success = YES;
d.allScores = sortedResults;
d.bestMatch = bestMatch;
d.bestScore = highestScore;
return d;
}

- (NSArray *)resample:(NSArray *)_points {
Expand All @@ -178,7 +198,7 @@ - (NSArray *)vectorize:(NSArray *)_points {

- (void)detectIfTimedOut {
if ([self hasTimedOut]) {
DebugLog(@"Running detection");
NSLog(@"Running detection");
[self detectGlyph];
}
}
Expand All @@ -196,9 +216,9 @@ - (BOOL)hasTimedOut {
NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
NSInteger elapsed = now - lastPointTime;

//DebugLog(@"Elapsed time since last point is: %i", elapsed);
DebugLog(@"Elapsed time since last point is: %i", elapsed);
if (elapsed >= self.timeoutSeconds) {
DebugLog(@"Timeout detected");
NSLog(@"Timeout detected");
return YES;
}

Expand Down
Empty file modified WTMGlyph/WTMGlyphStroke.h
100644 → 100755
Empty file.
Empty file modified WTMGlyph/WTMGlyphStroke.m
100644 → 100755
Empty file.
6 changes: 3 additions & 3 deletions WTMGlyph/WTMGlyphTemplate.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
//

#import <Foundation/Foundation.h>

#import "WTMGlyphUtilities.h"

@interface WTMGlyphTemplate : NSObject {
NSString *name;
NSMutableArray *points;
NSMutableArray *normalizedPoints;
CGPoint startUnitVector;
NSMutableArray *vector;
FloatArrayContainer vector;
}

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSMutableArray *points;
@property (nonatomic, retain) NSMutableArray *normalizedPoints;
@property (nonatomic, retain) NSMutableArray *vector;
@property (nonatomic, assign) FloatArrayContainer vector;

- (id)initWithName:(NSString *)_name points:(NSArray *)_points;
- (void)normalize;
Expand Down
Loading

0 comments on commit e3cecce

Please sign in to comment.