00001
00002
00003 import roslib; roslib.load_manifest('camera_pose_calibration')
00004 import cv
00005 from cv_bridge import CvBridge, CvBridgeError
00006 import rospy
00007 import threading
00008 import numpy
00009 from calibration_msgs.msg import Interval
00010 from calibration_msgs.msg import CalibrationPattern
00011 from sensor_msgs.msg import Image
00012 from sensor_msgs.msg import CameraInfo
00013 from camera_pose_calibration.msg import RobotMeasurement
00014 from camera_pose_calibration.msg import CameraCalibration
00015
00016
00017 def beep(conf):
00018 try:
00019 with file('/dev/audio', 'wb') as audio:
00020 for (frequency, amplitude, duration) in conf:
00021 sample = 8000
00022 half_period = int(sample/frequency/2)
00023 beep = chr(amplitude)*half_period+chr(0)*half_period
00024 beep *= int(duration*frequency)
00025 audio.write(beep)
00026 except:
00027 print "Beep beep"
00028
00029
00030
00031 class ImageRenderer:
00032 def __init__(self, ns):
00033 self.lock = threading.Lock()
00034 self.image_time = rospy.Time(0)
00035 self.info_time = rospy.Time(0)
00036 self.image = None
00037 self.interval = 0
00038 self.features = None
00039 self.bridge = CvBridge()
00040 self.ns = ns
00041 self.max_interval = 1.0
00042
00043 self.font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 0.30, 1.5, thickness = 2)
00044 self.info_sub = rospy.Subscriber(ns+'/camera_info', CameraInfo, self.info_cb)
00045 self.image_sub = rospy.Subscriber(ns+'/image_throttle', Image, self.image_cb)
00046 self.interval_sub = rospy.Subscriber(ns+'/settled_interval', Interval, self.interval_cb)
00047 self.features_sub = rospy.Subscriber(ns+'/features', CalibrationPattern, self.features_cb)
00048
00049 def info_cb(self, msg):
00050 with self.lock:
00051 self.info_time = rospy.Time.now()
00052
00053 def image_cb(self, msg):
00054 with self.lock:
00055 self.image_time = rospy.Time.now()
00056 self.image = msg
00057
00058 def interval_cb(self, msg):
00059 with self.lock:
00060 self.interval = (msg.end - msg.start).to_sec()
00061
00062 def features_cb(self, msg):
00063 with self.lock:
00064 self.features = msg
00065
00066 def render(self, window):
00067 with self.lock:
00068 if self.image and self.image_time + rospy.Duration(2.0) > rospy.Time.now() and self.info_time + rospy.Duration(2.0) > rospy.Time.now():
00069 cv.Resize(self.bridge.imgmsg_to_cv(self.image, 'rgb8'), window)
00070 interval = min(1,(self.interval / self.max_interval))
00071 cv.Rectangle(window,
00072 (int(0.05*window.width), int(window.height*0.9)),
00073 (int(interval*window.width*0.9+0.05*window.width), int(window.height*0.95)),
00074 (0, interval*255, (1-interval)*255), thickness=-1)
00075 cv.Rectangle(window,
00076 (int(0.05*window.width), int(window.height*0.9)),
00077 (int(window.width*0.9+0.05*window.width), int(window.height*0.95)),
00078 (0, interval*255, (1-interval)*255))
00079 if self.features and self.features.header.stamp + rospy.Duration(4.0) > self.image.header.stamp:
00080 w_scaling = float (window.width) / self.image.width
00081 h_scaling = float (window.height) / self.image.height
00082 if self.features.success:
00083 corner_color = (0,255,0)
00084 for cur_pt in self.features.image_points:
00085 cv.Circle(window, (int(cur_pt.x*w_scaling), int(cur_pt.y*h_scaling)), int(w_scaling*5), corner_color)
00086 else:
00087 window = add_text(window, ["Could not detect", "checkerboard"], False)
00088 else:
00089 window = add_text(window, ["Timed out waiting", "for checkerboard"], False)
00090
00091 else:
00092
00093 noise = numpy.random.rand(window.height, window.width)*256
00094 numpy.asarray(window)[:,:,0] = noise;
00095 numpy.asarray(window)[:,:,1] = noise;
00096 numpy.asarray(window)[:,:,2] = noise;
00097 cv.PutText(window, self.ns, (int(window.width * .05), int(window.height * .95)), self.font, (0,0,255))
00098
00099
00100 def add_text(image, text, good = True):
00101 if good:
00102 color = (0, 255, 0)
00103 else:
00104 color = (0, 0, 255)
00105 w = image.cols
00106 h = image.rows
00107 for i in range(len(text)):
00108 font = cv.InitFont(cv.CV_FONT_HERSHEY_SIMPLEX, 0.30, float(w)/350, thickness = 1)
00109 ((text_w, text_h), _) = cv.GetTextSize(text[i], font)
00110 cv.PutText(image, text[i], (w/2-text_w/2, h/2-text_h/2 + i*text_h*2), font, color)
00111 return image
00112
00113
00114
00115 def get_image(text, good=True, h=480, w=640):
00116 image = cv.CreateMat(h, w, cv.CV_8UC3)
00117 return add_text(image, text, good)
00118
00119
00120 class Aggregator:
00121 def __init__(self, ns_list):
00122 print "Creating aggregator for ", ns_list
00123
00124 self.lock = threading.Lock()
00125
00126
00127 w = 640
00128 h = 480
00129 self.image_out = cv.CreateMat(h, w, cv.CV_8UC3)
00130 self.pub = rospy.Publisher('aggregated_image', Image)
00131 self.bridge = CvBridge()
00132
00133 self.image_captured = get_image(["Successfully captured checkerboard"])
00134 self.image_optimized = get_image(["Successfully ran optimization"])
00135 self.image_failed = get_image(["Failed to run optimization"], False)
00136
00137
00138 layouts = [ (1,1), (2,2), (2,2), (2,2), (3,3), (3,3), (3,3), (3,3), (3,3) ]
00139 layout = layouts[len(ns_list)-1]
00140 sub_w = w / layout[0]
00141 sub_h = h / layout[1]
00142 self.windows = []
00143 for j in range(layout[1]):
00144 for i in range(layout[0]):
00145 self.windows.append( cv.GetSubRect(self.image_out, (i*sub_w, j*sub_h, sub_w, sub_h) ) )
00146
00147
00148 self.renderer_list = []
00149 for ns in ns_list:
00150 self.renderer_list.append(ImageRenderer(ns))
00151
00152
00153 self.capture_time = rospy.Time(0)
00154 self.calibrate_time = rospy.Time(0)
00155 self.captured_sub = rospy.Subscriber('robot_measurement', RobotMeasurement, self.captured_cb)
00156 self.optimized_sub = rospy.Subscriber('camera_calibration', CameraCalibration, self.calibrated_cb)
00157
00158
00159 def captured_cb(self, msg):
00160 with self.lock:
00161 self.capture_time = rospy.Time.now()
00162 beep([(400, 63, 0.2)])
00163
00164 def calibrated_cb(self, msg):
00165 with self.lock:
00166 self.calibrate_time = rospy.Time.now()
00167
00168
00169 def loop(self):
00170 r = rospy.Rate(20)
00171 beep_time = rospy.Time(0)
00172
00173 while not rospy.is_shutdown():
00174 r.sleep()
00175 with self.lock:
00176 for window, render in zip(self.windows, self.renderer_list):
00177 render.render(window)
00178
00179 if self.capture_time+rospy.Duration(4.0) > rospy.Time.now():
00180 if self.capture_time+rospy.Duration(2.0) > rospy.Time.now():
00181 self.pub.publish(self.bridge.cv_to_imgmsg(self.image_captured, encoding="passthrough"))
00182 elif self.calibrate_time+rospy.Duration(5.0) > rospy.Time.now():
00183 self.pub.publish(self.bridge.cv_to_imgmsg(self.image_optimized, encoding="passthrough"))
00184 if beep_time+rospy.Duration(4.0) < rospy.Time.now():
00185 beep_time = rospy.Time.now()
00186 beep([(600, 63, 0.1), (800, 63, 0.1), (1000, 63, 0.3)])
00187 else:
00188 self.pub.publish(self.bridge.cv_to_imgmsg(self.image_failed, encoding="passthrough"))
00189 if beep_time+rospy.Duration(4.0) < rospy.Time.now():
00190 beep_time = rospy.Time.now()
00191 beep([(400, 63, 0.1), (200, 63, 0.1), (100, 63, 0.6)])
00192
00193 else:
00194 self.pub.publish(self.bridge.cv_to_imgmsg(self.image_out, encoding="passthrough"))
00195
00196
00197
00198 def main():
00199 rospy.init_node('capture_monitor')
00200 args = rospy.myargv()
00201
00202 a = Aggregator(args[1:])
00203 a.loop()
00204
00205
00206
00207 if __name__ == '__main__':
00208 main()