Обработка изображений в С++

Блоговая публикация пользователя: Alexei16 Эта публикация была перенесена из личного блога пользователя в общие разделы уровок сайта.

Основа для программирования графических фильтров в С++

При программировании этой основы используется библиотека DevIL, о которой подробно рассказываетcя в этой статье.

Создайте у себя в проекте следующие файлы:
  1. Image.h - header file;
  2. Image.cpp - cpp code file;
В файле Image.h будут храниться описания функций, а в файле Image.cpp - реализации функций.

В названиях функций и констант вы встретите приставку "ag", вместо неё вы можете поставить любую другую. Это сделано для того чтобы не было дубликатов функций или констант в разных API.

Файл Image.h

Код:
/*http://esate.ru, Alexei16*/

#pragma once

#include <windows.h>
#include <il.h>                   //|
                                  // Подключаем DevIL
#pragma comment(lib, "DevIL.lib") //|


enum Pixelformat
{
   AG_BGR,  //Формат пикселей B|G|R
        AG_BGRA, //Формат пикселей B|G|R|A
        AG_RGB,  //Формат пикселей R|G|B
        AG_RGBA  //Формат пикселей R|G|B|A
};

enum ImageType
{
   AG_BMP = 0x0420,  //!< Microsoft Windows Bitmap - .bmp extension
   AG_JPG = 0x0425,  //!< JPEG - .jpg, .jpe and .jpeg extensions
   AG_PNG = 0x042A,  //!< Portable Network Graphics - .png extension
   AG_TGA = 0x042D,  //!< TrueVision Targa File - .tga, .vda, .icb and .vst extensions
   AG_TIF = 0x042E,  //!< Tagged Image File Format - .tif and .tiff extensions
   AG_JP2 = 0x0441   //!< Jpeg 2000 - .jp2 extension
};

typedef struct BaseIMGInfo
{
   int Depth;   //Глубина изобаржения(нужно только для 3D текстур), по умолчанию = 1
   int Format;  //Формат пикселей
   int Type;    //Тип данных в памяти, в основном = IL_UNSIGNED_BYTE
};

typedef struct ImageData
{
   unsigned char * Data; //Указатель на данные изобржения

   int Width;            //Ширина изображения
   int Height;           //Высота изображения
   int Bpp;              //Количество байт на пиксель
   int Stride;           //Количество байт в одной строке пикселей

   Pixelformat PixFormat;//Формат пикселей
   BaseIMGInfo BaseInfo; //Основные параметры изображения, нужные для сохранения изображений в DevIL

   int R_idx;            //Позиция красного в пикселе
   int G_idx;            //Позиция зелёного в пикселе
   int B_idx;            //Позиция синего в пикселе
   int A_idx;            //Позиция альфа-канала в пикселе, только для AG_RGBA или AG_BGRA
};

ImageData * agLoadImage(char * FileName); //Функция для загрузки изображения
bool agSaveImage(ImageData * IMG, char * FileName, ImageType IType); //Функция для сохранения изображения
ImageData * agNewImage(int Width, int Height,  Pixelformat PFormat); //Функция для создания нового,пустого, изображения
ImageData * agCloneImage(ImageData * Src); //Функция для создания копии изображения



Директива препроцессора #pragma once нужна для контроля: конкретный файл должен подключаться при компиляции только один раз.

Теперь перейдём к реализации.

Откройте файл Image.cpp и включите в него Image.h:

Код:
/*http://esate.ru, Alexei16*/

#include "Image.h"


Теперь разберём каждую функцию по отдельности.

1. Функция agLoadImage

Код:
/*http://esate.ru, Alexei16*/

