Как я могу использовать VIPS для нормализации изображения?

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

До сих пор я использовал VIPS, в частности PyVIPS, и предпочел бы решение, использующее эту библиотеку. Найдя этот ответ и просмотрев документация, я пытался

x = pyvips.Image.new_from_file('test.ndpi')
x = x.hist_norm()
x.write_to_file('test_normalized.tiff')

но это, кажется, всегда дает чисто белое изображение.


person Twiffy    schedule 01.11.2019    source источник


Ответы (1)


Вам нужно hist_equal для выравнивания гистограммы.

Основные документы здесь:

https://libvips.github.io/libvips/API/current/libvips-histogram.html

Однако это будет очень медленно для больших изображений слайдов. Для построения гистограммы потребуется отсканировать весь слайд один раз, а затем снова отсканировать, чтобы выровнять ее. Было бы намного быстрее найти гистограмму слоя с низким разрешением, а затем использовать ее для выравнивания слоя с высоким разрешением.

Например:

#!/usr/bin/env python3

import sys
import pyvips

# open the slide image and get the number of layers ... we are not fetching 
# pixels, so this is quick
x = pyvips.Image.new_from_file(sys.argv[1])
levels = int(x.get("openslide.level-count"))

# find the histogram of the highest level ... again, this should be quick
x = pyvips.Image.new_from_file(sys.argv[1], 
                               level=levels - 1)
hist = x.hist_find()

# from that, compute the transform for histogram equalisation
equalise = hist.hist_cum().hist_norm()

# and use that on the full-res image
x = pyvips.Image.new_from_file(sys.argv[1])

x = x.maplut(equalise)

x.write_to_file(sys.argv[2])

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

$ ~/try/equal.py bild.ndpi[level=7] y.jpg

введите здесь описание изображения

Полосы — от сканера слайдов, а некрасивые полосы — от сжатия.

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

Что-то типа:

x = pyvips.Image.new_from_file(sys.argv[1])
levels = int(x.get("openslide.level-count"))
x = pyvips.Image.new_from_file(sys.argv[1],
                               level=levels - 1)
mn = x.min()
mx = x.max()
x = pyvips.Image.new_from_file(sys.argv[1])
x = (x - mn) * (256 / (mx - mn))
x.write_to_file(sys.argv[2])

Вы нашли новую функцию Region в pyvips? Это позволяет генерировать патчи для обучения НАМНОГО быстрее, в некоторых случаях до 100 раз быстрее:

https://github.com/libvips/pyvips/issues/100#issuecomment-493960943

person jcupitt    schedule 03.11.2019
comment
Спасибо! Функция «Регион» выглядит великолепно. Для hist_equal я также получаю артефакты. Можете ли вы рассказать больше о том, как получить максимум и минимум и сделать линейное растяжение? - person Twiffy; 05.11.2019
comment
Кроме того, как записать регион в файл? - person Twiffy; 05.11.2019
comment
Я добавил пример mx/mn. Нет смысла использовать выборку, если вы работаете с файлами — что бы вы ни делали, это будет невероятно медленно. Fetch удобен, если вы хотите передавать массивы пикселей непосредственно в pytorch и т. д. - вы увидите огромное ускорение. - person jcupitt; 05.11.2019
comment
О, я думаю, вы имеете в виду для отладки? Вы можете обернуть изображение вокруг массива байтовых значений с помощью new_from_memory. - person jcupitt; 05.11.2019