Подтвердить что ты не робот

Изображения JPEG имеют разные значения пикселей для нескольких устройств

Я заметил, что при чтении на одинаковой фотографии на устройствах в формате JPEG значения пикселей не совпадают. Они близки, но разные. При преобразовании в PNG файлы значения пикселей, похоже, совпадают.

Казалось бы, это связано с (un) алгоритмами сжатия между устройствами. Это то, что приходит в голову. Есть ли способ читать в файлах JPEG, чтобы одни и те же пиксели извлекались из фотографии на устройствах? Я не вижу опции в компоненте BitmapFactory Options.

В настоящее время применяется для поддержания размера при работе с пиксельными значениями изображения между устройствами:

Options options = new Options();
options.inScaled = false;
options.inPreferQualityOverSpeed = true;

В настоящее время сравниваются пиксели со следующим, чтобы посмотреть несколько (близкие совпадения, но не равные):

int[] pixels = new int[bitmapF.getWidth() * bitmapF.getHeight()];
bitmapF.getPixels(pixels, 0, bitmapF.getWidth(), 0, 0, bitmapF.getWidth(), bitmapF.getHeight());
Log.d("pixel entries", "pixels = " + pixels[233] + " - " + pixels[4002] + " - " + pixels[11391]);

Примечание. Если вы читаете в PNG-версии того же файла, который несжатый, значения идентичны, как ожидалось.

Samsung Galaxy S4, например, и Samsung Galaxy S5 даже имеют разные пиксели от одного и того же jpeg (отключение той же тестовой активности), хранящейся в папке с ресурсами.

pixel [233], например, будет -5205635 на s5, но -5336451 на s4. Пиксель [4002] также немного выключен. Но пиксель [11391] равен для обоих устройств на этом изображении jpeg.

4b9b3361

Ответ 1

Стандарт JPEG не требует, чтобы реализация декодера создавала идентичные выходные изображения бит-бит. К сожалению, нормативный документ, определяющий требования декодера, ISO 10918-2, по-видимому, не доступен онлайн, но Wikipedia говорит

... стандарт JPEG (и аналогичные стандарты MPEG) включает некоторые требования к точности для декодирования, включая все части процесса декодирования (декодирование с переменной длиной, инверсный DCT, деквантование, перенормировка выходов); выход из эталонного алгоритма не должен превышать:

  • максимум 1 бит разницы для каждого компонента пикселя
  • низкая среднеквадратичная ошибка по каждому блоку размером 8 × 8 пикселей.
  • [и др.]

Различия между различными выходами декодера с использованием одного и того же входа обычно связаны с различными уровнями внутренней точности, особенно при выполнении IDCT. Другим возможным источником различий является сглаживание, которое пытается уменьшить "блокирующие" артефакты.

Как и вы, я ожидал бы, что настройка inPreferQualityOverSpeed будет выдавать тот же результат, но ничего на самом деле этого не гарантирует. Я могу подумать хотя бы о нескольких способах, которыми вы могли бы получить небольшие вариации на двух разных телефонах:

  • В телефонах могут работать разные версии Android, где была изменена реализация BitmapFactory (например, возможно, inPreferQualityOverSpeed была повреждена, а затем исправлена ​​или наоборот) или
  • Телефоны могут предоставлять различные аппаратные функции (например, набор векторных инструкций, сопроцессор DSP и т.д.), который использует BitmapFactory. Даже различия в скалярных единицах с плавающей запятой могут вызывать расхождения, особенно с компиляцией JIT, создающей фактические машинные инструкции.

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

Ответ 2

Я полагаю, вы также должны проверить, отображаются ли сжатые PNG одинаково на всех устройствах.

http://pngquant.org/

Если да, то единственное, что осталось, это выяснить, как конвертировать программно по телефону эти изображения в тот же самый сжатый png.

Ответ 3

Большая часть работы декодера JPEG включает вычисления реальных чисел. Обычно это делается с использованием целочисленной арифметики фиксированной точки для производительности. Это приводит к ошибкам округления. Небольшие вариации - естественная часть работы с JPEG.

Ответ 4

Да, значения цвета пикселей различны для разных устройств. Это очень раздражает, особенно если вы хотите сравнить цвета. Решение заключается в сравнении визуально равных цветов (по восприятию человеком).

Одним из лучших методов сравнения двух цветов с помощью человеческого восприятия является CIE76. Разница называется Delta-E. Когда он меньше 1, человеческий глаз не может распознать разницу.

Вы можете найти класс замечательных цветных утилит (ColorUtils), который включает методы сравнения CIE76. Это написано Даниэлем Штребелем, Цюрихским университетом.

Из ColorUtils.class я использую метод:

static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)

r1, g1, b1 - значения RGB первого цвета

r2, g2, b2 - значения RGB второго цвета, которые вы хотели бы сравнить

Если вы работаете с Android, вы можете получить следующие значения:

r1 = Color.red(pixel);

g1 = Color.green(pixel);

b1 = Color.blue(pixel);

Ответ 5

Измените размер носителя до требуемого размера или используйте атрибуты HTML, чтобы отключить масштабирование изображения.

Другим вариантом было бы позволить пользователю решить после загрузки представления эскизов для экономии полосы пропускания.