Улучшение производительности преобразования 10-в-8-бит - PullRequest
0 голосов
/ 03 июля 2018

У меня есть файл изображения в градациях серого с 10-битными данными. 10 бит сохраняются более 2 байтов, выровнены по младшему разряду (10 бит Значение 0b10 0000 1111 сохраняется как 0x020F.

Я хочу преобразовать это в 8 бит, сохраняя самый старший байт.

def convert_10bitTo8Bit(tenBitData):
    output_size = int(len(tenBitData) / 2)
    eightBitData = bytearray(output_size)
    for i in range(output_size):
        lowbyte, highbyte = tenBitData[i * 2 + 1], tenBitData[i * 2]
        value = (highbyte << 8) + lowbyte
        value = (value >> 2) & 0xff
        eightBitData[i] = value
    return eightBitData

Это работает, но довольно медленно: для образа размером 3 МБ на моем компьютере разработчика требуется около 0,5 секунды и> более 8 секунд на устройстве, на котором предполагается запускать (система ARM, аналогичная производительности PI).

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

$ python3 ImageTools.py
     5 function calls in 8.560 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    8.560    8.560 <string>:1(<module>)
     1    8.559    8.559    8.559    8.559 ImageTools.py:11(convert_10bitTo8Bit)
     1    0.000    0.000    8.560    8.560 {built-in method builtins.exec}
     1    0.000    0.000    0.000    0.000 {built-in method builtins.len}
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Как я могу улучшить производительность?

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Вы можете улучшить производительность, векторизовав операции, используя numpy:

# Store byte pairs as columns.
# If `tenBitData` is a `bytes` object, then use `np.fromiter` instead.
>>> data = np.asarray(tenBitData, dtype=np.uint8).reshape(-1, 2)

# Now we apply vectorized conversion.
>>> (data[:, 0] << 6) + (data[:, 1] >> 2)

При тестировании на моем компьютере (данные 4 МБ) я получаю следующее время:

Conversion: 3.044390e-01s
Function: 1.002173e+00s
Numpy: 7.728000e-03s

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

0 голосов
/ 03 июля 2018

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

def convert_8bitTo10Bit(tenBitData):
    eightBitData = bytearray()
    while tenBitData:
        eightBitData.insert(0,((tenBitData.pop() | (tenBitData.pop() << 8)) >> 2 & 0xFF))
    return eightBitData
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...