vendredi 18 juillet 2014

Concatenate images with OpenCV

Concatenate images with OpenCV

 The PDF file format has several advantages. When generating a PDF file, you have the certainty that it will be displayed the same way on every platform. On print, it's going to be the same everywhere.

Meanwhile, the PDF format isn't easily editable. The choices made by the file viewer can also be counter productive in some specific scenarios (when displaying full paged images from comics for example, the reoslution of the image has nothing to do with the resolution of the PDF and the display, meaning that you can have some pixelization occuring...)
Scientific publications in PDF (or those same comics) embed sometimes infographies, charts and pictures that you may need to reuse.

The pdfimages tool can extract JPEG images embedded inside a PDF file (doing it also for other image file format that we aren't going to use here). You can find a precompiled binary for Win32 there : http://www.foolabs.com/xpdf/download.html. You can choose to keep only the pdfimages.exe file and delete everything else. When it's saving the images, the tool doesn't 'reinterpret' them, which is important for JPEG images : there's no loss of quality when doing a new compression/decompression cycle.

The syntax to extract the files in JPEG is -j :


 pdfimages.exe -j "nom_du_fichier_pdf" 0


To keep the numerotation of the file the same as in the file, youneed to provide a prefix to the saved files. You can use what you want obviously. Here, I use '0'.

OpenCV to the rescue

Some tools split the image when embedding them inside the PDF. You can't see it onscreen but when the images are dumped from the PDF, they are extracting in several pieces.

I coded a little tool with OpenCV that takes all the images of a folder and concatenate them in logical 'pages'. OpenCV is overkill for a work like that, but by using it you can later add some effects (for example) on the images.

To read the folders and files in a multiplatform way (for a future port on Linux, for example), I use a simple header : tinydir.h (by Cong Xu and Baudoin Feildel, from here : https://github.com/cxong/tinydir).

To handle different cases of image splitting, the tool accept as a parameter the number of successive images to reassemble. Forexample, if you want to concatenate the images 5 by 5, here's the commandline :


OpenCVConcat.exe 5


By default, the tool is going to save the pictures sequentially from 000.jpg to 999.jpg (you can edit the code if you need to go over that).

For the moement, the tool works only with JPEG (with the .jpg extension). You need to add the checks for other file formats if you need to concatenate PNG or others.

The code isn't completely clean, but it's providing a good codebase to start with. For exemple, the proper way to handle memory would be to free the temporary images in RAM, handled by the vector. However the tool is fast and is only made to run for a short (it shoudln't stay in memory for too long). The memory segment allocated for the program is going to be properly freed at the end of the execution by the OS.

The code compile with OpenCV 2.4.9 and Visual Studio 2012, but it should works with any OpenCV install above 2.0+ and a fairly recent VS install (something above VS 2005). The linked libraries are declared as #pragma comment(lib,"") at the head of the main cpp file. You need to change those lines to match your installation.(This way of declaring the libraries is helpful when dealing with different version of OpenCV installed concurrently on the system...).

The code is available on GitHub : https://github.com/Pseudopode/OpenCVConcat, with an archive containing the compiled binary. The same archive is available here : https://dl.dropboxusercontent.com/u/1412774/Blog/BlogSpot/OpenCV_Concat/OpenCVConcat.1.0.7z.

Concatenation d'images avec OpenCV

Concatenation d'images avec OpenCV

pdfimages.exe


Le format PDF présente plusieurs avantages : en générant un fichier PDF vous avez la garantie qu'il sera affichée de la même manière sur toutes les plateformes. A l'impression le rendu sera identique partout.

En contrepartie, le format PDF n'est pas fait pour être édité facilement. De plus les choix d'affichages effectués par le lecteur de fichier peuvent se révéler mauvais dans certains cas (notamment lors de l'affichage d'images A4 pleine page dans le cas de bande dessinées ou de comics par exemple).
Les publications scientifiques en PDF (ou ces même comics) embarquent souvent des infographies que vous voudriez peut-être récupérer.

L'outil pdfimages permet d'extraire les images JPG embarquées dans un fichier PDF (ainsi que d'autres formats qui ne nous intéressent pas ici). Pour Win32, vous pouvez trouver l'outil précompilé là : http://www.foolabs.com/xpdf/download.html . Vous pouvez ne garder que pdfimages.exe présent dans l'archive.
Lorsqu'il enregistre les images, l'outil ne les "réinterprète" pas, ce qui est important pour les images JPEG : il n'y a pas de perte de qualité avec une nouvelle compression/décompression.

La syntaxe pour extraire les fichiers au format JPEG est -j :


 pdfimages.exe -j "nom_du_fichier_pdf" 0


Afin de garder la numérotation des images identique à celle du fichier, il faut donner un préfixe au fichiers qui seront sauvegardé. Vous pouvez utiliser ce que vous voulez, évidemment. Ici, j'utilise '0'. 

OpenCV à la rescousse 

Certains outils découpent les images lors de l'intégration des fichiers dans le fichier PDF. Cela ne se voit pas à l'écran lors de la visualisation du PDF, mais lors de la sauvegarde des images elles seront extraites en plusieurs morceaux.

J'ai programmé un petit outil avec OpenCV qui récupère toutes les images d'un dossier et les réassemble en pages logiques. OpenCV est surdimensionné pour une tâche de ce type, mais son utilisation permet d'appliquer d'éventuels traitement ultérieurs sur les images.

 Afin de pouvoir lire facilement les dossiers et les fichiers de manière multiplateforme (en prévision d'un portage éventuel sous Linux, par exemple), j'utilise un simple fichier d'en-tête, tinydir.h (par Cong Xu et Baudouin Feildel, venant d'ici https://github.com/cxong/tinydir).
 Afin de gérer plusieurs cas de découpe d'image, l'outil accepte en paramètre le nombre d'images successives à assembler. Par exemple, si vous désirer réunir les images 5 par 5, voici la ligne de commande :


OpenCVConcat.exe 5


Par défaut, l'outil va sauvegarder les images séquentiellement en partant de 000.jpg, jusqu'à 999.jpg

Pour l'instant, l'outil n'assemble que les fichiers .jpg . Il faut rajouter la vérification pour les autres formats de fichiers si vous voulez assembler des PNG ou autres.

Le code n'est pas complètement propre, mais cela donne une bonne base pour commencer. Par exemple, il faudrait pour la gestion des images temporaires en RAM désallouer proprement les images stockées dans le vecteur. Malgré tout, l'outil tournant rapidement et n'étant pas destiné à tourner en mémoire vive, le segment mémoire associé sera libéré proprement par l'OS à la fin de l'exécution.

Le code compile avec OpenCV 2.4.9 et Visual Studio 2012, mais cela devrait fonctionner avec n'importe quelle installation d'OpenCV en branche 2.0+ et un VS récent (certainement depuis VS2005). Les bibliothèques à lier par le compilateur sont déclarées en #pragma comment(lib,""), il faut changer ces lignes pour qu'elles correspondent à votre installation. (Cette manière de déclarer les librairies permet de changer facilement de version lorsque vous utilisez plusieurs version d'OpenCV en parallèle sur la même machine).

Le code est disponible sur GitHub : https://github.com/Pseudopode/OpenCVConcat, ainsi qu'une archive contenant l'exécutable et ses DLLs. Cette même archive est disponible également ici : https://dl.dropboxusercontent.com/u/1412774/Blog/BlogSpot/OpenCV_Concat/OpenCVConcat.1.0.7z.