В настоящее время я работаю над сценарием Python 3.5 для преобразования изображения BMP (или любого пиксельного массива) в изображение GIF.Я хотел бы сделать это без использования тяжелых модулей Python, таких как Numpy или Pillow, я работаю в квази чистом Python.Чтобы добиться этого, мне нужно уменьшить количество цветов до 256 и применить дизеринг к пикселю.У меня уже есть полностью работающий скрипт, но он очень медленный (около 3 с для изображения 570x370 и около 30 с для изображения 1900x1100), и это недопустимо: -)
Вот код, который я сделал.«px» - это массив [высота] x [ширина] x [3 цвета], созданный следующим образом:
px = []
for i in range(height):
px.append([[0,0,0]]*width)
и заполненный значениями bmp (например, px [10] [12] = [101,203,255)])
С помощью этого кода выполняется уменьшение цвета и сглаживание (с помощью Sierra Lite Dithering http://www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/):
data=bytearray(height*width) # Output data array
i = 0
for ligne in range(height):
for col in range(width):
[R,G,B] = px[ligne][col] # Get colors of pixel
Idx = GetColorIdx(R,G,B) # Get table index of nearest color
data[i] = Idx # Store index
i += 1
[Rnew,Gnew,Bnew] = GetIdxColor(Idx) # Get colors of table index
e = (R+G+B)/3-(Rnew+Gnew+Bnew)/3 # error between colors
# Error diffusion on nearest pixels if available
if col < width-1:
[R,G,B] = px[ligne][col+1]
px[ligne][col+1] = [clip(R+e/2),clip(G+e/2),clip(B+e/2)]
if ligne < height-1:
if col > 0:
[R,G,B] = px[ligne+1][col-1]
px[ligne+1][col-1] = [clip(R+e/4),clip(G+e/4),clip(B+e/4)]
[R,G,B] = px[ligne+1][col]
px[ligne+1][col] = [clip(R+e/4),clip(G+e/4),clip(B+e/4)]
Вот дополнительные функции:
# 256 8-8-4 color palette inspired from
# https://en.wikipedia.org/wiki/List_of_software_palettes#8-8-4_levels_RGB
def GetColorIdx(R,G,B): # Get color index from RGB colors
return round(R/36.5)+round(G/36.5)*8+round(B/85)*64
def GetIdxColor(Idx): # Get RGB colors from table index
R=int(Idx%8*36.5)
G=int(Idx//8%8*36.5)
B=int(Idx//64*85)
return [R,G,B]
def clip(n): # Trim n between 0 and 255
if n<0: return 0
elif n>255: return 255
return round(n)
Очень медленная часть - это двойная петля for вокруг ширины и высоты. Есть ли у вас какие-либо идеи, как улучшить это в чистом питоне? Я пробовал несколько вещей, таких как использование dict вместо list, кодирование цвета на 3байт вместо 3 значений, но это не имеет никакого реального эффекта ...
После этой части идет часть кодирования и записи gif. Я думаю, что это тоже можно улучшить, но это будет следующий шаг ^^
Спасибо !!