Цикл большого стека .tif (растровое изображение) и извлечение позиций - PullRequest
0 голосов
/ 28 апреля 2018

Я хочу пробежать через большой стек tif +1500 кадров и извлечь координаты локальных максимумов для каждого кадра. Приведенный ниже код делает работу, однако очень медленно работает с большими файлами. При работе с меньшими битами (например, 20 кадров) каждый кадр выполняется почти мгновенно - при работе со всем набором данных каждый кадр занимает секунды.

Какие-нибудь решения для запуска более быстрого кода? Я полагаю, что это связано с загрузкой большого файла TIFF - однако это должно быть необходимо только один раз изначально?

My data looks like this - bright dots on a dark background

У меня есть следующий код:

from pims import ImageSequence
from skimage.feature import peak_local_max

def cmask(index,array):
  radius = 3
  a,b = index
  nx,ny = array.shape
  y,x = np.ogrid[-a:nx-a,-b:ny-b]
  mask = x*x + y*y <= radius*radius

  return(sum(array[mask])) # number of pixels

images = ImageSequence('tryhard_red_small.tif')


frame_list = []
x = []
y = []
int_liposome = []
BG_liposome = []

for i in range(len(images[0])):
    tmp_frame = images[0][i]

    xy = pd.DataFrame(peak_local_max(tmp_frame, min_distance=8,threshold_abs=3000))
    x.extend(xy[0].tolist())
    y.extend(xy[1].tolist())

    for j in range(len(xy)):
        index = x[j],y[j]    
        int_liposome.append(cmask(index,tmp_frame))

    frame_list.extend([i]*len(xy))
    print "Frame: ", i, "of ",len(images[0])

features = pd.DataFrame(
        {'lip_int':int_liposome,
         'y'  : y,
         'x'  : x,
         'frame'  : frame_list})

1 Ответ

0 голосов
/ 28 апреля 2018

Вы пробовали профилировать код, скажем, с %prun или %lprun в ipython? Это точно скажет вам, где происходят ваши замедления.

Я не могу сделать свою собственную версию этого без стека tif, но я подозреваю, что проблема в том, что вы используете списки для хранения всего. Каждый раз, когда вы делаете добавление или расширение, python вынужден выделять больше памяти. Вы можете сначала попытаться получить общее количество максимумов, затем распределить выходные массивы, а затем выполнить повторный запуск, чтобы заполнить массивы. Что-то вроде ниже

# run through once to get the count of local maxima
npeaks = (len(peak_local_max(f, min_distance=8, threshold_abs=3000))
          for f in images[0])
total_peaks = sum(npeaks)

# allocate storage arrays and rerun
x = np.zeros(total_peaks, np.float)
y = np.zeros_like(x)
int_liposome = np.zeros_like(x)
BG_liposome = np.zeros_like(x)

frame_list = np.zeros(total_peaks, np.int)
index_0 = 0
for frame_ind, tmp_frame in enumerate(images[0]):
    peaks = pd.DataFrame(peak_local_max(tmp_frame, min_distance=8,threshold_abs=3000))
    index_1 = index_0 + len(peaks)
    # copy the data from the DataFrame's underlying numpy array
    x[index_0:index_1] = peaks[0].values
    y[index_0:index_1] = peaks[1].values
    for i, peak in enumerate(peaks, index_0):
        int_liposome[i] = cmask(peak, tmp_frame)
    frame_list[index_0:index_1] = frame_ind
    # update the starting index
    index_0 = index_1
    print "Frame: ", frame_ind, "of ",len(images[0])
...