video.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env python
  2. '''
  3. Video capture sample.
  4. Sample shows how VideoCapture class can be used to acquire video
  5. frames from a camera of a movie file. Also the sample provides
  6. an example of procedural video generation by an object, mimicking
  7. the VideoCapture interface (see Chess class).
  8. 'create_capture' is a convinience function for capture creation,
  9. falling back to procedural video in case of error.
  10. Usage:
  11. video.py [--shotdir <shot path>] [source0] [source1] ...'
  12. sourceN is an
  13. - integer number for camera capture
  14. - name of video file
  15. - synth:<params> for procedural video
  16. Synth examples:
  17. synth:bg=../data/lena.jpg:noise=0.1
  18. synth:class=chess:bg=../data/lena.jpg:noise=0.1:size=640x480
  19. Keys:
  20. ESC - exit
  21. SPACE - save current frame to <shot path> directory
  22. '''
  23. # Python 2/3 compatibility
  24. from __future__ import print_function
  25. import numpy as np
  26. from numpy import pi, sin, cos
  27. import cv2
  28. # built-in modules
  29. from time import clock
  30. # local modules
  31. import common
  32. class VideoSynthBase(object):
  33. def __init__(self, size=None, noise=0.0, bg = None, **params):
  34. self.bg = None
  35. self.frame_size = (640, 480)
  36. if bg is not None:
  37. self.bg = cv2.imread(bg, 1)
  38. h, w = self.bg.shape[:2]
  39. self.frame_size = (w, h)
  40. if size is not None:
  41. w, h = map(int, size.split('x'))
  42. self.frame_size = (w, h)
  43. self.bg = cv2.resize(self.bg, self.frame_size)
  44. self.noise = float(noise)
  45. def render(self, dst):
  46. pass
  47. def read(self, dst=None):
  48. w, h = self.frame_size
  49. if self.bg is None:
  50. buf = np.zeros((h, w, 3), np.uint8)
  51. else:
  52. buf = self.bg.copy()
  53. self.render(buf)
  54. if self.noise > 0.0:
  55. noise = np.zeros((h, w, 3), np.int8)
  56. cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
  57. buf = cv2.add(buf, noise, dtype=cv2.CV_8UC3)
  58. return True, buf
  59. def isOpened(self):
  60. return True
  61. class Chess(VideoSynthBase):
  62. def __init__(self, **kw):
  63. super(Chess, self).__init__(**kw)
  64. w, h = self.frame_size
  65. self.grid_size = sx, sy = 10, 7
  66. white_quads = []
  67. black_quads = []
  68. for i, j in np.ndindex(sy, sx):
  69. q = [[j, i, 0], [j+1, i, 0], [j+1, i+1, 0], [j, i+1, 0]]
  70. [white_quads, black_quads][(i + j) % 2].append(q)
  71. self.white_quads = np.float32(white_quads)
  72. self.black_quads = np.float32(black_quads)
  73. fx = 0.9
  74. self.K = np.float64([[fx*w, 0, 0.5*(w-1)],
  75. [0, fx*w, 0.5*(h-1)],
  76. [0.0,0.0, 1.0]])
  77. self.dist_coef = np.float64([-0.2, 0.1, 0, 0])
  78. self.t = 0
  79. def draw_quads(self, img, quads, color = (0, 255, 0)):
  80. img_quads = cv2.projectPoints(quads.reshape(-1, 3), self.rvec, self.tvec, self.K, self.dist_coef) [0]
  81. img_quads.shape = quads.shape[:2] + (2,)
  82. for q in img_quads:
  83. cv2.fillConvexPoly(img, np.int32(q*4), color, cv2.LINE_AA, shift=2)
  84. def render(self, dst):
  85. t = self.t
  86. self.t += 1.0/30.0
  87. sx, sy = self.grid_size
  88. center = np.array([0.5*sx, 0.5*sy, 0.0])
  89. phi = pi/3 + sin(t*3)*pi/8
  90. c, s = cos(phi), sin(phi)
  91. ofs = np.array([sin(1.2*t), cos(1.8*t), 0]) * sx * 0.2
  92. eye_pos = center + np.array([cos(t)*c, sin(t)*c, s]) * 15.0 + ofs
  93. target_pos = center + ofs
  94. R, self.tvec = common.lookat(eye_pos, target_pos)
  95. self.rvec = common.mtx2rvec(R)
  96. self.draw_quads(dst, self.white_quads, (245, 245, 245))
  97. self.draw_quads(dst, self.black_quads, (10, 10, 10))
  98. classes = dict(chess=Chess)
  99. presets = dict(
  100. empty = 'synth:',
  101. lena = 'synth:bg=../data/lena.jpg:noise=0.1',
  102. chess = 'synth:class=chess:bg=../data/lena.jpg:noise=0.1:size=640x480'
  103. )
  104. def create_capture(source = 0, fallback = presets['chess']):
  105. '''source: <int> or '<int>|<filename>|synth [:<param_name>=<value> [:...]]'
  106. '''
  107. source = str(source).strip()
  108. chunks = source.split(':')
  109. # handle drive letter ('c:', ...)
  110. if len(chunks) > 1 and len(chunks[0]) == 1 and chunks[0].isalpha():
  111. chunks[1] = chunks[0] + ':' + chunks[1]
  112. del chunks[0]
  113. source = chunks[0]
  114. try: source = int(source)
  115. except ValueError: pass
  116. params = dict( s.split('=') for s in chunks[1:] )
  117. cap = None
  118. if source == 'synth':
  119. Class = classes.get(params.get('class', None), VideoSynthBase)
  120. try: cap = Class(**params)
  121. except: pass
  122. else:
  123. cap = cv2.VideoCapture(source)
  124. if 'size' in params:
  125. w, h = map(int, params['size'].split('x'))
  126. cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
  127. cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
  128. if cap is None or not cap.isOpened():
  129. print('Warning: unable to open video source: ', source)
  130. if fallback is not None:
  131. return create_capture(fallback, None)
  132. return cap
  133. if __name__ == '__main__':
  134. import sys
  135. import getopt
  136. print(__doc__)
  137. args, sources = getopt.getopt(sys.argv[1:], '', 'shotdir=')
  138. args = dict(args)
  139. shotdir = args.get('--shotdir', '.')
  140. if len(sources) == 0:
  141. sources = [ 0 ]
  142. caps = list(map(create_capture, sources))
  143. shot_idx = 0
  144. while True:
  145. imgs = []
  146. for i, cap in enumerate(caps):
  147. ret, img = cap.read()
  148. imgs.append(img)
  149. cv2.imshow('capture %d' % i, img)
  150. ch = 0xFF & cv2.waitKey(1)
  151. if ch == 27:
  152. break
  153. if ch == ord(' '):
  154. for i, img in enumerate(imgs):
  155. fn = '%s/shot_%d_%03d.bmp' % (shotdir, i, shot_idx)
  156. cv2.imwrite(fn, img)
  157. print(fn, 'saved')
  158. shot_idx += 1
  159. cv2.destroyAllWindows()