This is a progress report after a long time.
Since my last post, my work has involved hours of staring at debug outputs and fixing bugs in libface. I guess I can now say that libface is very usable. Apart from fixing certain segfaults, I also expanded the API a bit.
Till now, you could only give images for detection by passing a filename string to LibFace::detectFaces as:
LibFace libFace = LibFace(DETECT, "."); // Only for Detection vector<Face> result; result = libFace.detectFaces(string(argv[i]));
which is from one of the programs in the examples directory. Not a very good idea to load an image from the filesystem if digiKam already has it in memory.
Fortunately now this has been overloaded with :
result = libFace.detectFaces(img->imageData,img->width, img->height, img->widthStep, img->depth, img->nChannels);
Where img is of type IplImage, the OpenCV native image type. This is useful because now digiKam et al won’t have to use IplImage, as the new way is API-agnostic.
Another thing which I modified, does not change the interface, but which is very useful nevertheless, is the management of face ID’s.Every ID has a one-to-one correspondence with a person.
This is how a libface database can be updated:
1. Updating with new faces, whose ID’s are specified by digiKam. These are people whose faces have never been added to the DB before, but digiKam wants to decide the ID’s for them.
2. Updating with faces that have been given no ID’s. These are totally new people. The Face objects whose ID’s have not been specified will automatically be given the next available ID.
3. Updating with faces that already have matching ID’s in the DB. These are people whose faces have already been added to the DB before. In this case, the new and old face images are averaged and the result is treated as that ID’s face. This way, every person has only one single face image stored for him/her in the libface database.
This was quite complicated to code, because we store the Face images sequentially in a chronological order in the DB.
What I had to do was link the storage index of a face image with it’s ID using one std::map, and then use another map to link each ID to the number of times that ID’s face has been averaged. It’s complicated to explain, you’ll need to look at the code.
This is stored at the end of the DB in this way :
<indexIdMap_0>0</indexIdMap_0> <indexIdMap_1>1</indexIdMap_1> <indexIdMap_2>2</indexIdMap_2> <indexIdMap_3>3</indexIdMap_3> <indexIdMap_4>4</indexIdMap_4> <indexIdMap_5>5</indexIdMap_5> <indexIdMap_6>6</indexIdMap_6> <indexIdMap_7>7</indexIdMap_7> <indexIdMap_8>8</indexIdMap_8> <indexIdMap_9>9</indexIdMap_9> <indexIdMap_10>10</indexIdMap_10> <idCountMap_0>5</idCountMap_0> <idCountMap_1>3</idCountMap_1> <idCountMap_2>2</idCountMap_2> <idCountMap_3>5</idCountMap_3> <idCountMap_4>1</idCountMap_4> <idCountMap_5>2</idCountMap_5> <idCountMap_6>3</idCountMap_6> <idCountMap_7>1</idCountMap_7> <idCountMap_8>10</idCountMap_8> <idCountMap_9>1</idCountMap_9> <idCountMap_10>1</idCountMap_10>
Looking near the end, you can see that the person with ID 8 has 10 occurences.
Also, the recognise function now also returns the “accuracy” of each recognition. This would very helpful if digiKam wants to present “suggestions” for tagging.
What I’m working on right now is a new KDE-friendly wrapper for libface, named “libkface”, which presents a Qt-only interface to client apps, so that digiKam, Krita, Gwenview, KPhotoAlbum etc can use it very easily if they wish.
Oh, and as much as I want to, I’ll not be coming to Akademy this year because my passport issual has been delayed.
Before ending this post, here’s the obligatory screenshot: