Сжатие изображения - PullRequest
       64

Сжатие изображения

2 голосов
/ 03 ноября 2019

Я рассчитывал размер несжатого и сжатого файла изображения. Для меня это всегда приводило к тому, что сжатое изображение было меньше, чем несжатое изображение, которое я ожидал. Если изображение содержит большое количество разных цветов, сохранение палитры занимает много места, и для хранения каждого кода также требуется больше битов. Однако мой вопрос заключается в том, возможно ли, что метод сжатия может привести к созданию файла большего размера, чем несжатого RGB-изображения. Каков будет размер (в пикселях) самого маленького квадратного изображения RGB, содержащего всего k различных цветов, для которого этот метод сжатия все еще полезен? Таким образом, мы хотим найти для заданного значения k минимальное целое число n, для которого изображение размером n × n занимает меньше места после сжатия, чем исходное изображение RGB.

Ответы [ 2 ]

1 голос
/ 03 ноября 2019

Давайте начнем с небольшого упрощения - размер закодированного вывода зависит от количества пикселей (фактическое соотношение ширины и высоты на самом деле не имеет значения). Поэтому давайте обобщим задачу на количество пикселей N , из которого мы всегда можем вычислить n , взяв квадратный корень.

imageN = n \times n \ \text{pixels}">

Чтобы еще больше упростить задачу, мы также будем игнорировать издержки любых заголовков / метаданных изображения, таких как ширина, высота, размер палитры и т. Д. На практике это обычно будет относительно небольшая константа.


Постановка задачи

Учитывая, что у нас есть

  • N , представляющее количество пикселей в изображении
  • k представляет количество различных цветов в изображении
  • 24 бит на пиксель в кодировке RGB
  • L RGB представляющий длину изображения RGB
  • L P представляющий длину изображения палитры

наша цель - решитьследующее неравенство

imageL_{\text{RGB}} > L_{\text{P}}">

с точки зрения N .


Размер изображения RGB

RGB-изображение - это просто массив из N пикселей, каждый пиксель занимает фиксированное количество бит, заданное кодированием RGB. Следовательно,

imageL_{\text{RGB}} = \left( N \times 24 \right) \ \text{bits}">


Размер изображения палитры

Изображение палитры состоит из двух частей: палитры и пикселей.

imageL_{\text{P}} = L_{\text{palette}} + L_{\text{pixels}}">

Палитра - это массив k цветов, каждый цвет занимает фиксированное количество битов, заданное кодированием RGB. Следовательно,

imageL_{\text{palette}} = \left( k \times 24 \right) \ \text{bits}">

В этом случае каждый пиксель содержит индекс для записи палитры, а не фактический цвет RGB. Число битов, необходимых для представления значений k , равно

image\log_{2}{k} \ \text{bits}">

Однако, если только мы не можем кодировать дробные биты (что я рассматриваю за рамками этого вопроса)нам нужно округлить это. Следовательно, количество битов, необходимых для кодирования индекса палитры, составляет

image\left \lceil{\log_{2}{k}}\right \rceil \ \text{bits}">

Поскольку существует N таких индексов палитры, размер данных пикселя равен

imageL_{\text{pixels}} = \left( N \times \left \lceil{\log_{2}{k}}\right \rceil \right) \ \text{bits}">

, а общий размер изображения палитры составляет

imageL_{\text{P}} = \left( k \times 24 \right) + \left( N \times \left \lceil{\log_{2}{k}}\right \rceil \right) \ \text{bits}">


Решение неравенства

imageL_{\text{RGB}} > L_{\text{P}}">

image\left( N \times 24 \right) > \left( k \times 24 \right) + \left( N \times \left \lceil{\log_{2}{k}}\right \rceil \right)">

image\left( N \times 24 \right) - \left( N \times \left \lceil{\log_{2}{k}}\right \rceil \right) > \left( k \times 24 \right)">

image\left( N \times \left( 24 - \left \lceil{\log_{2}{k}}\right \rceil \right) \right) > \left( k \times 24 \right)">

И, наконец,

imageN > \frac{k \times 24}{24 - \left \lceil{\log_{2}{k}}\right \rceil}">


В Python мы можем выразить это следующим образом:

import math

def limit_size(k):
    return (k * 24.) / (24. - math.ceil(math.log(k, 2)))

def size_rgb(N):
    return (N * 24.)

def size_pal(N, k):
    return (N * math.ceil(math.log(k, 2))) + (k * 24.)

0 голосов
/ 04 ноября 2019

В целом нет, но ваш вопрос не точный.

Если мы сжимаем обычные файлы, они могут быть больше. Например, если вы сжимаете случайную сгенерированную последовательность байтов, сжимать особо нечего, и поэтому вы получаете заголовок программы сжатия, который сообщает, какой метод сжатия используется, и некоторое управление версиями. Это увеличит файл, и ev. некоторые убегают. Хорошая программа сжатия увидит, что сжатие не будет уменьшать размер, и поэтому они должны просто не сжиматься, и скажут в заголовке, что это плоский файл. Возможно, это делается по региону программы.

Но ваш вопрос об изображениях. Сжатие выполняется внутри файла, и часто не во всем файле, а только в битах изображения. В этом случае программа увидит, что нет необходимости сжимать, и поэтому они будут держать файл без сжатия. Но поскольку заголовки изображений присутствуют всегда, это меняет только флаг, и поэтому увеличение размера не происходит.

Но это может зависеть также от формата файла. Вы писали о «палитре», но в настоящее время она мало используется: сжатие выполняется при нахождении аналогичного шаблона в файле. Но опять же: это зависит от формата изображения. Если вы посмотрите в Википедии конкретный формат файла, вы можете увидеть таблицу с параметрами заголовков (например, битовая глубина или количество цветов (палитра), определения цветов и методы, используемые для сжатия).

Затем,для изображения, подобного палитре, ответ Дана Машека (https://stackoverflow.com/a/58683948/2758823)) имеет хорошее математическое объяснение, но не следует забывать, что сжатие очень эвристично и проверяет реальные примеры: реальные изображения имеют шаблоны.

...