Introducing Facerecognition Resetter Plugin for the Nokia N9

As my mate Simón was writing short time ago in his post Announcing the Gallery Tilt Shift plugin for the Nokia N9, we got published at Igalia some plugins for enhancing the experience of the built-in Gallery application in the N9/N950 through the Nokia Store: Enlarge & Shrink Plugin, Gallery Tilt Shift Plugin, and Facerecognition Resetter Plugin.

The Enlarge & Shrink Plugin is a filter developed by Antía Puentes for the built-in Gallery application which applies a radial distortion to a picture featuring an enlarge or shrink effect (also known as punch or pinch).

The Gallery Tilt Shift Plugin is a filter developed by Simón Pena for the built-in Gallery application which makes a picture look like a miniature.

Finally, Facerecognition Resetter Plugin was developed by me. It is a add-on for the built-in Gallery application which is not a real filter for the pictures. Instead, it is just a way of forcing the deletion or un/protection of the face recognition database through its usage from Gallery. The main reason for doing this is a well known bug in the face recognition feature.

If you are experiencing that the the N9 is not recognizing faces any more or it is not giving any more suggestions just install Facerecognition Resetter Plugin and click on the “Protect” button. You want to do this even if you are not suffering this problem since this will prevent it from appearing in the future.

BTW, comments and reviews in the Nokia Store will be welcomed 😀

But, specifically, why would we want to reset or un/protect the face recognition database? Or, actually, what the heck is that face recognition database? Let’s get to the beginning.

When Nokia released the PR1.2 update for the Harmattan platform they included a new feature which made the N9 to be the first smartphone with integrated automated face recognition.

This feature, when activated, let the Gallery or Camera application to automatically recognize faces on the pictures stored in the device, showing a white bubble with a question mark on top of the region detected as a face.

Clicking on such bubble you would be able to select one of your contacts to be assigned as the detected face.

The algorithm would be even learning as the user selected and assigned faces to contacts so at some point it would be also suggesting the proper contact for the detected faces. The user, then, would only have to double tap on the suggestion bubble to confirm such contact.

Everything seemed great but after a while, some users started to complain that this feature eventually stopped working. Either it was not suggesting anyone, when there were people tagged in a big number of pictures or it was just not recognizing faces any more.

As with any software, the face recognition feature contains bugs and this problem was the consequence of one that Nokia has not yet fixed to the current date.

The technical explanation is that the algorithm that performs the face detection relies in SQLite to store its learning parameters and contacts. This database is located at:

This file and its directory are protected through the usage of the AEGIS “powered” gallerycoredata-user user and gallerycoredata-users group. Also, the file permissions mask for them are 070 in the case of the directory and 060 in the case of the file.

When doing transactions to the database file the SQLite driver may create some temporal files as the journal one, to be able to recover the database under disaster. This journal file gets the UID and GID of the running process and the permissions from a combination of the permissions of the original database file and the running process’ umask. As a consequence, the journal file usually has the permissions mask 040.

While using the Camera or Gallery application the SQLite file is open. Whether a disaster may happen, although we hold the journal file, the owner of that file is not able to read it. Hence, the SQLite database remains useless for the processes with the same UID than the owner of the journal file, even when they belong to the same group than that file.

What it happen afterwards is that the SQLite database remained waiting to be “recovered” using the journal file but as the journal could not be read, the face recognition algorithm could not provide the learned information and suggest contacts any more. The solution for this would have been as easy as to change the file permissions of the journal file but this is not even possible for the root user since only the gallerycore-user user and those belonging to the gallerycore-users group were allowed through AEGIS to read and change the files on the parent directory of the database file.

Hence, the only way of being able to do a hack that would solve this problem was that the actual application doing such changes would be either Gallery or Camera. Fortunately, Gallery had the possibility of being extended through plugins and that’s the reason why Facerecognition Resetter is such.

Following, you can watch a video featuring an usage introduction tutorial and a detailed explanation of its usage below it.

