Общие советы по работе с изображениями
Не стоит работать на низком уровне с изображениями через системные функции
Системные типы и классы HBITMAP, Bitmap и им подобные рассчитаны, в первую очередь, на вывод на экран.
Для них существует множество функций рисования геометрических примитивов, вывода текста, но при этом отсутствует
прямой доступ к пикселям изображения. Функции Bitmap::GetPixel и им подобные работают непозволительно долго.
Оптимальным вариантом является работа с изображением непосредственно в памяти.
Это можно сделать двумя способами:
- Написав свои классы для работы с изображениями. Особенно полезно это будет для тех, кто не имеет
достаточного опыта программирования.
- Через DIB (device independent bitmap). Данный способ рекомендуется в случае, когда помимо прямого доступа к
пискелям изображения нужно рисовать на нём с помощью GDI-функций.
Работайте с пикселями в формате float, а не byte
Экономия памяти важна при написании коммерческого кода, но не при разработке математических методов обработки изображений.
Использование float имеет следующие преимущества перед byte:
- Отсутствие ошибок, связанных с переполнением при выходе за границы диапазона [0, 255]
- Не накапливаются ошибки округления.
- Многие алгоритмы значительно проще реализуются при использовании типа float, например, Canny edge detection.
Некоторые алгоритмы вообще не могут быть реализованы при использовании типа byte для пикселя.
Более того, в современных процессорах работа с float будет производиться быстрее, чем с byte.
Делайте обход по изображениям в правильном порядке
Двумерные изображения хранятся в памяти в виде одномерных массивов. Обычно они записываются построчно: сначала идёт 0-я строка,
затем 1-я и т.д. Последовательный доступ к памяти осуществляется быстрее, чем произвольный. Поэтому обход по изображению
нужно делать так, чтобы доступ к памяти был последовательный: во внешнем цикле производится обход по вертикали, а во
внутреннем — по горизонтали:
for (int y = 0; y < image.Height(); y++)
for (int x = 0; x < image.Width(); x++)
...
Также стоит быть аккуратным при использовании двумерных массивов в C# (а лучше вообще их не использовать,
написав класс-обёртку для одномерных массивов): в них первый индекс — это строка (Y-координата), а вторая — столбец (X).
Как загружать и сохранять изображения
Вы всегда можете ознакомиться с форматами графических файлов и написать свои функции (классы, библиотеки) для
чтения и сохранения изображений в желаемых форматах. Однако если для формата BMP написание подобных функций не
составляет труда, то для более популярных форматов, таких как JPEG и PNG, написание своего декодера — идея не
из лучших.
Существует множество сторонних библиотек для работы с изображениями в C++, которые можно использовать для
загрузки и сохранения и загрузки изображений, однако в системе Windows для этих задач можно использовать встроенную
библиотеку GDI+. Общий принцип работы такой: загрузить изображение в класс Gdiplus::Bitmap, получить прямой доступ
к пикселям изображения и преобразовать изображение во внутреннее представление.
Ниже приложены проекты для Microsoft Visual Studio 2010, в которых реализованы функции чтения и записи изображений: