
This semester I am taking a course at University called Multi-Agent Semantic Web Systems and as part of the assignment for it I had to take a publicly available dataset and convert it into RDF Turtle format. I chose the Scottish Election Results 1997 – 2009 dataset (available through EDINA here) because I have a keen interest in politics and it seemed like it might be useful for researchers to have. Therefore, for the benefit of my lecturer (so I can get marked) and for anyone else that’s interested the full dataset is available as a zip file: Scottish Election Results 1997-2009 in RDF Turtle format.zip.
All-IP Convergence in the Telecommunications Industry
So far I’ve got straight A’s for my university assignments this semester. One of the more interesting things I had to do was research All-IP convergence in the telecommunications industry for my Computer Networking course. Essentially, communications companies are moving from a vertical model to a horizontal one, where the data for your tv, internet, mobile and fixed phone lines will all be coming over IP packets in the future as opposed to the myriad of technologies employed at the moment. I suppose the point in the exercise was get us to read through all the various RFC documents on the protocols involved and thereby introduce us to more cutting-edge computer science problems. Anyway I thought I’d upload my report in case anyone’s interested.
Image Labelling Program
A month or two ago I worked with Behzad Tabibian (another Edinburgh undergraduate) on an assignment for our Human-Computer Interaction course. The purpose of the assignment was to create a program that could be used by researchers to annotate large sets of images at a time. The report and accompanying program got us full marks so I thought I’d upload it here.
School Yearbook
It’s almost painful to look at now, not least because it’s the perfect example of everything that was wrong with early web design, but I created a site for my high school yearbook back in the day, just came across it, and thought I’d upload it. It’s quite funny to look back at, seems like another lifetime ago now though.
Citigroup Prize Winner
I’ve been working hard at Uni so haven’t had the time to post this until now, but I was part of the team who won the 2010/2011 Citigroup Prize for the best third-year System Design group project.
In the System Design project course, which is compulsory for most Edinburgh University Informatics students, the class is split into teams of around 10 people. Each team is given a Lego Mindstorms kit and instructed to create a robot that can compete against the other teams in a football tournament inspired by the RoboCup. In my year there were twelve teams in total and it was a great experience and a lot of fun.
In the process of creating our system we all learned a great deal, worked extremely hard, and each person brought in there own skills and abilities to complement each other. I’d just like to say a big thanks to my other team members and look forward to working with any of you again in the future.
Steve Jobs (1955 – 2011)
The first thing I do every morning when I wake up is roll over, grab my phone, begin checking emails/rss etc, and it was in that context that I found out about Steve Jobs passing away. I think I’ll always remember that morning; I obviously never met the man, and there are a lot of stories about the more negative aspects of his personality, but I genuinely felt sadness at the news – the world had lost another true genius.
It’s very hard not to be hyperbolic about what Steve Jobs did for the technology sector. He was a very charismatic and intelligent person, anyone in doubt should check out his Stanford Commencement address on youtube. I debated with myself about posting this since a lot of people have already said it better than I ever could, but I felt I needed to mark this event in history since he was one of my personal heros and is simply irreplaceable.
This tribute probably puts it best.
Extracting face data from iPhoto
One of my pet projects over the summer was to scan and categorise my family album, which consists of about 4.5 thousand photos stretching back around 80 years. Having digitised them all I decided to use iPhoto to organise them: the face detection feature was very useful for this purpose. However, having put everything into iPhoto I became a little concerned about how I would get it back out again (in a useful matter) should I need to. After searching around the internet for a bit I couldn’t find any software that would do what I really wanted so I decided to make my own. Below is an excerpt from my app delegate (if you know cocoa it’ll make sense) in case anyone else wants to extract their iPhoto faces data and photos cleanly from their library.
My intention is to copy the folder structure created using this code to my website, convert the sqlite data to mysql, knock up some quick php, and thereby create an interface to my iPhoto library online. It’s unfortunate that Apple has removed the Gallery from iCloud, previously MobileMe, since this would have saved me a lot of hassle and is far more elegant.
Anyway, if it helps anyone here’s some quick code:-
// iPhotoToWebAppDelegate.m
// Created by William Ogilvie on 31/08/2011.
#import <sqlite3.h>
#import "iPhotoToWebAppDelegate.h"
@implementation iPhotoToWebAppDelegate
@synthesize progressIndicator;
@synthesize progressText;
@synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
[progressIndicator startAnimation:self];
[NSThread detachNewThreadSelector:@selector(processLibrary) toTarget:self withObject:nil];
}
- (void)processLibrary {
// create an autorelease pool for this thread
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// get the paths we're going to use
NSString *dbPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/iPhoto.db"];
NSString *iPData = [NSHomeDirectory() stringByAppendingPathComponent:@"Pictures/iPhoto Library/ALbumData.xml"];
// create the database and tables
sqlite3 *dbHandler;
sqlite3_open([dbPath UTF8String], &dbHandler);
sqlite3_exec(dbHandler, "CREATE TABLE events (eventId INTEGER, imageId INTEGER, name TEXT, PRIMARY KEY (eventId, imageId), FOREIGN KEY (imageId) REFERENCES images (imageId) ON DELETE CASCADE)", NULL, NULL, NULL);
sqlite3_exec(dbHandler, "CREATE TABLE faces (faceId INTEGER, name TEXT, PRIMARY KEY (faceId))", NULL, NULL, NULL);
sqlite3_exec(dbHandler, "CREATE TABLE facesInImages (imageId INTEGER, faceId INTEGER, x1 REAL, y1 REAL, x2 REAL, y2 REAL, PRIMARY KEY (imageId, faceId), FOREIGN KEY (imageId) REFERENCES images ON DELETE CASCADE, FOREIGN KEY (faceId) REFERENCES faces ON DELETE CASCADE)", NULL, NULL, NULL);
sqlite3_exec(dbHandler, "CREATE TABLE images (imageId INTEGER, imagePath TEXT, thumbPath TEXT, PRIMARY KEY (imageId))", NULL, NULL, NULL);
// get the plist from the iphoto library
NSDictionary *plistDictionary = [NSDictionary dictionaryWithContentsOfFile:iPData];
// get the list of faces and iterate
NSDictionary *facesDictionary = [plistDictionary objectForKey:@"List of Faces"];
for (NSNumber *key in [facesDictionary allKeys]) {
NSString *name = [[facesDictionary objectForKey:key] objectForKey:@"name"];
NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO faces VALUES (%d, '%@')", [key intValue], name];
sqlite3_exec(dbHandler, [sqlString UTF8String], NULL, NULL, NULL);
}
// get the list of images and iterate
NSDictionary *imagesDictionary = [plistDictionary objectForKey:@"Master Image List"];
for (NSNumber *key in [imagesDictionary allKeys]) {
NSDictionary *image = [imagesDictionary objectForKey:key];
NSString *imagePath = [image objectForKey:@"ImagePath"];
NSString *thumbPath = [image objectForKey:@"ThumbPath"];
NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO images VALUES (%d, '%@', '%@')", [key intValue], imagePath, thumbPath];
sqlite3_exec(dbHandler, [sqlString UTF8String], NULL, NULL, NULL);
// get the list of faces in this image and iterate
NSArray *facesArray = [image objectForKey:@"Faces"];
if (facesArray != nil) {
for (NSDictionary *face in facesArray) {
int faceId = [[face objectForKey:@"face key"] intValue];
NSMutableString *rectangle = [[face objectForKey:@"rectangle"] mutableCopy];
[rectangle replaceOccurrencesOfString:@"{" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [rectangle length])];
[rectangle replaceOccurrencesOfString:@"}" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [rectangle length])];
NSArray *tempArray = [rectangle componentsSeparatedByString:@", "];
[rectangle release];
float x1 = [[tempArray objectAtIndex:0] floatValue];
float y1 = [[tempArray objectAtIndex:1] floatValue];
float x2 = [[tempArray objectAtIndex:2] floatValue];
float y2 = [[tempArray objectAtIndex:3] floatValue];
NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO facesInImages VALUES (%d, %d, %f, %f, %f, %f)", [key intValue], faceId, x1, y1, x2, y2];
sqlite3_exec(dbHandler, [sqlString UTF8String], NULL, NULL, NULL);
}
}
}
// get the list of events and iterate
NSArray *events = [plistDictionary objectForKey:@"List of Rolls"];
for (NSDictionary *event in events) {
int eventId = [[event objectForKey:@"RollID"] intValue];
NSString *name = [event objectForKey:@"RollName"];
// get the list of images in that event and iterate
NSArray *images = [event objectForKey:@"KeyList"];
for (NSNumber *imageId in images) {
NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO events VALUES (%d, %d, '%@')", eventId, [imageId intValue], name];
sqlite3_exec(dbHandler, [sqlString UTF8String], NULL, NULL, NULL);
}
}
// get the number of files we're going to copy
int numberResults;
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare_v2(dbHandler, "SELECT COUNT(*) FROM events AS e, images AS i WHERE e.imageId = i.imageId", -1, &compiledStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
numberResults = sqlite3_column_int(compiledStatement, 0);
}
}
sqlite3_finalize(compiledStatement);
// update the GUI to inform the user we've moved onto the copying phase
[progressText setStringValue:@"Copying Events Folders to Desktop..."];
[progressIndicator setDoubleValue:0.0];
[progressIndicator setMaxValue:(double)numberResults];
[progressIndicator setIndeterminate:NO];
// iterate over the images again but this time with respect to the events
int fileNumber=0;
NSString *eventName = @"";
NSString *lastName = @"";
NSFileManager *fileManager = [NSFileManager defaultManager];
if(sqlite3_prepare_v2(dbHandler, "SELECT e.name, i.imagePath, i.imageId, i.thumbPath FROM events AS e, images AS i WHERE e.imageId = i.imageId ORDER BY e.name ASC", -1, &compiledStatement, NULL) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
lastName = eventName;
int imageId = sqlite3_column_int(compiledStatement, 2);
eventName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSString *imagePath = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *thumbPath = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
if ([lastName isEqualToString:eventName]) {
fileNumber++;
} else {
fileNumber = 1;
}
NSString *directoryPath = [NSString stringWithFormat:@"/Users/William/Desktop/%@", eventName];
if (![fileManager fileExistsAtPath:directoryPath isDirectory:nil]) {
[fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:NO attributes:nil error:nil];
}
NSString *newImagePath = [NSString stringWithFormat:@"%@/%d.%@", directoryPath, fileNumber, [[imagePath pathExtension] lowercaseString]];
NSString *newThumbPath = [NSString stringWithFormat:@"%@/thumb%d.%@", directoryPath, fileNumber, [[thumbPath pathExtension] lowercaseString]];
NSError *error;
[fileManager copyItemAtPath:imagePath toPath:newImagePath error:&error];
if (error != nil) {
NSLog(@"%@", [error description]);
}
[fileManager copyItemAtPath:thumbPath toPath:newThumbPath error:&error];
if (error != nil) {
NSLog(@"%@", [error description]);
}
// update the database for the new paths
NSString *sqlStatement = [NSString stringWithFormat:@"UPDATE images SET imagePath = '%@/%d.%@', thumbPath = '%@/thumb%d.%@' WHERE imageId = %d", eventName, fileNumber, [[imagePath pathExtension] lowercaseString], eventName, fileNumber, [[imagePath pathExtension] lowercaseString], imageId];
sqlite3_exec(dbHandler, [sqlStatement UTF8String], NULL, NULL, NULL);
[progressIndicator incrementBy:1.0];
}
}
sqlite3_finalize(compiledStatement);
// clean up and exit
sqlite3_close(dbHandler);
[pool release];
[NSApp terminate:nil];
}
@end
OS Dev Resource
I love the topic of systems in computer science, I really like the low level stuff. If it was at all practical to do it I’d write all my programs in assembly just because of how close you get to the actual hardware. Unfortunately it’s not, but when I get some free time I do like to dabble with it. Recently I’ve been writing my own boot loader for an OS I want to build. I’m not doing it for any particularly good reason other than I think it’s fun: probably seems quite masochistic but I find it interesting.
Anyway, whilst reading up on the subject I found an excellent source of tutorials for an OS Dev beginner at http://www.brokenthorn.com/Resources/OSDevIndex.html and just thought I’d share.


