Формат JPEG{59}
предполагает выполнение не менее пяти последовательных преобразований, большинство из которых сжимает данные, полученные на предыдущем этапе (первоначальные сырые данные на первом этапе). Остальные перекодируют их для дальнейшего сжатия. Цифровые изображения состоят из миллионов крохотных квадратиков, именуемых пикселями – элементами картинки (на английском слово pixel расшифровывается как picture element). Сырые данные с камеры присваивают каждому пикселю битовую строку, представляющую как цвет, так и яркость. Обе величины представляются как доли трех компонентов: красного, зеленого и синего. Низкие доли всех трех компонентов соответствуют бледным цветам, высокие – темным. Эти числа конвертируются в три связанных друг с другом числа, которые лучше соответствуют тому, как человеческий мозг воспринимает изображения. Первое из них – светлота – дает общую яркость изображения и измеряется числами от черного, через все более светлые оттенки серого, до белого. Если удалить информацию о цвете, у вас останется старомодное черно-белое изображение – на самом деле это множество оттенков серого. Другие два числа, известные как цветность, представляют собой разности между светлотой и количеством синего и красного света соответственно.Символьно, если R – красный, G – зеленый и B – синий, то начальные числа для R, G и B заменяются светлотой R + G + B и двумя цветностями (R + G + B) – B = R + G и (R + G + B) – R = G + B. Если вы знаете R + G + B, R + G и G + B, то можете вычислить R, G и B, так что этот этап проходит без потерь.
Реализовать второй этап без потерь не удастся. Здесь данные цветности урезаются до меньших значений за счет огрубления разрешения. Один только этот этап снижает размер файла данных наполовину. Это приемлемо, потому что в сравнении с тем, что «видит» камера, зрительная система человека более чувствительна к яркости и менее – к цветовым различиям.
Третий этап наиболее математичен. Он сжимает информацию светлости с использованием цифровой версии преобразования Фурье, которую мы встречали в главе 9 в связи с медицинскими сканерами. Там оригинальное преобразование Фурье, которое превращает сигналы в составляющие их частоты и наоборот, было модифицировано, чтобы представлять проекции черно-белых изображений. На этот раз мы представляем сами черно-белые изображения, но в простом цифровом формате. Изображение разбивается на крохотные блоки 8 × 8 пикселей, так что в каждом из них присутствуют 64 возможных значения светлости, по одному на каждый пиксель. Дискретное косинусное преобразование – цифровой вариант преобразования Фурье – представляет это черно-белое изображение 8 × 8 как суперпозицию 64 стандартных изображений с коэффициентами. Эти коэффициенты суть
Хотя дискретное преобразование Фурье реализуется без потерь, его нельзя назвать бессмысленным, потому что именно оно делает возможным четвертый этап. Этот этап опять же основан на недостаточной чувствительности человеческого зрения, которая порождает избыточность. Если яркость или цвет меняется на большой площади изображения, мы это замечаем. Если они меняются на очень небольших участках, зрительная система сглаживает эффект, и мы видим лишь среднее. Именно поэтому печатные изображения воспринимаются как картинки, хотя при ближайшем рассмотрении они представляют оттенки серого россыпью черных точек на белой бумаге. Эта особенность человеческого зрения означает, что узоры с очень тонкими полосками менее важны, так что их амплитуды могут быть записаны с меньшей точностью.
64 базовых паттерна дискретного косинусного преобразования
Пятый этап – это технический прием, известный как «код Хаффмана», для более эффективной записи амплитуд 64 базовых паттернов. Дэвид Хаффман придумал этот метод в 1951 году еще студентом. Он тогда получил задание написать курсовую работу по оптимально эффективным двоичным кодам, но не мог доказать, что хотя бы какой-нибудь из существовавших на тот момент кодов оптимален. Уже собираясь сдаться, Хаффман придумал новый метод, а затем и доказал, что он является наилучшим из возможных. Грубо говоря, задача в том, чтобы закодировать множество символов при помощи двоичных строк, а затем использовать их как словарь для кодирования сообщения. Сделать это необходимо так, чтобы минимизировать общую длину закодированного сообщения.