ImageData * agLoadImage(char * FileName) //FileName - указатель на строку с именем файла
{
   ILuint * Texture = new ILuint; //Указатель на текстуру
   ImageData * Result = NULL; //Изображение

   ilInit();                //И и и л з ц я D v L
   ilEnable(IL_ORIGIN_SET); // н ц а и а и   е I
   ilGenImages(1, Texture); //Генерируем текстуру
   ilBindImage(*Texture);   //Делаем текстуру текущей

   if(ilLoadImage(FileName) == true) //Пытаемся загрузить изображение
   { // если да, то
      Result = new ImageData(); //Создаём изображение
      
      Result -> Width = ilGetInteger(IL_IMAGE_WIDTH); //Получаем ширину изображения
      Result -> Height = ilGetInteger(IL_IMAGE_HEIGHT);//Получаем высоту изображения
      Result -> Bpp = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);//Получаем количество байт на пиксель
      Result -> Stride = Result -> Width * Result -> Bpp;//Вычислем количество байт в одной строке пикселей

      Result -> Data = new unsigned char[Result -> Width * Result -> Height * Result -> Bpp]; //Создаём указатель на данные изображения

      

      memcpy(Result -> Data, ilGetData(), ilGetInteger(IL_IMAGE_SIZE_OF_DATA)); //Копируем данные из памяти в наше изображение

      Result -> BaseInfo.Type = ilGetInteger(IL_IMAGE_TYPE);//Получаем тип данных в памяти
      Result -> BaseInfo.Format = ilGetInteger(IL_IMAGE_FORMAT);//Получаем формат пикселей
      Result -> BaseInfo.Depth = ilGetInteger(IL_IMAGE_DEPTH);//Получаем глубину изображения

      if(Result -> BaseInfo.Format == IL_RGB) //Если формат пикселей BGR, то
      {                                       //данные располагаются в памяти
         Result -> R_idx = 0;            //так ->
         Result -> G_idx = 1;            //0|1|2|0|1|2|0|1|2|0|1
         Result -> B_idx = 2;            //R|G|B|R|G|B|R|G|B|R|G
      }
      else if(Result -> BaseInfo.Format == IL_RGBA) //Если формат пикселей RGBA,то
      {                                          //данные располагаются в памяти
         Result -> R_idx = 0;               //так ->
         Result -> G_idx = 1;               //0|1|2|3|0|1|2|3|0|1|2|3|0
         Result -> B_idx = 2;               //R|G|B|A|R|G|B|A|R|G|B|A|R
         Result -> A_idx = 3;
      }
      else if(Result -> BaseInfo.Format == IL_BGR) //Если формат пикселей BGR,то
      {                                            //данные располагаются в памяти
         Result -> R_idx = 2;                 //так ->
         Result -> G_idx = 1;                 //0|1|2|0|1|2|0|1|2|0|1|2
         Result -> B_idx = 0;                 //B|G|R|B|G|R|B|G|R|B|G|R
      }
      else if(Result -> BaseInfo.Format == IL_BGRA) //Если формат пикселей BGRA, то
      {                                          //данные располагаются в памяти
         Result -> R_idx = 2;               //так ->
         Result -> G_idx = 1;               //0|1|2|3|0|1|2|3|0|1|2|3|0
         Result -> B_idx = 0;               //B|G|R|A|B|G|R|A|B|G|R|A|B
         Result -> A_idx = 3;
      }
      else
      {
         MessageBoxA(0, "Unsuitable pixel format", "Error", MB_OK | MB_ICONERROR);
      }
   }
   else
   { //Если нет, то выдаём сообщение об ошибке
      MessageBoxA(0, "Could not load image", "Error", MB_OK | MB_ICONEXCLAMATION);
   }
   ilDeleteImages(1, Texture); //Удаляем текстуру ->
   delete Texture;             //->|

   return Result;
}



2. Функция agSaveImage

Код:
/*http://esate.ru, Alexei16*/

bool agSaveImage(ImageData * IMG, char * FileName, ImageType IType) //IMG - изображение, FileName - имя сохраняемого файла, IType - расширение файла
{
   bool Res;//Результат функции
   if(IMG != NULL && strlen(FileName) > 0)//Если изображение не пустое и длинна имени файла больше нуля,то
   {
      ILuint * Texture = new ILuint;//Указатель на текстуру

      ilInit(); //Инициализация DevIL
      ilGenImages(1, Texture);//Генерируем текстуру
      ilBindImage(*Texture);  //Делаем её текущей

      ilTexImage(IMG -> Width,IMG -> Height,
               IMG -> BaseInfo.Depth,IMG -> Bpp,IMG -> BaseInfo.Format,IMG -> BaseInfo.Type,
               IMG -> Data);//Закидываем данные в память
      Res = ilSave(IType, FileName);//И сохраняем изображение

      ilDeleteImages(1, Texture); //Удаляем текстуру ->
      delete Texture;             //->|
   }
   else
   { //Иначе,выдаем сообщене об ошибке
      MessageBoxA(0, "Pointer to the image is empty or the wrong name of the saved file", "Error", MB_OK | MB_ICONERROR);
   }
   return Res;
}



