Примеры кода в main.ipynb. Текст:
Талантливый школьник во время сезона 2024 г. нарисовал новую эмблему Красноярской летней школы. Он так всем понравился, что дирекция решила отсканировать изображение и сохранить его на компьюетере. Получился файл формата BMP с расширением ".bmp".
Эту картинку можно найти по ссылке 1:
Известно, что байтовое представление файла ".bmp" имеет следующую структуру.
- BITMAPFILEHEADER — первые 14 байт.
- BITMAPINFO — в наших задачах это всегда будут следующие 40 байт.
- Пиксельные данные — всё остальное.
Подробную информацию про этот формат можно прочитать на Википедии, но из всех этих данных нас будут интересовать в основном следующие.
- С 10 по 14 байт записан номер байта, с которого начинается описание пиксельных данных картинки. В нашем случае это всегда 36 (54 в десятиричной).
- С 18 по 22 байт записана ширина изображения в пикселях.
- С 22 по 26 байт записана высота изображения в пикселях. Если это число положительное, то строки пикселей перечислены снизу вверх. Если это число отрицательное, то запись строк идёт сверху вниз, причём количество строк равно модулю этого числа.
- С 28 по 30 байт записано количество бит, которым шифруется цвет каждого пикселя. В нашем случае это всегда 3 байта (24 бита) : по одному байту на каждую цветовую компоненту.
Пиксельные данные — это последовательность цветов пикселей, записанная по следующим правилам.
- Всё изображение разбито на строки высотой в один пиксель.
- Данные о пикселях строк перечислены по порядку (сначала 1-я строка, потом 2-я и т.д.).
- Порядок строк зависит от значения высоты, записанной в BITMAPINFO: сверху вниз при отрицательном значении, снизу вверх при положительном.
- Пиксели каждой строки перечислены слева направо.
- Каждый пиксель зашифрован тремя числами от 0 до 255 в палитре rgb, то есть значениями синей, зелёной и красной компонент цвета пикселя, именно в таком порядке.
- Количество байт, соответствующих каждой строке, должно делиться на 4. Если количество байт не делится на 4, то в конец каждой строки дописывается необходимое количество нулей.
Чтобы лучше разобраться, как это работает, давайте рассмотрим следующий пример изображения из 4 пикселей (увеличено для наглядности). Изображение доступно по ссылке 2.
Это изображение занимает ровно 70 байт.
- Первые 14 байт секции BITMAPFILEHEADER:
Из-за ошибки при сканировании изображение получилось перевёрнутым. Тебя попросили вернуть изображению правильную ориентацию.
Напиши функцию (метод) vertical_reverse_image(input_image, result_image)
, которая изменит порядок строк изображения на противоположный. У этой функции должно быть два аргумента:
input_image : string
— относительный или абсолютный путь к файлу BMP изображения,result_image : string
— относительный или абсолютный путь к файлу, в который будет записан результат выполнения функции.
Твоя функция (метод) должна использовать только функции стандартных библиотек используемого языка программирования. При выполнении этого задания считай, что входное изображения обязательно имеет описанный выше формат.
Дирекция очень довольна твоей работой и захотела отправить это изображение по интернету из "Орбиты" в Красноярск, но интернет в "Орбите" не всегда стабильный, а наше изображение весит целых 7,5 мегабайт! Тебя попросили сжать это изображение так, чтобы при разжатии восстанавливалось в точности то же самое изображение.
Давай посмотрим на верхнюю пиксельную строку нашего изображения. Она состоит из белого пикселя "ff ff ff", повторенного много раз (столько раз, сколько пикселей поместилось в одну строку изображения). Но!
Мы же можем сильно сократить запись этого изображения, если вместо имеющейся записи укажем что-то вроде
"пиксель ff ff ff стоит 1629 раз", или просто "1629 ff ff ff ".
Будем обозначать число повторов одним байтом. Тогда 1629 белых пикселей можно записать следующим образом: "255 ff ff ff, 255 ff ff ff, 255 ff ff ff, 255 ff ff ff, 255 ff ff ff, 255 ff ff ff, 99 ff ff ff ".
Такая запись уже сильно сократит размер нашего файла, ведь теперь первая строка будет занимать 28 байт вместо 4887.
-
Напиши две функции (метода):
compress(input_image, result_image)
иdecompress(input_image, result_image)
, которые будут сжимать и разжимать обратно файл изображения по определённому ниже алгоритму. Аргументы этих функций имеют такой же смысл, что в задании 1.
Результатом применения функцииcompress()
должен стать файл с расширением ".cmp", который получается из оригинального BMP файла по следующему алгоритму.- Первые 54 байта файла ".cmp" такие же как и в файле ".bmp".
- Далее идёт пиксельная информация. Пиксели теперь кодируются следующим образом: сначала идёт один байт, обозначающий то количество раз, которое некоторый цвет встречается в строке подряд, а потом идут 3 байта, которые кодируют этот цвет в палитре rgb.
Результатом применения функции
decompress()
должен стать файл ".bmp", разжатый из файла ".cmp".
Обе написанные тобой функции должны использовать только функции стандартных библиотек используемого языка программирования. -
Какие изображения алгоритм будет сжимать в наибольшее количество раз? Во сколько раз будут сжаты пиксельные данные таких изображений?
-
Если считать, что целью сжатия изображения является как можно большее уменьшение его размера, то при применении к каким изображением данный алгоритм сжатия покажет самый плохой результат? Каким будет этот результат?
Дирекция потеряла цифровой исходник новой эмблемы. Осталась только её фотография, сделанная на телефон. Эта фотография доступна по ссылке 3. Дирекция заметила, что результат применения реализованного алгоритма сжатия к этой фотографии очень плохой.
- Объясни, почему результат оказался таким плохим.
Этот алгоритм может давать более приемлемый результат, если при сжатии "потерять" часть информации, имеющейся в изображении. Например, нескольким пикселям, которые изначально имели разные цвета, при сжатии можно присвоить один и тот же цвет.
- Напиши функцию
super_compress(input_image, result_image)
, которая улучшит степень сжатия фотографии новой эмблемы алгоритмом из задания 2 за счёт потери части информации. Добейся того, чтобы при сжатии размер фотографии уменьшился хотя бы на 20%. Также напиши функциюsuper_decompress(input_image, result_image)
, которая создаст изображение BMP из файла, полученного применением функцииsuper_compress()
. Постарайся сделать так, чтобы исходная фотография и её "разжатая" версия не сильно отличались друг от друга.