Почему ImageStat возвращает неверную статистику для целочисленных изображений со знаком (`mode = 'I'`)? - PullRequest
1 голос
/ 02 июля 2019

У меня есть изображения глубины с очень большими диапазонами значений, порядка [0, 10000], сохраненные в формате png. По умолчанию они загружаются как изображения PIL с mode='I', 32-разрядными целочисленными пикселями со знаком, но имеют непредвиденное поведение.

Например, Image.show() отображает пустой белый экран. Это несколько ожидаемо, так как я предполагаю, что функция ожидает ввода [0, 1] или [0, 255] и усекает значения пикселей в моих изображениях, которые находятся вне этого диапазона.

Более того, ImageStat возвращает неправильные значения для большинства статистических данных. Я подтвердил оба этих значения независимыми результатами numpy и Matlab. Этого не происходит для более обычных изображений RGB, mode='RGB'.

*

1018 Вопрос * Что здесь происходит? Это тоже проблема усечения? MCVE

Используйте следующее изображение как test.png

Depth camera capture with smoothing* * 1030

from PIL import Image
im = Image.open("test.png")
im.show() # shows white blank screen 
print(im.mode) # prints 'I'

from PIL.ImageStat import Stat
stat = Stat(im)
print(stat.mean)    # [85.10539415869734]
print(stat.extrema) # [(0, 255)]
print(stat.sum)     # [32927277.0]

import numpy as np
print(np.mean(im)) # 28051.3720754717
print(np.min(im))  # 9992
print(np.max(im))  # 63816
print(np.sum(im))  # 10853075856

Результаты Matlab похожи на numpy

1 Ответ

1 голос
/ 02 июля 2019

Image.show() отображает пустой белый экран

Причина этого в том, что Image.show() использует временный буфер для хранения объекта изображения. А затем преобразует объект Image в .bmp ( bitmap ) перед его отображением. Растровый формат не поддерживает 32-битные одноканальные изображения (в оттенках серого), поэтому результаты, полученные с помощью show(), нежелательны.

ImageStat возвращает неверные значения для большинства статистических данных

После выполнения анализа исходного кода модуля ImageStat я узнал, что модуль специально создан для работы с изображениями, имеющими 0 ≤ выборочное пространство > 256 , или изображениями со значениями пикселей в диапазоне (0 ≤ value ≤ 255) .

Например, если мы проанализируем Stat.extreme: -

def _getextrema(self):
    """Get min/max values for each band in the image"""

    def minmax(histogram):
        n = 255
        x = 0
        for i in range(256):
            if histogram[i]:
                n = min(n, i)
                x = max(x, i)
        return n, x  # returns (255, 0) if there's no data in the histogram

    v = []
    for i in range(0, len(self.h), 256):
        v.append(minmax(self.h[i:]))
    return v

Мы можем ясно видеть, что функция, используемая для вычисления верхней и нижней границы значений пикселей изображения, не может возвращать значение ниже 0 и не может возвращать значение больше 255. т.е. (значение ∈ {0 - 255}) .

Функция Stat выполнена таким образом, что она работает правильно только в том случае, если диапазон значений пикселей изображения меньше 256.

Это тоже проблема усечения

Нет. Усечения не происходит, при расчете значений в Stat. Модуль Stat не создан таким образом, чтобы он мог сгладить / усечь значения пикселей вне своего нормального диапазона. Скорее, что происходит, когда объект изображения передается в Stat, он просто выполняет для него нормальные вычисления (при условии, что диапазон значений пикселей находится в диапазоне от 0 до 255). Тогда выход зависит исключительно от того, вызвал ли входной параметр прерывание / исключение при расчете значения или нет, т. Е. Если все как-то пойдет хорошо, вывод будет нежелательным. Но это не всегда так.

Например: -

img = Image.new("I", (300, 300), (3000))

stat = Stat(img)
print(stat.mean)
print(stat.extrema)
print(stat.sum)     

Код после исполнения: -

Traceback (most recent call last):
  File "C:/Users/Vasu/AppData/Local/Programs/Python/Python37-32/Lib/site-packages/PIL/testing.py", line 10, in <module>
    print(stat.mean)
  File "C:\Users\Vasu\AppData\Local\Programs\Python\Python37-32\lib\site-packages\PIL\ImageStat.py", line 48, in __getattr__
    v = getattr(self, "_get" + id)()
  File "C:\Users\Vasu\AppData\Local\Programs\Python\Python37-32\lib\site-packages\PIL\ImageStat.py", line 104, in _getmean
    v.append(self.sum[i] / self.count[i])
ZeroDivisionError: float division by zero

Следовательно, вывод будет либо нежелательным, либо в конечном итоге приведет к ошибке / исключению.

Означает ли это, PIL не поддерживает I цветной режим

Нет. PIL имеет полную поддержку 32-битных целых чисел со знаком.

Например, если мы пытаемся получить пиксельные значения вашего изображения: -

im = Image.open(r"Input_img")
im = list(im.getdata())

print(im)

Мы получаем фактические значения пикселей: -

40384, 40384, 40384, 40384, 40384, 40600, 40600, 40600, 40808, 41016, 41232, 41440, 41656.....22232]

ЗАКЛЮЧЕНИЕ: - PIL имеет встроенную поддержку 32-битных целочисленных пикселей со знаком, но ImageStat - нет.

PS: - Текущее состояние PIL / подушки документация не так хороша, то есть она не так хороша для объяснения ..... что бы оно ни пыталось объяснить , Поэтому мы должны добавить как можно больше информации. Итак, я бы посоветовал вам опубликовать запрос на выпуск / выгрузку в PIL-репозитории на Github , касающийся улучшений в описании модуля ImageStat. Как добавление строк, таких как: -

Модуль не имеет встроенной поддержки значений пикселей больше 8 бит

или что-то еще в этом духе.

...