Представление изображений в памяти
Исходным цветом монитора является чёрный, а все остальные цвета на нем получаются при помощи комбинации трех цветов различной интенсивности - красного, зеленого и синего.
Минимальный элемент изображения на мониторе, это 3 рядом стоящие точки, красного, зеленого и синего цветов. Если приглядеться, или посмотреть на монитор через линзу, их можно увидеть.
Такой триплет называется пикселом (pixel), как сокращение от picture element. Интенсивность красного, зеленого и синего компонет (RGB) задается числом от 0 до 255. 0 соответствует наименьшей интенсивности, 255 наибольшей.
Таким образом, любую картинку можно описать при помощи таких наборов из трех чисел.

Каждое число, описывающее компонент пиксела, умещается в 8 бит, и весь пиксел описывается при помощи 24 битов. Иногда можно встретить другое представление пикселя, где максимальная интенсивность компоненты 5 или 6 бит и пиксел описывается 16-битным числом. Такое представление часто можно встретить на переносных устройствах, вроде телефонов. Также встречается 32-битное представление, где первые 8 бит описывают величину прозрачности пиксела. Такие представления я рассматривать не буду, и делее везде будет предполагаться (если отдельно не оговорено) 24-битное представление пикселя.
Каждое прямоугольное электронное изображение характеризуется шириной и высотой. Ширина такого изображения это количество столбцов из пикселей, а высота - количество строк. В памяти компьютера удобно хранить такое изображение последовательно, слева направо и сверху вниз. Пусть H - высота изображения, а W - его ширина. Тогда размер памяти IM, который понадобиться для изображения равен H * W * 3 байт. Если мы хотим считать пиксель, с координатами картинки (x,y) из памяти, то нам нужно считать значение по адресу памяти A = (y * W + x) * 3. Тогда, по адресу A будет храниться красный компонент, по адресу А+1, зеленый и по адресу А+2, синий.
Напишем простейший класс на С++, который будет хранителем изображения и позволит обращаться к каждому пикселу:
class CImageCore { public: // конструктор CImageCore(int w, int h) { // размер памяти для изображения int size = w * h * 3; // выделяем память нужного размера m_image = new unsigned char[size]; // сохраняем ширину и высоту изображения внутри класс m_width = w; m_height = h; } // в деструкторе освобождаем память ~CImageCore() { delete []m_image; } // получить пиксель с координатами (x,y) из памяти unsigned long pixel(int x, int y) { // вычисляем адрес пикселя int a = (y * m_width + x) * 3; // получаем компоненты пикселя unsigned long R = image[A]; unsigned long G = image[A+1]; unsigned long B = image[A+2]; // так мы представляем 8-битные компоненты пикселя в виде одного 32-битного числа. return (R << 16) | (G << 8) | B; } // установить для пикселя с координатами (x,y) значение цвета r,g,b void setPixel(int x, int y, int r, int g, int b) { // вычисляем адрес пикселя int a = (y * m_width + x) * 3; // сохраняем компоненты пикселя image[A] = r; image[A+1] = g; image[A+2] = b; } // получить ширину картинки int width() { return m_width; } // получить высоту картинки int height() { return m_height; } protected: unsigned char *m_image; // массив картинки int m_width; // ширина int m_height; // высота };
Теперь у нас есть готовый объект для работы с изображениями в памяти.