diff --git a/ProcessInputDir.sh b/ProcessInputDir.sh new file mode 100644 index 0000000..8780966 --- /dev/null +++ b/ProcessInputDir.sh @@ -0,0 +1,19 @@ +#! /bin/sh -f +rm -rf ${1}/tmp +rm -rf ${1}/tmpOutput +mkdir ${1}/tmp +mkdir ${1}/tmpOutput + +python timeLapseRegistrator.py --glob "*.jpg" --convert /c/Program\ Files/ImageMagick-7.0.3-Q16/convert.exe --maskFile ${1}/mask.jpg --tmpDir ${1}/tmp ${1}/input ${1}/tmpOutput +python timeLapseOpticFlowInterpolator.py --glob "*_RegAtlas.png" --interp /c/src/TimeLapse-OpticalFlow-Release/InterpByOpticalFlow.exe ./${1}/tmpOutput +python timeLapseMovieMaker.py --convert /c/Program\ Files/ImageMagick-7.0.3-Q16/convert.exe --glob "*_RegAtlas_?.png" ${1}/tmpOutput ${1}/movie.gif +convert -coalesce ${1}/movie.gif ${1}/tmp/movie%04d.png +ffmpeg -r 10 -i ${1}/tmp/movie%04d.png -vcodec mpeg4 -y ${1}/movie.mp4 + +rm -rf ${1}/tmpOutputOrg +cp -r ${1}/input ${1}/tmpOutputOrg + +python timeLapseOpticFlowInterpolator.py --glob "*.jpg" --interp /c/src/TimeLapse-OpticalFlow-Release/InterpByOpticalFlow.exe ${1}/tmpOutputOrg +python timeLapseMovieMaker.py --convert /c/Program\ Files/ImageMagick-7.0.3-Q16/convert.exe --glob "*_?.jpg" ${1}/tmpOutputOrg ${1}/movie-org.gif +convert -coalesce ${1}/movie-org.gif ${1}/tmpOutputOrg/movie-org%04d.png +ffmpeg -r 10 -i ${1}/tmpOutputOrg/movie-org%04d.png -vcodec mpeg4 -y ${1}/movie-org.mp4 diff --git a/README.md b/README.md index b583eb5..8b8cd03 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# TimeLapse-OpticalFlow \ No newline at end of file +# TimeLapse-OpticalFlow + +This repo currently consists of: +* Two small c++ programs: one for registering two images, one for interpolating between two registered images +* A python wrapper script to create a TimeLapse from a set of images + +C++ build dependencies are ITK and OpenCV. + +Locations of some programs/data are hard-coded in the Python wrapper, those will need to be changed depending on where its running. diff --git a/timeLapseMovieMaker.py b/timeLapseMovieMaker.py new file mode 100644 index 0000000..c04a005 --- /dev/null +++ b/timeLapseMovieMaker.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +# This program will convert sequence of images into a movie + +import os +import imp +import fnmatch +import argparse +from subprocess import run + +def ApplyTimeLapseMovieMaker( convert, folder, glob, speed, movie ): + command_string = [convert, "-delay", speed, "-loop", "0"] + for root, dirnames, filenames in os.walk( folder ): + for filename in fnmatch.filter( filenames, glob ): + command_string.append( str( os.path.join( root, filename ) ) ) + break # Only use files in top level subdir + command_string.append( movie ) + + print( command_string ) + + run( command_string ) + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Apply timeLapseMovieMaker to files in a folder.' ) + parser.add_argument( 'folder', help='Folder to apply the script to.' ) + parser.add_argument( 'movie', help='Output movie name.' ) + parser.add_argument( '--convert', + help='Path to the convert executable from ImageMagick.', + default='convert' ) + parser.add_argument( '--glob', + help='Glob to find files recursively in the given folder.', + default='*.???' ) + parser.add_argument( '--speed', + help='playback speedup.', + default='10' ) + args = parser.parse_args() + ApplyTimeLapseMovieMaker( args.convert, args.folder, args.glob, + args.speed, args.movie ) diff --git a/timeLapseOpticFlowInterpolator.py b/timeLapseOpticFlowInterpolator.py new file mode 100644 index 0000000..f738788 --- /dev/null +++ b/timeLapseOpticFlowInterpolator.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +import os +import fnmatch +import argparse +import shutil as sh +from subprocess import run + +def ApplyTimeLapseOpticFlowInterpolator(folder, glob, interp): + file_list = [] + for root, dirnames, filenames in os.walk(folder): + for filename in fnmatch.filter(filenames, glob): + file_list.append(os.path.join(root, filename)) + break # only use files in first subdir + number_of_files = len(file_list) + print("Number of files = " + str(number_of_files)) + for i, input_file in enumerate(file_list): + fileName1 = input_file + if i0: + tmpCurFile = tmpDir + "/" + filename_list[i] + outCurFile = outDir + "/" + filename_list[i] + + preTransformFile = tmpDir + "/" + filename_list[i-1] + "_RegAtlas.tfm" + + # Blend color channels using basis + run( [convert, "-separate", curFile, tmpDir+"/base.png" ] ) + run( ["EnhanceUsingDiscriminantAnalysis", + "--loadBasisInfo", tmpDir+"/basis.mlda", + "--objectId", "255,127", + tmpDir + "/base-0.png," + \ + tmpDir + "/base-1.png," + \ + tmpDir + "/base-2.png", + tmpDir + "/cur"] ) + run( ["ImageMath", tmpDir+"/cur.basis00.mha", + "-b", edge_scale, + "-w", tmpDir + "/curB.mha"] ) + + # Register the current image (blurred) to the atlas + run( ["RegisterImages", tmpDir+"/AtlasB.mha", + tmpDir+"/curB.mha", + "--resampledImage", tmpCurFile + "_RegAtlasB.mha", + "--saveTransform", tmpCurFile + "_RegAtlas.tfm", + "--registration", "Affine", + "--loadTransform", preTransformFile, + "--initialization", "None", + "--expectedRotation", "0.001", + "--expectedScale", "0.01", + "--expectedSkew", "0.0001", + "--expectedOffset", "60", + "--fixedImageMask", regMaskFile, + "--affineSamplingRatio", "0.5", + "--affineMaxIterations", "1000", + "--rigidSamplingRatio", "0.5", + "--rigidMaxIterations", "1000"] ) + #"--metric", "MeanSqrd", + + # Apply the image to atlas transform to the current image (raw) + run( ["RegisterImages", atlasFile, + tmpDir+"/base-0.png", + "--resampledImage", tmpDir+"/RegAtlas-0.mha", + "--loadTransform",tmpCurFile + "_RegAtlas.tfm", + "--registration", "None", + "--initialization", "None", + "--rigidMaxIterations", "0"] ) + run( ["RegisterImages", tmpDir+"/AtlasB.mha", + tmpDir+"/base-1.png", + "--resampledImage", tmpDir+"/RegAtlas-1.mha", + "--loadTransform",tmpCurFile + "_RegAtlas.tfm", + "--registration", "None", + "--initialization", "None", + "--rigidMaxIterations", "0"] ) + run( ["RegisterImages", tmpDir+"/AtlasB.mha", + tmpDir+"/base-2.png", + "--resampledImage", tmpDir+"/RegAtlas-2.mha", + "--loadTransform",tmpCurFile + "_RegAtlas.tfm", + "--registration", "None", + "--initialization", "None", + "--rigidMaxIterations", "0"] ) + run( ["ImageMath", tmpDir+"/RegAtlas-0.mha", + "-W", "0", tmpDir+"/RegAtlas-0.png"] ) + run( ["ImageMath", tmpDir+"/RegAtlas-1.mha", + "-W", "0", tmpDir+"/RegAtlas-1.png"] ) + run( ["ImageMath", tmpDir+"/RegAtlas-2.mha", + "-W", "0", tmpDir+"/RegAtlas-2.png"] ) + run( [convert, "-combine", + tmpDir+"/RegAtlas-0.png", + tmpDir+"/RegAtlas-1.png", + tmpDir+"/RegAtlas-2.png", + "-colorspace", "sRGB", + "-type", "truecolor", + outCurFile + "_RegAtlas.png"] ) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Apply timeLapseRegistrator to files in a folder.' ) + parser.add_argument( 'inputFolder', help='Folder to apply the script to.' ) + parser.add_argument( 'outputFolder', help='Folder to save the results to.' ) + parser.add_argument( '--glob', + help='Glob to find files recursively in the given folder.', + default='*.???' ) + parser.add_argument( '--convert', + help='Path to the convert executable from ImageMagick.', + default='convert' ) + parser.add_argument( '--maskFile', help='File for masking ROI.', + default='mask.png' ) + parser.add_argument( '--tmpDir', help='Folder for Temp files.', + default='tmp' ) + args = parser.parse_args() + ApplyTimeLapseRegistrator( args.inputFolder, args.outputFolder, + args.glob, args.maskFile, args.tmpDir, args.convert )