video.py 5.7 KB

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