3. Функция agNewImage

Код:
/*http://esate.ru, Alexei16*/

ImageData * agNewImage(int Width, int Height,  Pixelformat PFormat)
{
   ImageData * Result = NULL;//Результат функции
   if(Width > 0 && Height > 0) //Если длинна и ширина - положительные величины, то
   {
      Result = new ImageData();//Создаем изображение

      Result -> Width = Width; // Присваиваем длинну
      Result -> Height = Height; // Присваиваем ширину
      Result -> PixFormat = PFormat; // Присваиваем формат пикселей

      Result -> BaseInfo.Depth = 1;
      Result -> BaseInfo.Type = IL_UNSIGNED_BYTE;

      if(Result -> PixFormat == AG_BGR)
      {
         Result -> R_idx = 2;
         Result -> G_idx = 1;
         Result -> B_idx = 0;
         Result -> BaseInfo.Format = IL_BGR; 
         Result -> Bpp = 3; //3 байта на пиксель, потомучто B(1 byte) + G(1 byte) + R(1 byte) = 3 bytes 
      }
      else if(Result -> PixFormat == AG_BGRA)
      {
         Result -> R_idx = 2;
         Result -> G_idx = 1;
         Result -> B_idx = 0;
         Result -> A_idx = 3;
         Result -> BaseInfo.Format = IL_BGRA;
         Result -> Bpp = 4; //4 байта на пиксель, потомучто B(1 byte) + G(1 byte) + R(1 byte) + A(1 byte) = 3 bytes
      }
      else if(Result -> PixFormat == AG_RGB)
      {
         Result -> R_idx = 0;
         Result -> G_idx = 1;
         Result -> B_idx = 2;
         Result -> BaseInfo.Format = IL_RGB;
         Result -> Bpp = 3;
      }
      else if(Result -> PixFormat == AG_RGBA)
      {
         Result -> R_idx = 0;
         Result -> G_idx = 1;
         Result -> B_idx = 2;
         Result -> A_idx = 3;
         Result -> BaseInfo.Format = IL_RGBA;
         Result -> Bpp = 4;
      }

      Result -> Data = new unsigned char[Result -> Width * Result -> Height * Result -> Bpp]; //Выделяем память под данные изображения
      Result -> Stride = Result -> Width * Result -> Bpp; //Вычисляем количество байт на строку пикселей
   }
   else
   { //Иначе выдаем сообщение об ошибке
      MessageBoxA(0, "Invalid input parameters", "Error", MB_OK | MB_ICONERROR);
   }
   return Result;
}



4. Функция agCloneImage

Код:
/*http://esate.ru, Alexei16*/

ImageData * agCloneImage(ImageData * Src) //Src - исходное изображение
{
   ImageData * Dst = NULL; //Новое изображение
   if(Src != NULL) // Если исходное изображение не пустое,то
   {
      Dst = new ImageData();//Создаем новое изображение

      Dst -> B_idx = Src -> B_idx;// далее все просто копируем
      Dst -> G_idx = Src -> G_idx;
      Dst -> R_idx = Src -> R_idx;
      Dst -> A_idx = Src -> A_idx;

      Dst -> Width = Src -> Width;
      Dst -> Height = Src -> Height;
      Dst -> Stride = Src -> Stride;
      Dst -> Bpp = Src -> Bpp;
      Dst -> PixFormat = Src -> PixFormat;

      Dst -> BaseInfo.Depth = Src -> BaseInfo.Depth;
      Dst -> BaseInfo.Format = Src -> BaseInfo.Format;
      Dst -> BaseInfo.Type = Src -> BaseInfo.Type;
      try
      {
         Dst -> Data = new unsigned char[Dst -> Width * Dst -> Height * Dst -> Bpp];
         memcpy(Dst -> Data, Src -> Data, Dst -> Width * Dst -> Height * Dst -> Bpp);
      }
      catch(...)
      {
         MessageBoxA(0, "Can not allocate memory", "Error", MB_OK | MB_ICONERROR);
         delete Dst;
      }
   }
   else
   { //иначе, выдаем сообщение об ошибке
      MessageBoxA(0, "Invalid input parameters", "Error", MB_OK | MB_ICONERROR);
   }
   return Dst;
}


Вот собственно и все!

Нет доступа к просмотру комментариев.

^