The plugin shows 3 buttons for its corresponding actions:

  • Reset the database: As simple as that. It will delete the directory and files containing all the information gathered through the face recognition algorithm. From that on, the face recognition feature will start to work again but the learning gotten previously and powering the suggestions will be lost.
  • Protect the database: This will correct the permissions of the directories and files containing all the information gathered through the face recognition algorithm. From that on, the face recognition feature will start to work again and the suggestions would have the learning gotten previously. The problem will not show up in the future ever again but the database will remain protected and only usable through Gallery and Camera (or any other application with the proper AEGIS tokens).
  • Unprotect the database: This will correct the permissions of the directories and files containing all the information gathered through the face recognition algorithm. From that on, the face recognition feature will start to work again and the suggestions would have the learning gotten previously. The problem will not show up in the future ever again and the database will be available to any other application that would like to make use of it.

The permissions get corrected when un/protecting since the plugin sets the SGID bit to the parent directory of the database file so any other files created under it will belong to the same group than the directory and not to the GID of the running process that created that file. Also, the database will have now the 660 mask so any temporal file created by the SQLite drive will attempt to keep the same mask.

And with this, we can keep enjoying the usage of the face recognition feature of the N9 and go to celebrate it with some beers!!! 😀

This and the other plugins are Open Source, so you can go to their page at GitHub: Enlarge & Shrink, Gallery Tilt Shift and Facerecognition Resetter

Also, don’t forget to take a look at all the applications published by Igalia at the Nokia Store

Download Facerecognition Resetter Plugin from Nokia Store

Attending the Automotive Linux Summit 2012

Next Wednesday I will be attending the Automotive Linux Summit 2012.

It will be a good time to meet the key people pushing the usage of Linux in the automotive arena and I hope to have a great time at the Heritage Motor Centre in Warwickshire.

If you happen to attend the event and want to have a good chat with an Igalian about any of the technologies in which we are strongly involved: WebKit, rendering, compilers, Grilo, GStreamer, the kernel, Qemu, Yocto, OSTree, Skeltrack, OpenCV, a11y, Qt, Gtk+ and so on. Just poke me whenever you see me around 😉

QUrl (mis)usage: appendix, avoid automatic cast from QString

As I was introducing in the former entry QUrl (mis)usage, the direct creation of a QUrl from a QString should be avoided in any software that is not trying to smartly guess what a user input should lead to.

So, going directly to the ham, to avoid mistakes due to automatic conversions from QString to QUrl, I encourage the usage of the QT_NO_URL_CAST_FROM_STRING macro. The only thing you have to do is adding a line to your qmake project file like this:

# Avoid automatic casts from QString to QUrl. Dangerous!!!
DEFINES += QT_NO_URL_CAST_FROM_STRING

Or add it directly to the compilation line, like this

g++ ... -DQT_NO_URL_CAST_FROM_STRING ...

As I was pointing in my previous post, the usage of QUrl::fromLocalFile(QString) and QUrl::fromEncoded(QByteArray, QUrl::StrictMode) is recommended when dealing with QString and QUrl, but committing mistakes is a human condition so it is pretty easy to end passing a QString as a parameter to some API expecting a QUrl, or assigning a QString to a QUrl with the “=” operator through the C++ automatic cast mechanism which is implemented in the QUrl class. That’s why forbidding these automatic casts in our code is of such importantance.

QUrl (mis)usage

Lately, I’ve been developing some software which makes an intensive usage of QUrls as resource locators for local files. Nothing wrong here. QUrl is a powerful way of sharing the locations of those in an universal way. The problem is when you construct those QUrls from QStrings and you actually forget that QUrls are meant for much more than representing local file locations.

Authority chunks on an URL

Authority chunks on an URL

At the moment of writing this, QUrl documentation, although quite complete, could be much more explanatory. For example, it says that the recommended way for creating a QUrl from a QString is:


* When creating an URL QString from a QByteArray or a char*,
always use QString::fromUtf8().
* Favor the use of QUrl::fromEncoded() and QUrl::toEncoded()
instead of QUrl(string) and QUrl::toString() when converting
QUrl to/from string.

But this is explained in the documentation for QUrl::fromUserInput(), instead of in the Detailed Description [ 1 ].

What is important from this explanation is that it is not a matter of favor the use of QUrl::from/toEncoded() over QUrl::(from)toString() but, I would say, a must if you don’t want to end up with bogus corner cases.

