Python 3: Как размыть изображение GeoTIFF с помощью таблицы цветов? - PullRequest
0 голосов
/ 07 сентября 2018

У меня есть изображение GeoTIFF, которое мне нужно сделать размытым, применив фильтр сглаживания. Само изображение содержит метаданные, которые необходимо сохранить. Он имеет битовую глубину 8 и использует таблицу цветов с 256 32-битными значениями RGBA для поиска цвета для каждого пикселя, но для того, чтобы полученное изображение выглядело гладким, ему, вероятно, придется использовать битовую глубину 24 или 32 и нет таблицы цветов, в качестве альтернативы используйте сжатие JPEG. Что еще может усложнить это, так это то, что размер изображения составляет 23 899 x 18 330 пикселей, что почти в пять раз больше, чем самый большой файл, который PIL хочет открыть по умолчанию.

Как создать размытую версию этого изображения в Python 3?

Я также пытался использовать PIL , чтобы просто открыть и снова сохранить его:

from PIL import Image
Image.MAX_IMAGE_PIXELS = 1000000000
im = Image.open(file_in)
im.save(file_out)

Этот код не дает сбоя, и я получаю новый файл .tif, который приблизительно равен оригинальному файлу, но когда я пытаюсь открыть его в средстве просмотра фотографий Windows, приложение говорит, что оно повреждено, и он не может быть повторно открыт PIL.

Я также пытался использовать GDAL. Когда я пытаюсь этот код , я получаю выходное изображение размером 835 МБ, которое соответствует несжатому изображению с битовой глубиной 16 (это также то, что метаданные файла говорят, когда я щелкаю правой кнопкой мыши) на нем и выбираю «Свойства» - я использую Windows 10). Однако получающееся изображение является монохромным и очень темным, и цвета выглядят так, как будто они перемешаны, что заставляет меня поверить, что код, который я пытаюсь интерпретировать, представляет значения пикселей как значения интенсивности, а не как ключи таблицы.

Итак, чтобы заставить этот метод работать, мне нужно выяснить, как применить таблицу цветов (которая является своего рода контейнером для кортежей типа osgeo.gdal.ColorTable) к растровой полосе (какой бы ни была растровая полоса) , который является массивом с формой (18330, 23899), чтобы получить новый массив с формой (18330, 23899, 4) или (4, 18330, 23899) (не знаю, какая форма правильная), вставьте его обратно в загруженное изображение и удалите таблицу цветов (или создайте новую с теми же метаданными) и, наконец, сохраните измененное изображение с включенным сжатием (так что я приближаюсь к исходному размеру файла - 11,9 МБ), а не к 835 МБ, который является размером файла, который я Получить сейчас). Как я могу это сделать?

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

pyvips может быстро обрабатывать огромные изображения, используя лишь небольшой объем памяти, и поддерживает палитру изображений TIFF.

К сожалению, он не будет поддерживать дополнительные теги geotiff, так как libtiff не будет работать с неизвестными типами тегов. Вам нужно скопировать эти метаданные другим способом.

В любом случае, если вы можете сделать это, pyvips должен работать с вашим изображением. Я попробовал этот пример:

import sys
import pyvips

# the 'sequential' hint tells libvips that we want to stream the image
# and don't need full random access to pixels ... in this mode, 
# libvips can read, process and write in parallel, and without needing
# to hold the whole image in memory
image = pyvips.Image.new_from_file(sys.argv[1], access='sequential')
image = image.gaussblur(2)
image.write_to_file(sys.argv[2])

На изображении того типа и размера, которое у вас есть, сгенерированное в формате JPEG TIFF:

$ tiffinfo x2.tif 
TIFF Directory at offset 0x1a1c65c6 (438068678)
  Image Width: 23899 Image Length: 18330
  Resolution: 45118.5, 45118.5 pixels/cm
  Bits/Sample: 8
  Compression Scheme: None
  Photometric Interpretation: palette color (RGB from colormap)
...
$ /usr/bin/time -f %M:%e python3  ~/try/blur.py x2.tif x3.tif[compression=jpeg]
137500:2.42

Итак, 140 МБ памяти, 2,5 секунды. Выходное изображение выглядит правильно и составляет 24 Мб, так что не слишком далеко от вашего.

0 голосов
/ 07 сентября 2018

Растровая полоса - это просто имя, данное каждому «слою» изображения, в вашем случае это будут красные, зеленые, синие и альфа-значения. Это то, что вы хотите размыть. Вы можете открыть изображение и сохранить каждую полосу в отдельный массив, используя data.GetRasterBand(i), чтобы получить i-ую полосу (с индексированием 1, , а не 0-индексированием) изображения, которое вы открыли с помощью GDAL.

Затем вы можете попробовать использовать scipy.ndimage.gaussian_filter SciPy для достижения размытия. Вы захотите отправить ему массив shape (x, y), поэтому вам придется делать это для каждой растровой полосы в отдельности. Вы должны быть в состоянии сохранить ваши данные как другой GeoTIFF, используя GDAL.


Если таблица цветов, с которой вы работаете, означает, что ваши данные хранятся в каждой полосе растров в нечетном формате, который не просто колеблется между 0 и 1 для каждого из R, G, B и A, тогда подумайте об использовании scipy.ndimage.generic_filter, хотя, не зная, как хранятся ваши данные, сложно дать конкретную информацию о том, как вы это сделаете.

...