Jaki byłby najszybszy/efektywny pod względem pamięci sposób na uzyskanie średniej z wielu ramek 16-bitowego obrazu TIFF w postaci tablicy numpy?Uśrednianie na wielostronicowych stronach TIFF w Pythonie
Do tej pory podałem kod podany poniżej. Ku mojemu zaskoczeniu metoda 2 była szybsza niż metoda1.
Ale dla profilowania nigdy nie zakładaj, przetestuj to! Tak więc chcę przetestować więcej. Warto spróbować Wand? Nie uwzględniłem tutaj, ponieważ po zainstalowaniu ImageMagick-6.8.9-Q16 i MAGICK_HOME env var nadal nie importuje ... Dowolna inna biblioteka dla tiff wielostronicowych w Pythonie? GDAL może trochę za dużo na to.
(edycja) Dołączyłem libtiff. Nadal metoda2 najszybsza i dość wydajna pod względem pamięci.
from time import time
#import cv2 ## no multi page tiff support
import numpy as np
from PIL import Image
#from scipy.misc import imread ## no multi page tiff support
import tifffile # http://www.lfd.uci.edu/~gohlke/code/tifffile.py.html
from libtiff import TIFF # https://code.google.com/p/pylibtiff/
fp = r"path/2/1000frames-timelapse-image.tif"
def method1(fp):
'''
using tifffile.py by Christoph (Version: 2014.02.05)
(http://www.lfd.uci.edu/~gohlke/code/tifffile.py.html)
'''
with tifffile.TIFFfile(fp) as imfile:
return imfile.asarray().mean(axis=0)
def method2(fp):
'primitive peak memory friendly way with tifffile.py'
with tifffile.TIFFfile(fp) as imfile:
nframe, h, w = imfile.series[0]['shape']
temp = np.zeros((h,w), dtype=np.float64)
for n in range(nframe):
curframe = imfile.asarray(n)
temp += curframe
return (temp/nframe)
def method3(fp):
' like method2 but using pillow 2.3.0 '
im = Image.open(fp)
w, h = im.size
temp = np.zeros((h,w), dtype=np.float64)
n = 0
while True:
curframe = np.array(im.getdata()).reshape(h,w)
temp += curframe
n += 1
try:
im.seek(n)
except:
break
return (temp/n)
def method4(fp):
'''
https://code.google.com/p/pylibtiff/
documentaion seems out dated.
'''
tif = TIFF.open(fp)
header = tif.info()
meta = dict() # extracting meta
for l in header.splitlines():
if l:
if l.find(':')>0:
parts = l.split(':')
key = parts[0]
value = ':'.join(parts[1:])
elif l.find('=')>0:
key, value =l.split('=')
meta[key] = value
nframes = int(meta['frames'])
h = int(meta['ImageLength'])
w = int(meta['ImageWidth'])
temp = np.zeros((h,w), dtype=np.float64)
for frame in tif.iter_images():
temp += frame
return (temp/nframes)
t0 = time()
avgimg1 = method1(fp)
print time() - t0
# 1.17-1.33 s
t0 = time()
avgimg2 = method2(fp)
print time() - t0
# 0.90-1.53 s usually faster than method1 by 20%
t0 = time()
avgimg3 = method3(fp)
print time() - t0
# 21 s
t0 = time()
avgimg4 = method4(fp)
print time() - t0
# 1.96 - 2.21 s # may not be accurate. I got warning for every frame with the tiff file I tested.
np.testing.assert_allclose(avgimg1, avgimg2)
np.testing.assert_allclose(avgimg1, avgimg3)
np.testing.assert_allclose(avgimg1, avgimg4)
[ 'pylibtiff'] (https://code.google.com/p/pylibtiff/) pozwala także iteracyjne na stronach wielostronicowego pliku TIFF, jak będzie [' PIL. ImageSequence'] (http://effbot.org/imagingbook/imagesequence.htm). –
Jeśli naprawdę nie masz wielu klatek i są one bardzo małe, zapętlenie w Pythonie przez ramki nie będzie dużym czynnikiem w twoim czasie pracy. Jak dowiedziałeś się z metody 1, zapisanie wszystkich klatek do pamięci jednocześnie okazało się wolniejsze, nawet jeśli pętla następowała w C. Nie sądzę, że znajdziesz coś działającego znacznie lepiej niż twoja metoda2. – Jaime
Powinienem spróbować pylibtiff. Metoda 2 wydaje się wtedy wystarczająco dobra. ale tego nie byłem tak dobry, aby usłyszeć od innych. Dzięki! – otterb