Vous voulez effectuer du traitement d’images en C/C++ sans vous casser la tête? C’est possible avec DevIL, une librairie légère et assez simple à manipuler.
La librairie est portable, open source et des tutoriels sommaires sont disponibles.
Elle est compatible avec:
- Windows
- Linux dont:
- Debian (et probablement Ubuntu) dans le dépot sous les noms de libdevil1c2 et libdevil-dev
- Red Hat et tout ce qui a des RPM
- Slackware
Pour les courageux, il est possible de la recompiler, mais des binaires sont déjà fournis.
Il est manifestement possible de s’en servir pour charger des textures avec OpenGL.
Si vous ne voulez pas vous casser la tête avec la librairie, voici des sources perso qui vous permettront de manipuler votre image comme un tableau unidimentionnel:
Voici un exemple de traitement d’image (réhaussement de LSB avec possibilité de filtrer par calque).
fichier lsbManipulator.hpp
#ifndef __LSBMANIPULATOR_HPP #define __LSBMANIPULATOR_HPP #include <IL/il.h> class lsbManipulator { private: // Layer from the lsb to show. static ILuint showLayer; static bool showOneLayer; public: static void setVisibleBitLayer( ILuint nLayer); static void lsbEnhancer( ILubyte* data, ILuint width, ILuint height); }; #endif //__LSBMANIPULATOR_HPP
fichier lsbManipulator.cpp
#include <iostream> #include "lsbManipulator.hpp" // default init list ILuint lsbManipulator::showLayer = 0; bool lsbManipulator::showOneLayer = false; void lsbManipulator::lsbEnhancer(ILubyte* data, ILuint width, ILuint height) { ILuint picLength = width * height * 3; ILubyte oneByte; for( ILuint i=0; i<picLength; ++i) { // Swap endianness of the byte data[i] = ((data[i] * 0x0802LU | 0x22110LU ) | (data[i] * 0x0802LU | 0x88440LU )) * 0x10101LU >> 16; oneByte = data[i]; // If applicable, shift to the n-layer and bitmask if( lsbManipulator::showOneLayer) data[i] = (oneByte << lsbManipulator::showLayer) & 0x80LU; } } void lsbManipulator::setVisibleBitLayer(ILuint nLayer) { lsbManipulator::showOneLayer = true; lsbManipulator::showLayer = nLayer; }
Ici, vous trouverez tout le code qui va permettre d’ouvrir l’image, de lancer traitement, et de sauver le résultat. La fonction n’est pas encore thread safe, je vous tiendrai au courant quand ça sera le cas, (avec une classe, ça sera vite réglé 😉 ).
fichier pictureProcessor.h
#ifndef __PICTUREPROCESSOR_H #define __PICTUREPROCESSOR_H #include <string> #include <IL/il.h> /** * ilProcessor -- Image stream processor function * Functions of this type can process pictures as provided by the OpenIL layer. * * @author Geoffroy GRAMAIZE */ typedef void (*ilProcessor)( ILubyte*, ILuint, ILuint); /** * processPicture() -- Process an image using an ilProcessor and OpenIL. * This is a wrapper function for easy OpenIL handling. * * @author Geoffroy GRAMAIZE * * @param inFileName The input picture file path. * @param outFileName The output picture file path. * @param ilProcessingAlg ilProcessor used to process the input picture. */ void processPicture( const std::string& inFileName, const std::string& outFileName, ilProcessor ilProcessingAlg); #endif //__PICTUREPROCESSOR_H
fichier pictureProcessor.cpp
#include <iostream> #include <IL/il.h> #include <IL/ilu.h> #include <stdlib.h> #include <string.h> #include "pictureProcessor.h" void processPicture( const std::string& inFileName,const std::string& outFileName, ilProcessor ilProcessingAlg) { ilInit(); ILuint imageName; ilGenImages(1, &imageName); ilBindImage(imageName); if( !ilLoadImage(inFileName.c_str()) ) { std::cerr << "Couldn't load '" << inFileName << "' , aborting..." << std::endl; } ILuint width = ilGetInteger(IL_IMAGE_WIDTH); ILuint height = ilGetInteger(IL_IMAGE_HEIGHT); std::clog << "Loaded '" << inFileName << "' (wid: " << width << "px, hei: " << height << "px)." << std::endl; ILuint tailleUniDim = width*height*3; // grab the original picture, and create a temporary memory array ILubyte *dataImg = ilGetData(), *dataTemp = new ILubyte[ tailleUniDim ]; // copy the picture into the work array memcpy (dataTemp, dataImg, tailleUniDim); // call the picture processor ilProcessingAlg( dataTemp, width, height); // restore the work array memcpy (dataImg, dataTemp, tailleUniDim); // Write the picture in output file ilEnable(IL_FILE_OVERWRITE); if( ! ilSaveImage( outFileName.c_str()) ) { std::cerr << "Couldn't save work in '" << inFileName << "' , aborting..." << std::endl; } ilShutDown(); }
Pour vous mettre sur la voie, voiçi un exemple d’utilisation du tout 😉
fichier argParser.hpp
#ifndef __ARGPARSER_HPP #define __ARGPARSER_HPP #include <iostream> struct SAppParams { bool renderOneLayer; unsigned int layerToRender; std::string inFile; std::string outFile; static void init(SAppParams& p) { p.renderOneLayer=false; p.layerToRender=0; p.inFile = std::string(""); p.outFile = std::string(""); } }; bool processArgs( SAppParams& params, int argc, char** argv); #endif //__ARGPARSER_HPP
fichier argParser.cpp
#include <string.h> #include <stdlib.h> #include "argParser.hpp" bool processArgs( SAppParams& params, int argc, char** argv) { if( argc<2) return false; for( int i=1; i<argc; ++i) { if( strncmp( argv[i], "-l", 2) == 0 ) { // Show one layer if( i>= argc) break; params.layerToRender = atoi(argv[++i]); params.renderOneLayer = true; } else if( strncmp( argv[i], "-o", 2) == 0 ) { // Set the output File if( i>= argc) break; params.outFile = std::string( argv[i+1]); } else { // Set the input file params.inFile = std::string( argv[i]); } } return true; }
fichier main.cpp
#include <iostream> #include <string> #include <IL/il.h> #include <stdlib.h> #include <string.h> #include "pictureProcessor.h" #include "lsbManipulator.hpp" #include "argParser.hpp" void welcomeBanner(void) { std::cout << std::endl << "Geoffroy Gramaize's image tickler - (c) 2011" << std::endl << "--------------------------------------------" << std::endl << std::endl; } void usage(char **argv) { std::cout << "Usage: "<< argv[0] <<" args inputFile" << std::endl << std::endl << "Arguments\tMeaning"<< std::endl << "-l <0-7> \tShow only the N-layer starting from LSB" << std::endl << "-o <file>\tSpecifies in which file the result will be stored." << std::endl << std::endl; } int main(int argc, char **argv) { SAppParams appParams; SAppParams::init(appParams); if( !processArgs( appParams, argc, argv) || appParams.inFile.compare("") == 0 || appParams.outFile.compare("") == 0 ) { usage(argv); return 1; } welcomeBanner(); if( appParams.renderOneLayer==true && appParams.layerToRender >= 0 && appParams.layerToRender <8) { std::clog << "Will render layer " << appParams.layerToRender << " from LSB." << std::endl; lsbManipulator::setVisibleBitLayer( appParams.layerToRender); } processPicture( appParams.inFile, appParams.outFile, &(lsbManipulator::lsbEnhancer) ); return 0; }
Bonne chance et amusez-vous bien.