video2ros.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env python
  2. """ video2ros.py - Version 1.1 2013-12-20
  3. Read in a recorded video file and republish as a ROS Image topic.
  4. Created for the Pi Robot Project: http://www.pirobot.org
  5. Copyright (c) 2012 Patrick Goebel. All rights reserved.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details at:
  14. http://www.gnu.org/licenses/gpl.html
  15. """
  16. import rospy
  17. import sys
  18. from cv2 import cv as cv
  19. import cv2
  20. from sensor_msgs.msg import Image
  21. from cv_bridge import CvBridge, CvBridgeError
  22. class Video2ROS:
  23. def __init__(self):
  24. rospy.init_node('video2ros', anonymous=False)
  25. rospy.on_shutdown(self.cleanup)
  26. """ Define the input (path to video file) as a ROS parameter so it
  27. can be defined in a launch file or on the command line """
  28. self.input = rospy.get_param("~input", "")
  29. """ Define the image publisher with generic topic name "output" so that it can
  30. be remapped in the launch file. """
  31. image_pub = rospy.Publisher("output", Image, queue_size=5)
  32. # The target frames per second for the video
  33. self.fps = rospy.get_param("~fps", 25)
  34. # Do we restart the video when the end is reached?
  35. self.loop = rospy.get_param("~loop", False)
  36. # Start the video paused?
  37. self.start_paused = rospy.get_param("~start_paused", False)
  38. # Show text feedback by default?
  39. self.show_text = rospy.get_param("~show_text", True)
  40. # Resize the original video?
  41. self.resize_video = rospy.get_param("~resize_video", False)
  42. # If self.resize_video is True, set the desired width and height here
  43. self.resize_width = rospy.get_param("~resize_width", 0)
  44. self.resize_height = rospy.get_param("~resize_height", 0)
  45. # Initialize a few variables
  46. self.paused = self.start_paused
  47. self.loop_video = True
  48. self.keystroke = None
  49. self.restart = False
  50. self.last_frame = None
  51. # Initialize the text font
  52. font_face = cv2.FONT_HERSHEY_SIMPLEX
  53. font_scale = 0.5
  54. # Define the capture object as pointing to the input file
  55. self.capture = cv2.VideoCapture(self.input)
  56. # Get the original frames per second
  57. fps = self.capture.get(cv.CV_CAP_PROP_FPS)
  58. # Get the original frame size
  59. self.frame_size = (self.capture.get(cv.CV_CAP_PROP_FRAME_HEIGHT), self.capture.get(cv.CV_CAP_PROP_FRAME_WIDTH))
  60. # Check that we actually have a valid video source
  61. if fps == 0.0:
  62. print "Video source", self.input, "not found!"
  63. return None
  64. # Bring the fps up to the specified rate
  65. try:
  66. fps = int(fps * self.fps / fps)
  67. except:
  68. fps = self.fps
  69. # Create the display window
  70. cv.NamedWindow("Video Playback", True) # autosize the display
  71. cv.MoveWindow("Video Playback", 375, 25)
  72. # Create the CvBridge object
  73. bridge = CvBridge()
  74. # Enter the main processing loop
  75. while not rospy.is_shutdown():
  76. # Get the next frame from the video
  77. frame = self.get_frame()
  78. # Convert the frame to ROS format
  79. try:
  80. image_pub.publish(bridge.cv2_to_imgmsg(frame, "bgr8"))
  81. except CvBridgeError, e:
  82. print e
  83. # Create a copy of the frame for displaying the text
  84. display_image = frame.copy()
  85. if self.show_text:
  86. cv2.putText(display_image, "FPS: " + str(self.fps), (10, 20), font_face, font_scale, cv.RGB(255, 255, 0))
  87. cv2.putText(display_image, "Keyboard commands:", (20, int(self.frame_size[0] * 0.6)), font_face, font_scale, cv.RGB(255, 255, 0))
  88. cv2.putText(display_image, " ", (20, int(self.frame_size[0] * 0.65)), font_face, font_scale, cv.RGB(255, 255, 0))
  89. cv2.putText(display_image, "space - toggle pause/play", (20, int(self.frame_size[0] * 0.72)), font_face, font_scale, cv.RGB(255, 255, 0))
  90. cv2.putText(display_image, " r - restart video from beginning", (20, int(self.frame_size[0] * 0.79)), font_face, font_scale, cv.RGB(255, 255, 0))
  91. cv2.putText(display_image, " t - hide/show this text", (20, int(self.frame_size[0] * 0.86)), font_face, font_scale, cv.RGB(255, 255, 0))
  92. cv2.putText(display_image, " q - quit the program", (20, int(self.frame_size[0] * 0.93)), font_face, font_scale, cv.RGB(255, 255, 0))
  93. # Merge the original image and the display image (text overlay)
  94. display_image = cv2.bitwise_or(frame, display_image)
  95. # Now display the image.
  96. cv2.imshow("Video Playback", display_image)
  97. """ Handle keyboard events """
  98. self.keystroke = cv.WaitKey(1000 / fps)
  99. """ Process any keyboard commands """
  100. if self.keystroke != -1:
  101. try:
  102. cc = chr(self.keystroke & 255).lower()
  103. if cc == 'q':
  104. """ user has press the q key, so exit """
  105. rospy.signal_shutdown("User hit q key to quit.")
  106. elif cc == ' ':
  107. """ Pause or continue the video """
  108. self.paused = not self.paused
  109. elif cc == 'r':
  110. """ Restart the video from the beginning """
  111. self.restart = True
  112. elif cc == 't':
  113. """ Toggle display of text help message """
  114. self.show_text = not self.show_text
  115. except:
  116. pass
  117. def get_frame(self):
  118. # If the video is paused, return the last frame
  119. if self.paused and not self.last_frame is None:
  120. frame = self.last_frame
  121. else:
  122. # Get the next frame
  123. ret, frame = self.capture.read()
  124. if frame is None:
  125. # If we've run out of frames, loop if set True
  126. if self.loop_video:
  127. self.restart = True
  128. # Did we receive the restart command?
  129. if self.restart:
  130. # To restart, simply reinitialize the capture object
  131. self.capture = cv2.VideoCapture(self.input)
  132. self.restart = False
  133. ret, frame = self.capture.read()
  134. # Were we asked to resize the video?
  135. if self.resize_video:
  136. frame = cv2.resize(frame, (self.resize_width, self.resize_height))
  137. # Store the last frame for when we pause
  138. self.last_frame = frame
  139. return frame
  140. def cleanup(self):
  141. print "Shutting down video2ros node."
  142. cv2.destroyAllWindows()
  143. def main(args):
  144. help_message = "Hot keys: \n" \
  145. "\tq - quit the program\n" \
  146. "\tr - restart video from beginning\n" \
  147. "\tspace - toggle pause/play\n"
  148. print help_message
  149. try:
  150. v2r = Video2ROS()
  151. except KeyboardInterrupt:
  152. print "Shutting down video2ros..."
  153. cv2.destroyAllWindows()
  154. if __name__ == '__main__':
  155. main(sys.argv)