Нормализация яркости/гистограммы для интервальных изображений

Я работаю в лаборатории, и мы часто делаем таймлапс-серии (изображение каждый час) стволовых клеток. Текущая идея состоит в том, чтобы собрать все кадры вместе и сделать видео, показывающее эти растущие клетки (аналогично этому youtube. видео). Что можно сделать просто и круто, используя OpenCV + Python.

import numpy as np
import os
import cv2

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

timelapse_folder = '../myTimeLapse/'

for file in os.listdir(timelapse_folder):
    frame = cv2.imread(timelapse_folder+file, 0)
    out.write(frame)

out.release()

Но у нас есть проблема, что все изображения немного различаются по яркости, поэтому мы получаем мерцание в нашем выходном видео.

Мне не разрешено загружать видео, но вот несколько простых примеров, сгенерированных с помощью gimp для визуализации проблемы:

Это видео, которое я получаю из кадров

введите здесь описание изображения

и это мое желаемое видео (было бы также здорово минимизировать мерцание, а не удалять его полностью)

введите здесь описание изображения

Есть ли способ настроить гистограмму или яркость для всех изображений (или, может быть, между двумя изображениями), чтобы удалить мерцание с помощью OpenCV?

Спасибо за каждую идею или подсказку!

Изменить: последовательность gif, созданная по идее Эндрю (ответ ниже)

введите здесь описание изображения


person Fabian    schedule 07.09.2016    source источник
comment
Предполагая, что все изображения представляют собой двумерные массивы с плавающей запятой/целые числа, тогда вы можете создать трехмерный массив всех изображений, а затем нормализовать их по самым ярким (max(np.average(arr, axis=2))). Затем вы проходите и пишете на видео?   -  person Andrew    schedule 07.09.2016
comment
Эй, я попробовал max_avg = np.max(np.average(images, axis=2)), а затем в цикле for для каждого кадра frame = (frame/max_avg)*255, но это не устраняет мерцание. Или вы имеете в виду другой тип нормализации?   -  person Fabian    schedule 07.09.2016


Ответы (2)


Если ваши данные находятся в трехмерном массиве, вам не нужно перебирать их, чтобы сделать это. Имея 5 изображений, скажем, 256 x 256, вы сможете построить массив, равный arr.shape == (256, 256, 5). Я думаю, что мой первоначальный комментарий был немного неправильным, но приведенный ниже пример должен это сделать.

target_array = []

for file in os.listdir(timelapse_folder):
    frame = cv2.imread(timelapse_folder+file, 0)
    if target_array:#Not entirely happy with this, but it should work
        target_array = np.dstack((target_array, frame))
    elif not target_array:
        target_array = np.asarray(frame)
target_array = target_array / np.max(target_array)
#target_array *= 255 #If you want an intensity value with a more common range here  
for idx in xrange(target_array.shape[2]):
    out.write(target_array[:, :, idx])

РЕДАКТИРОВАТЬ: я использовал эту страницу чтобы сгладить некоторые перегибы с адресацией 3D-массива

person Andrew    schedule 07.09.2016
comment
Если у вас есть проблемы с мерцанием, вы можете добавить интерполированный срез между каждым из ваших срезов данных, который находится посередине между двумя кадрами, что уменьшит видимый эффект мерцания. Не уверен, что функция сглаживания будет работать, в зависимости от количества кадров. - person Andrew; 07.09.2016
comment
Эй, я попробовал ваше решение, выполняющее такую ​​нормализацию между изображениями и добавляющее переходы (интерполированный фрагмент), и теперь оно выглядит нормально. Нормализация немного устраняет мерцание, но у меня есть некоторые проблемы с интерполированным срезом, потому что ячейки иногда недостаточно близки, и это выглядит очень размытым. Я добавлю гифку, созданную с идеей вашего ответа на мой вопрос, но я подожду с принятием - может быть, у кого-то есть другая идея. В противном случае приму через пару дней. Большое спасибо. - person Fabian; 07.09.2016
comment
Если гладкость является приоритетом, вы всегда можете добавить несколько интерполированных срезов, что можно сделать во время dstack, определив количество интерполированных срезов, а затем создав это количество массивов. Затем вы можете выбрать линейный или логарифмический шаг (может быть, нормальное распределение с 11 срезами даст оптимальную гладкость?). Очевидно, что ваши реальные данные будут численно превосходить 11:1 или около того, но до тех пор, пока вы откровенны об этом с учеными, которые их увидят, я не вижу никаких проблем. - person Andrew; 07.09.2016
comment
если у вас есть белый пиксель (255), вы, по сути, будете делить, а затем умножать на 255 - вообще ничего не меняя... - person Frank Musteman; 25.02.2020

Являются ли эти изображения значениями RGB или оттенков серого? Я бы просто выполнил нормализацию в вашем цикле после чтения каждого кадра:

frame = frame/np.max(frame)

В случае значений серого каждое изображение должно иметь значения от 0 до 1, но в зависимости от того, как выглядят ваши изображения, вы также можете попробовать другие нормализации, например. используя np.median или np.mean вместо np.max.

person a.smiet    schedule 07.09.2016
comment
Я попробовал это, но разница в яркости между всеми изображениями сохраняется. Я думаю, что мне нужно уважать среднее значение всех изображений, как написал Эндрю в своем комментарии, но я не знаю, как я могу перевести среднее значение для каждого кадра в среднее значение всех кадров. Ты знаешь, что я имею в виду? - person Fabian; 07.09.2016
comment
Думаю, я понимаю вашу проблему. У вас есть какие-то объекты, которые вы можете отделить от фона в своих кадрах (например, с помощью простого порога)? Таким образом, вы можете попытаться настроить только фон всех кадров. Например: возьмите среднее значение фона произвольного кадра в качестве эталона и сдвиньте все остальные кадры так, чтобы средние значения их фона соответствовали эталону. - person a.smiet; 07.09.2016
comment
Есть ли простой метод numpy или cv2 для смещения этих значений кадра? Ячейки не полностью белые, поэтому я думаю, что если я настрою только фон, я получу мерцающие ячейки (передний план). В более поздних изображениях с более высокой конфлюэнтностью (много ячеек) я не могу отделить фон, потому что есть только мерцающие ячейки, расположенные очень близко друг к другу. - person Fabian; 07.09.2016
comment
Хм... Если простая нормализация не работает, то кажется, что у вас непостоянные различия между ячейками и фоном в каждом кадре, т.е. у вас всегда будет мерцание, либо на переднем плане, либо на заднем плане... Может быть, вы могли бы поиграться с выравниванием гистограммы и выяснить, поможет ли это как-то? См. opencv-python-tutroals.readthedocs .io/en/latest/py_tutorials/ - person a.smiet; 07.09.2016