Оптимизация производительности при чтении файла спутникового изображения в python - PullRequest
4 голосов
/ 02 сентября 2011

У меня есть многоканальное спутниковое изображение, сохраненное в формате чередующихся пикселей (BIP) вместе с отдельным файлом заголовка. Заголовочный файл содержит такие сведения, как количество строк и столбцов в изображении, а также количество полос (может быть больше, чем стандарт 3).

Само изображение сохраняется следующим образом (предположим, 5-полосное изображение):

[B1] [B2] [B3] [B4] [B5] [B1] [B2] [B3] [B4] [B5] ... и т. Д. (В основном 5 байтов - по одному для каждой полосы - для каждый пиксель, начиная с верхнего левого угла изображения).

Мне нужно выделить каждую из этих полос в виде изображений PIL в Python 3.2 (в Windows 7, 64-разрядная версия), и в настоящее время я думаю, что неправильно подхожу к проблеме. Мой текущий код выглядит следующим образом:

def OpenBIPImage(file, width, height, numberOfBands):
    """
    Opens a raw image file in the BIP format and returns a list
    comprising each band as a separate PIL image.
    """
    bandArrays = []
    with open(file, 'rb') as imageFile:
        data = imageFile.read()
    currentPosition = 0
    for i in range(height * width):
        for j in range(numberOfBands):
            if i == 0:
                bandArrays.append(bytearray(data[currentPosition : currentPosition + 1]))
            else:
                bandArrays[j].extend(data[currentPosition : currentPosition + 1])
            currentPosition += 1
    bands = [Image.frombytes('L', (width, height), bytes(bandArray)) for bandArray in bandArrays]
    return bands

Этот код занимает слишком много времени, чтобы открыть файл BIP, несомненно, должен быть лучший способ сделать это. У меня также есть библиотеки numpy и scipy, но я не уверен, как я могу их использовать, и могут ли они даже помочь.

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

И просто для записи, я попытался возиться с методами списка в циклах (используя срезы, не используя срезы, используя только добавление, используя только расширение и т. Д.), Это не имеет особого значения, поскольку основное время теряется из-за количества задействованных итераций - (width * height * numberOfBands).

Любые предложения или советы будут действительно полезны. Спасибо.

Ответы [ 3 ]

4 голосов
/ 02 сентября 2011

Если вы можете найти быструю функцию для загрузки двоичных данных в большой список Python (или пустой массив), вы можете де-чередовать данные, используя обозначение срезов:

band0 = biglist[::nbands]
band1 = biglist[1::nbands]
....

Помогает ли это

1 голос
/ 02 сентября 2011

Я подозреваю, что повторение расширения не очень хорошо, лучше распределить все сначала

def OpenBIPImage(file, width, height, numberOfBands):
    """
    Opens a raw image file in the BIP format and returns a list
    comprising each band as a separate PIL image.
    """
    bandArrays = []
    with open(file, 'rb') as imageFile:
        data = imageFile.read()
    currentPosition = 0
    for j in range(numberOfBands):
        bandArrays[j]= bytearray(b"\0"*(height * width)):


    for i in xrange(height * width):
        for j in xrange(numberOfBands):
                bandArrays[j][i]=data[currentPosition])
            currentPosition += 1
    bands = [Image.frombytes('L', (width, height), bytes(bandArray)) for bandArray in bandArrays]
    return bands

мои измерения не показывают такого замедления

def x():
    height,width,numberOfBands=1401,801,6
    before = time.time()
    for i in range(height * width):
        for j in range(numberOfBands):
            pass
    print (time.time()-before)

>>> x()
0.937999963760376

EDITED

1 голос
/ 02 сентября 2011

Стандартный PIL

Чтобы загрузить изображение из файла, используйте функцию открытия в модуле изображения.

>>> import Image
>>> im = Image.open("lena.ppm")

В случае успеха эта функция возвращаетОбъект изображения.Теперь вы можете использовать атрибуты экземпляра для проверки содержимого файла.

>>> print im.format, im.size, im.mode
PPM (512, 512) RGB

Атрибут формата определяет источник изображения.Если изображение не было прочитано из файла, для него установлено значение Нет.Атрибут size представляет собой 2-кортеж, содержащий ширину и высоту (в пикселях).Атрибут mode определяет количество и названия полос в изображении, а также тип и глубину пикселей.Обычными режимами являются «L» (яркость) для изображений в оттенках серого, «RGB» для изображений в истинном цвете и «CMYK» для изображений перед печатью.

Библиотека изображений Python также позволяет работать с отдельными полосамимногополосного изображения, такого как изображение RGB.Метод разделения создает набор новых изображений, каждое из которых содержит одну полосу из исходного многоканального изображения.Функция слияния принимает режим и кортеж изображений и объединяет их в новое изображение.В следующем примере три полосы RGB-изображения меняются местами:

Разделение и объединение полос

r, g, b = im.split()
im = Image.merge("RGB", (b, g, r))

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

PIL со Spectral Python (модуль SPy Python)

Однако, как вы указали в своих комментариях ниже, вы не имеете дело с обычным RGB-изображением с 3 полосами.Таким образом, чтобы справиться с этим, SpectralPython (чистый модуль Python, который требует PIL) может быть просто то, что вы ищете.

В частности - http://spectralpython.sourceforge.net/class_func_ref.html#spectral.io.bipfile.BipFile

spectral.io.bipfile.BipFile сделокс файлами изображений в формате Band Interleaved Pixel (BIP).

Надеюсь, это поможет.

...