Affichage des articles dont le libellé est opencv. Afficher tous les articles
Affichage des articles dont le libellé est opencv. Afficher tous les articles

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.

dimanche 11 novembre 2012

Pseudocouleurs avec OpenCV

La Lune en niveaux de gris (photo)

Les fausses couleurs, ou pseudo-couleurs, sont utilisées pour rajouter une gamme de couleurs à une image en niveaux de gris.
La Lune en pseudo-couleurs, colorisée avec OpenCV

Le processus est différent d'une recolorisation, où vous essayez de retrouver les couleurs les plus plausibles sur une vieille pellicule cinéma ou un cliché, pris lorsque seuls les systèmes noirs et blancs étaient disponibles facilement. La recolorisation est une étape mathématique complexe, alors que la pseudocolorisation est très simple : vous mettez en correspondance chaque intensité spécifique de chaque pixel de l'image d'origine avec un triplet de valeurs RGB provenant d'une échelle de couleurs fournie au préalable.

La technique est largement utilisée en photographie aérienne, en imagerie thermique et dans d'autres domaines. L'adjonction d'un nouveau canal d'information par l'utilisation de la couleur peut apporter une nouvelle lecture de l'information.

Différentes techniques sont possibles pour le choix du triplet des valeurs RGB.

Dans la suite de l'article, les exemples de code sont plus spécifiquement liés à l'utilisation d'OpenCV.
Ici, l'auteur utilise 3 sinusoides pour récupérer trois valeurs d'intensité différentes, une pour chaque canal. C'est rapide, mais ce n'est pas toujours facile de savoir à quelle couleur correspond telle ou telle intensité de blanc.

Je propose ici une mise en correspondance directe de la valeur d'intensité du pixel en niveau de gris à une couleur spécifique, choisie dans une table des couleurs. Cette table de couleurs est fournie en tant qu'image additionnelle.
L'intensité de blanc est dans l'espace [0..255] (image 8 bits), et la couleur est représentée comme un triplet classique R([0..255]),G([0..255]),B([0..255]).




Explication du processus de recolorisation

Vous pouvez également utiliser les fonctions LUT d'OpenCV pour construire une table de lookup, mais je voulais essayer quelque chose de plus "manuel".

L'idée est très simple : vous tracez un gradient de couleur sur une image de 255 pixels de haut, et d'un pixel de large, qui sera notre colormap.


Sur l'image en niveaux de gris, vous prenez la valeur de chaque pixel, et vous regardez dans la colormap à la coordonnée (0,valeur_d_intensité). (En fait, vous devez faire l'opération trois fois, une pour chaque canal R,G et B).
Les 3 valeurs stockées à ces coordonnées sont celles du pixel nouvellement coloré !



J'ai élargi un peu l'image de la colormap en largeur, c'est ainsi plus facile de contrôler les couleurs. Seule la première colonne de pixels de l'image est utilisée par le code.




(Dans l'archive fournie comme exemple, la colormap est un fichier JPEG. Pour obtenir les meilleurs résultats, utilisez un format de fichier non-destructif, comme le PNG ou le BMP).

Avec OpenCV, vous pouvez utiliser cvSplit() pour obtenir trois images différentes, une par canal de couleur de l'image originale.




Vous pouvez trouver ici un exemple Visual Studio assez rapide, qui utilise OpenCV, pour coloriser une image en niveaux de gris passée en paramètre sur la ligne de commande, à l'aide d'une colormap. Vous devez également fournir le nom de la colormap. Le programme écrit l'image couleur résultant dans une image bitmap.

Sur l'exemple du babouin, vous pouvez vous rendre compte que les gris de l'image originale sont concentrés autour d'une couleur moyenne (proche de 128). Il n'y a pas beaucoup de gris très foncés ou très clairs dans l'image, l'image finale est donc principalement jaune, la couleur moyenne de la colormap. Pour obtenir de meilleurs résultats, vous pouvez effectuer quelques manipulation sur l'image d'origine (comme une équalisation de l'histogramme, pour couvrir de manière plus uniforme les couleurs du noir vers le blanc).


Voici un lien vers l'archive contenant le code, vous pouvez également parcourir le code sur GitHub.

J'ai utilisé la syntaxe C d'OpenCV. L'exemple se compile avec Visual Studio 2005 et plus récent (normalement).

(A propos, l'image de la Lune est dans le domain public, l'image du babouin provient du répertoire d'OpenCV).

OpenCV Pseudocolors

Grayscale Moon

False colors, or pseudocolors, is the method you use when you want to augment grayscale pictures with predetermined colors. 

Pseudocolored Moon with OpenCV

It is very different from recolorization, where you try to retrieve the plausible true colors of an old picture or movie, shot when only black & white recording systems where widely available. Recolorization is somewhat mathematically tricky, whereas pseudocoloring is very straightforward : you map every specific pixel intensity (the "whiteness" value of the pixel) of the original image to the triplet of RGB values from a given color scale.
It is widely used in aerial photography, in thermal imagery and other field where you can provide that new channel of information to literally shed a new light on the data (pun intended...).

You can use different technique to choose the triplet of RGB values.

From now, I'm going to give some code more specifically linked to OpenCV.
Here, for example, you can see the use of sine functions to retrieve three different values for each channel. It's quick, but it's not always easy to know which white intensity is going to match which color.

What I'm providing here is a straight mapping from pixel value in the grayscale range to a specific color, chosen from a color table. That color table is provided as an image.
The white intensity value is in the range 0 to 255 (8 bit depth image) and the color is represented as a classic R([0..255]),G([0..255]),B([0..255]) triplet.

Recolorization process explanation


You can use LUT functions in OpenCV to construct LookUp Tables, but I wanted to try something more handcrafted.

The idea is really simple : you draw a color gradient on an image of 255 pixels height, and with a width of 1 pixel, which is going to be your colormap

Colormap used by OpenCV

From the grayscale image, you take the value of each and every pixel, and you search in the colormap at the coordinates (0,intensity_value) (in fact, you must do that three times, one per color channel R,G and B).
The 3 values stored at those coordinates are your new colored pixel value !

I stretched a bit the width of the colormap, it's easier to visually check the colors, but only the first column of the image is really used by the code.
Grayscale Baboon
(In the provided example archive, the colormap is a JPEG file. For the best result, you need to use a non-destructive file format, like PNG or BMP).

In OpenCV, you use cvSplit() to get three different images as color channel from the original.

I provide a quick Visual Studio example, using OpenCV, to color a grayscale picture given on the command line to a new color mapped picture. You must also provide the name of the colormap. The program writes the produced colored image as a bitmap.
Pseudocolored Baboon

On the baboon example, you can see that since the grays in the original image are centered around a midpoint (close to 128). There isn't a lot of very dark or very bright gray in the image, so the resulting picture is mostly yellow, the middle color of the color map. It can be interesting to do some small image enhancement on the original before using the recoloring (something like Histogram Stretching, to cover more evenly the range from black to white).

Here's a link to the code archive, you can also browse the code on GitHub.
I used OpenCV's C syntax. The example can be compiled from Visual Studio 2005, and should work with more recent builds.

(And by the way, the moon picture is public domain, the baboon picture is coming from the OpenCV install directory).