pythonopencvtimelapse

Brightness/Histogram normalization for time lapse images


I'm working in a laboratory and we often make time lapse series (image every hour) of stem cells. The current idea is to put all frames together and make a video showing this growing cells (similar to this youtube video). Which could done simple and cool using 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()

But we have the problem, that all images vary a little bit in brightness, so we get some flickering in our output video.

I'm not allowed to upload the videos but here are some simple examples generated with gimp to visualize the problem:

That's the video I get from the frames

enter image description here

and that's my desired video (it would be also great to minimize the flickering instead of removing it completely)

enter image description here

Is there a way to adjust the histogram or brightness over all images (or maybe between 2 images) to remove those flickering using OpenCV?

Thanks for every idea or hint!

Edit: The gif sequence produced by Andrew's idea (Answer below)

enter image description here


Solution

  • If your data is in a 3D array, you shouldn't need to loop over it to do this. With 5 images of, say 256 x 256, you should be able to construct an array that is arr.shape == (256, 256, 5). My initial comment was a little off I think, but the below example should do it.

    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])
    

    EDIT: I used this page to iron out some kinks with addressing the 3D array