Why would this happen? Well, as I was saying, QUrl is meant for much more than universally representing the location of a file so, here go the big tips:

  1. If you want to get the QUrl from a local file represented with a QString, use always QUrl::fromLocalFile ( const QString & localFile ) . Don’t use QUrl::QUrl ( const QString & url ) if you don’t want to end up with some problems. In the same way, get the path to the local file always with QUrl::toLocalFile().
  2. If you want to get a QUrl from a QString representing an URL, be sure that the QString is actually representing a percent encoded URL, as it should to be a valid URL, and always use QUrl::fromEncoded ( const QByteArray & input, ParsingMode parsingMode ), with QUrl::StrictMode as the QUrl::ParsingMode.
  3. If you want to get a QString representation of an URL from a QUrl use always QUrl::toEncoded ().

Bogus examples for each case:

Local file

/mypath/my#file.jpg

Correct:

QUrl myUrl = QUrl::fromLocalFile("/mypath/my#file.jpg")

Incorrect:

QUrl myUrl = QUrl("file:///mypath/my#file.jpg")

The problem here is the way QUrl will treat the “#” character in the second example. It will think, as it actually doesn’t have a way of guessing, that the character is delimiting the fragment part of the URL.

Fragment part on an URL

Fragment part on an URL

As a result, calling to:

myUrl.toLocalFile()

in the first case will result to:

/mypath/my#file.jpg

while in the second will be:

/mypath/my

Parsing mode

/mypath/my#file.jpg

(encoded) url representation:

file:///mypath/my%23file.jpg

Correct:

QUrl myUrl = QUrl::fromEncoded("file:///mypath/my%23file.jpg", QUrl::StrictMode)

Incorrect:

QUrl myUrl = QUrl::fromEncoded("file:///mypath/my%23file.jpg")

The problem here is the way QUrl will treat the “%23” encoding in the second example. Although it is not explicitly explained in the documentation [ 2 ], QUrl will use QUrl::TolerantMode as ParsingMode by default. Therefore, it will think that the input comes from an ignorant user which was actually trying to pass “file:///mypath/my#file.jpg”. Again, it will understand after converting back “%23” to “#”, that the character is delimiting the fragment part of the URL.

As a result, calling to:

myUrl.toLocalFile()

in the first case will result to:

/mypath/my#file.jpg

while in the second will be:

/mypath/my

Encoded usage

/mypath/my#file.jpg

(encoded) url representation:

file:///mypath/my%23file.jpg

(unencoded and wrong) url representation:

file:///mypath/my#file.jpg

Correct:

QUrl myUrl = QUrl::fromEncoded("file:///mypath/my%23file.jpg", QUrl::StrictMode)

Incorrect:

QUrl myUrl = QUrl("file:///mypath/my#file.jpg")

Here, we have another incarnation of the very same problem than the two examples above. QUrl will think, again, as it actually doesn’t have a way of guessing, that the character is delimiting the fragment part of the URL.

As a result, calling to:

myUrl.toLocalFile()

in the first case will result to:

/mypath/my#file.jpg

while in the second will be:

/mypath/my

Corollary:

The default behavior of QUrl is to provide an easy handling of URLs to the user of our programs, the end user, but not the user of QUrl, the developers. I find this quite awkward but, still, it is a decision of Qt people and, as developers, we only have to take this into account when writing our code.

These bogus URLs, which are to be corrected with the usage of the QUrl::TolerantMode ParsingMode, usually come from a text entry box “à là” browser location bar, but this use case is, actually, not so common when talking from the developer’s point of view. When dealing with URLs in our code we have to take into account what an URL is and how it should be formatted/encoded to be valid. Therefore, if I’m receiving a wrongly encoded URL I should go to the source code providing this URL and fix the problem there rather than trying to smartly guess which should be the proper URL. For example, in my software currently in development we use Tracker and I rely on it to feed my code with properly formatted URLs. If for some reason Tracker gives me a wrongly encoded one, the place for solving it is, actually, Tracker, and not my software. I should not and must not interpret what Tracker may have wanted to pass me, but open a bug in its bugzilla and provide as accurate information as I can to help them solve this issue.

Just so my friend Iván Frade doesn’t kill me, make notice that Tracker is, so far, perfectly dealing with URLs 🙂