Skip to content

Instantly share code, notes, and snippets.

@larryhou
Created April 23, 2022 08:13
Show Gist options
  • Save larryhou/dd13ed1b7826108efe32d2258fd5612c to your computer and use it in GitHub Desktop.
Save larryhou/dd13ed1b7826108efe32d2258fd5612c to your computer and use it in GitHub Desktop.
convert CT sequene into movie
#!/usr/bin/env python3
import argparse
import os
import re
import sys
from PIL import Image
def main():
arguments = argparse.ArgumentParser()
arguments.add_argument('--file', '-f', nargs='+', required=True, help='CT image files')
arguments.add_argument('--cols', '-c', type=int, required=True, help='number of images on row')
arguments.add_argument('--rows', '-r', type=int, required=True, help='number of images on column')
arguments.add_argument('--left', '-l', type=int, default=0, help='left margin')
arguments.add_argument('--top', '-t', type=int, default=0, help='top margin')
arguments.add_argument('--right', '-i', type=int, default=0, help='right margin')
arguments.add_argument('--bottom', '-b', type=int, default=0, help='bottom margin')
arguments.add_argument('--debug', '-d', action='store_true', help='debug mode')
options = arguments.parse_args(sys.argv[1:])
shift = 5
white = (240,240,240)
black = (10,10,10)
for filename in options.file:
img = Image.open(filename)
pix = img.load()
w, h = img.size # type: int, int
dx = (w - options.left - options.right) // options.cols
dy = (h - options.top - options.bottom) // options.rows
num = 1
prefix = re.sub(r'\.[^.]+$', '', filename)
locY = options.top
for r in range(options.rows):
locX = options.left
for c in range(options.cols):
posY = locY + 10
posX = locX
c0 = pix[locX, posY]
if c0 < black:
dirty = False
for x in range(max(locX-shift, 0), locX):
c1 = pix[x, posY]
if c1 >= white:
posX = x
dirty = True
break
if not dirty:
for x in range(locX, locX+shift):
c1 = pix[x, posY]
if c1 >= white:
posX = x
break
if pix[posX, posY] >= white:
available = True
for y in range(locY, posY):
if pix[posX,y] < white: available = False
if available:
for x in range(posX, posX+shift):
if pix[x, posY] < white:
locX = x
break
rit = min(locX + dx, w)
bot = min(locY + dy, h)
frame = img.crop((locX, locY, rit, bot))
canvas = Image.new('RGBA', ((dx + 1) // 2 * 2, (dy + 1) // 2 * 2))
canvas.paste(frame, (0, 0))
output = '{}_{:03d}.tga'.format(prefix, num)
canvas.save(output)
for y in range(locY, bot):
pix[locX,y] = (0xFF,0,0)
for x in range(locX, rit):
pix[x,locY] = (0xFF,0,0)
num += 1
locX += dx
locY += dy
command = 'ffmpeg -framerate 6 -i {0}_%03d.tga -crf 1 -c:v libx264 -pix_fmt yuv420p -y {0}.mp4'.format(prefix)
print('++ {}'.format(command))
assert os.system(command) == 0
os.system('rm -f {}_*.tga'.format(prefix))
if options.debug: img.save('{}.tga'.format(prefix))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment