optical_flow.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env python
  2. '''
  3. This sample using FlowNet v2 model to calculate optical flow.
  4. Original paper: https://arxiv.org/abs/1612.01925.
  5. Original repo: https://github.com/lmb-freiburg/flownet2.
  6. Download the converted .caffemodel model from https://drive.google.com/open?id=16qvE9VNmU39NttpZwZs81Ga8VYQJDaWZ
  7. and .prototxt from https://drive.google.com/file/d/1RyNIUsan1ZOh2hpYIH36A-jofAvJlT6a/view?usp=sharing.
  8. Otherwise download original model from https://lmb.informatik.uni-freiburg.de/resources/binaries/flownet2/flownet2-models.tar.gz,
  9. convert .h5 model to .caffemodel and modify original .prototxt using .prototxt from link above.
  10. '''
  11. import argparse
  12. import os.path
  13. import numpy as np
  14. import cv2 as cv
  15. class OpticalFlow(object):
  16. def __init__(self, proto, model, height, width):
  17. self.net = cv.dnn.readNetFromCaffe(proto, model)
  18. self.net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
  19. self.height = height
  20. self.width = width
  21. def compute_flow(self, first_img, second_img):
  22. inp0 = cv.dnn.blobFromImage(first_img, size=(self.width, self.height))
  23. inp1 = cv.dnn.blobFromImage(second_img, size=(self.width, self.height))
  24. self.net.setInput(inp0, "img0")
  25. self.net.setInput(inp1, "img1")
  26. flow = self.net.forward()
  27. output = self.motion_to_color(flow)
  28. return output
  29. def motion_to_color(self, flow):
  30. arr = np.arange(0, 255, dtype=np.uint8)
  31. colormap = cv.applyColorMap(arr, cv.COLORMAP_HSV)
  32. colormap = colormap.squeeze(1)
  33. flow = flow.squeeze(0)
  34. fx, fy = flow[0, ...], flow[1, ...]
  35. rad = np.sqrt(fx**2 + fy**2)
  36. maxrad = rad.max() if rad.max() != 0 else 1
  37. ncols = arr.size
  38. rad = rad[..., np.newaxis] / maxrad
  39. a = np.arctan2(-fy / maxrad, -fx / maxrad) / np.pi
  40. fk = (a + 1) / 2.0 * (ncols - 1)
  41. k0 = fk.astype(np.int)
  42. k1 = (k0 + 1) % ncols
  43. f = fk[..., np.newaxis] - k0[..., np.newaxis]
  44. col0 = colormap[k0] / 255.0
  45. col1 = colormap[k1] / 255.0
  46. col = (1 - f) * col0 + f * col1
  47. col = np.where(rad <= 1, 1 - rad * (1 - col), col * 0.75)
  48. output = (255.0 * col).astype(np.uint8)
  49. return output
  50. if __name__ == '__main__':
  51. parser = argparse.ArgumentParser(description='Use this script to calculate optical flow using FlowNetv2',
  52. formatter_class=argparse.ArgumentDefaultsHelpFormatter)
  53. parser.add_argument('-input', '-i', required=True, help='Path to input video file. Skip this argument to capture frames from a camera.')
  54. parser.add_argument('--height', default=320, type=int, help='Input height')
  55. parser.add_argument('--width', default=448, type=int, help='Input width')
  56. parser.add_argument('--proto', '-p', default='FlowNet2_deploy_anysize.prototxt', help='Path to prototxt.')
  57. parser.add_argument('--model', '-m', default='FlowNet2_weights.caffemodel', help='Path to caffemodel.')
  58. args, _ = parser.parse_known_args()
  59. if not os.path.isfile(args.model) or not os.path.isfile(args.proto):
  60. raise OSError("Prototxt or caffemodel not exist")
  61. winName = 'Calculation optical flow in OpenCV'
  62. cv.namedWindow(winName, cv.WINDOW_NORMAL)
  63. cap = cv.VideoCapture(args.input if args.input else 0)
  64. hasFrame, first_frame = cap.read()
  65. divisor = 64.
  66. var = {}
  67. var['ADAPTED_WIDTH'] = int(np.ceil(args.width/divisor) * divisor)
  68. var['ADAPTED_HEIGHT'] = int(np.ceil(args.height/divisor) * divisor)
  69. var['SCALE_WIDTH'] = args.width / float(var['ADAPTED_WIDTH'])
  70. var['SCALE_HEIGHT'] = args.height / float(var['ADAPTED_HEIGHT'])
  71. config = ''
  72. proto = open(args.proto).readlines()
  73. for line in proto:
  74. for key, value in var.items():
  75. tag = "$%s$" % key
  76. line = line.replace(tag, str(value))
  77. config += line
  78. caffemodel = open(args.model, 'rb').read()
  79. opt_flow = OpticalFlow(bytearray(config.encode()), caffemodel, var['ADAPTED_HEIGHT'], var['ADAPTED_WIDTH'])
  80. while cv.waitKey(1) < 0:
  81. hasFrame, second_frame = cap.read()
  82. if not hasFrame:
  83. break
  84. flow = opt_flow.compute_flow(first_frame, second_frame)
  85. first_frame = second_frame
  86. cv.imshow(winName, flow)