object_circler.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # Copyright (c) 2013, Oregon State University
00003 # All rights reserved.
00004 #
00005 # Redistribution and use in source and binary forms, with or without
00006 # modification, are permitted provided that the following conditions are met:
00007 #     * Redistributions of source code must retain the above copyright
00008 #       notice, this list of conditions and the following disclaimer.
00009 #     * Redistributions in binary form must reproduce the above copyright
00010 #       notice, this list of conditions and the following disclaimer in the
00011 #       documentation and/or other materials provided with the distribution.
00012 #     * Neither the name of the Oregon State University nor the
00013 #       names of its contributors may be used to endorse or promote products
00014 #       derived from this software without specific prior written permission.
00015 #
00016 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 # DISCLAIMED. IN NO EVENT SHALL OREGON STATE UNIVERSITY BE LIABLE FOR ANY
00020 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 #
00027 # Author Dan Lazewatsky/lazewatd@engr.orst.edu
00028 
00029 import roslib; roslib.load_manifest('projector_interface')
00030 import rospy
00031 from sensor_msgs.msg import CameraInfo, PointCloud2
00032 from std_msgs.msg import Empty, String as String, Duration
00033 from geometry_msgs.msg import PointStamped
00034 import image_geometry
00035 from projector_interface._point_cloud import read_points_np
00036 from projector_interface.treeable import TreeCircleInfo, GraphicsItemInfo
00037 from pr2_python.pointclouds import xyz_array_to_pointcloud2
00038 from projector_interface import srv
00039 import tf
00040 
00041 import cv2
00042 import numpy as np
00043 from collections import deque
00044 from threading import RLock
00045 import sys
00046 
00047 
00048 # import PySide
00049 from PySide import QtGui, QtCore
00050 
00051 from dynamic_reconfigure.server import Server as DynamicReconfigureServer
00052 from projector_interface.cfg import InterfaceConfig
00053 
00054 import kdtree
00055 
00056 from functools import partial
00057 
00058 #X_OFFSET =  25
00059 #Y_OFFSET = -25
00060 
00061 X_OFFSET = 0
00062 Y_OFFSET = 0
00063 
00064 CURSOR_RADIUS = 10
00065 
00066 SAME_OBJ_THRESH    = 0.03
00067 
00068 class Colors:
00069     WHITE = QtGui.QColor(255, 255, 255)
00070     GREEN = QtGui.QColor(  0, 255, 0  )
00071     BLUE  = QtGui.QColor(  0, 135, 189)
00072 
00073 class Circler(QtGui.QGraphicsView):
00074     H = None
00075     POLYGON_PEN = QtGui.QPen(Colors.WHITE, 5)
00076     ACTIVE_POLYGON_PEN = QtGui.QPen(Colors.GREEN, 5)
00077     CLICKED_OBJECT_PEN = QtGui.QPen(Colors.BLUE, 5)
00078     CIRCLE_RADIUS = 150
00079 
00080     objects = None  
00081     projected_objects = None
00082     int_objects = None  
00083     int_projected_objects = None
00084     click_loc = np.float64([-1, -1, -1])
00085     click_duration = rospy.Duration(1.0)
00086     
00087     selected_pt = np.array([])
00088     
00089     use_selected_thresh = True
00090     
00091     cursor_pts = None
00092     
00093     model = None
00094     object_header = None
00095     cursor_header = None
00096 
00097     object_lock = RLock()
00098     intersected_lock = RLock()
00099     cursor_lock = RLock()
00100     polygon_lock = RLock()
00101     
00102     polygons = dict()
00103     polygon_pens = dict()
00104 
00105     key_handlers = dict()
00106 
00107     click_stale = False
00108     config_inited = False
00109 
00110     click = QtCore.Signal()
00111     polygonAdded = QtCore.Signal(srv.DrawPolygonRequest)
00112     polygonsCleared = QtCore.Signal()
00113     cursorMoved = QtCore.Signal(PointCloud2)
00114     objectsChanged = QtCore.Signal(PointCloud2)
00115     objectHighlighted = QtCore.Signal(srv.HilightObject)
00116     hilightsCleared = QtCore.Signal()
00117 
00118     def keyPressEvent(self, e):
00119         for key, fn in self.key_handlers.items():
00120             if key == e.key():
00121                 fn(e)
00122         
00123     def addKeyHandler(self, key, fn):
00124         self.key_handlers[key] = fn
00125 
00126     def escHandler(self, _):
00127         QtGui.QApplication.quit()
00128 
00129     def initUI(self):
00130         self.resetClickedObject()
00131         self.resetActiveObject()
00132         self.active_poly   = GraphicsItemInfo(QtGui.QGraphicsPolygonItem(), -1, label='\x00')
00133         self.active_object = TreeCircleInfo(QtCore.QRect(), self.POLYGON_PEN, (0, 0, 0))
00134         gfx_scene = QtGui.QGraphicsScene() 
00135         gfx_scene.setBackgroundBrush(QtGui.QColor(0, 0, 0))
00136         self.last_click_time = rospy.Time(0)
00137 
00138         # setup the cursor pen
00139         pen = QtGui.QPen(Colors.BLUE, 5)
00140 
00141         # add an ellipse to the scene
00142         cursor_rect = QtCore.QRect(self.width(), self.height(), CURSOR_RADIUS, CURSOR_RADIUS)
00143         self.obj_cursor = gfx_scene.addEllipse(cursor_rect, pen)   
00144         self.obj_cursor.setCacheMode(QtGui.QGraphicsItem.CacheMode.NoCache)
00145         self.obj_cursor.setZValue(2000)
00146         self.last_cursor_rect = self.obj_cursor.boundingRect()
00147 
00148         # add a line for the offscreen cursor hint
00149         self.obj_cursor_hint = gfx_scene.addLine(0, 0, 0, 0, pen=pen)
00150         self.obj_cursor_hint.hide()
00151         self.obj_cursor_hint.setZValue(2000)
00152 
00153         self.setScene(gfx_scene)
00154 
00155         self.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing)
00156 
00157         self.addKeyHandler(16777216, self.escHandler)
00158 
00159         self.showFullScreen()
00160 
00161         # Manually set the scene rect to prevent the view
00162         # from scrolling to fit off-screen objects
00163         self.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
00164         self.setSceneRect(0, 0, self.width(), self.height())
00165 
00166         self.circles = kdtree.create(dimensions=3)
00167 
00168     def resetClick(self, obj):
00169         obj.item.setPen(self.polygon_pens[obj.uid])
00170         obj.item.setZValue(0)
00171         obj.clicked = False
00172         self.scene().invalidate(obj.item.boundingRect())
00173         self.resetClickedObject()
00174 
00175     def resetClickedObject(self):
00176         self.clicked_object = GraphicsItemInfo(QtGui.QGraphicsPolygonItem(), -1, label='\x00')
00177 
00178     def resetActiveObject(self):
00179         self.active_poly = GraphicsItemInfo(QtGui.QGraphicsPolygonItem(), -1, label='\x00')
00180 
00181     def info_cb(self, info):
00182         tmp_model = image_geometry.PinholeCameraModel()
00183         tmp_model.fromCameraInfo(info)
00184         self.model = tmp_model 
00185         self.info_sub.unregister()
00186     
00187 
00188     def handleClick(self):
00189         # Make sure the click was on an object, and that nothing is already clicked
00190         self.last_click_time = rospy.Time.now()
00191 
00192         # Polygons
00193         if (self.active_poly.label != '\x00') and (self.clicked_object.label == '\x00'):
00194             self.clicked_object = self.active_poly
00195             self.clicked_object.item.setPen(self.CLICKED_OBJECT_PEN)
00196             self.clicked_object.item.setZValue(1000)
00197             self.clicked_object.clicked = True
00198             self.clicked_object_pub.publish(self.clicked_object.uid)
00199             self.scene().invalidate(self.clicked_object.item.boundingRect())
00200             QtCore.QTimer.singleShot(
00201                 1000*self.click_duration.to_sec(),
00202                 partial(self.resetClick, self.clicked_object)
00203             )
00204 
00205         # Circles
00206         if self.active_object.active:
00207             self.clicked_object = self.active_object
00208             self.clicked_object.item.setPen(self.CLICKED_OBJECT_PEN)
00209             self.clicked_object.item.setZValue(1000)
00210             self.clicked_object.clicked = True
00211             self.clicked_object_pub.publish(self.clicked_object.uid)
00212             self.scene().invalidate(self.clicked_object.item.boundingRect())
00213             QtCore.QTimer.singleShot(
00214                 1000*self.click_duration.to_sec(),
00215                 partial(self.resetClick, self.clicked_object)
00216             )
00217 
00218     def click_cb(self, msg):
00219         self.click_stale = False
00220         self.click.emit()
00221 
00222         with self.cursor_lock:
00223             self.click_loc = self.selected_pt
00224             msg = xyz_array_to_pointcloud2(np.array(self.cursor_pts_xyz))
00225             msg.header.frame_id = self.model.tf_frame
00226             msg.header.stamp = rospy.Time.now()
00227             self.click_stats_pub.publish(msg)
00228         
00229     def object_cb(self, msg):
00230         self.objectsChanged.emit(msg)
00231 
00232     def updateObjects(self, obj_msg):
00233         with self.object_lock:
00234             for obj in self.circles.inorder():
00235                 self.scene().removeItem(obj.data)
00236                 self.scene().invalidate(obj.data.boundingRect())
00237             self.circles = kdtree.create(dimensions=3)
00238 
00239             objects = read_points_np(obj_msg, masked=False)
00240             if objects.shape[1] == 0:
00241                 return
00242             
00243             self.object_header = obj_msg.header
00244             self.objects = objects
00245             transformed_objects = self.projectPoints(self.objects, obj_msg.header)
00246             self.projected_objects = cv2.perspectiveTransform(transformed_objects, self.H)
00247             for pt, xformed in zip(self.objects[0], self.projected_objects[0]):
00248                 coords = self.maybe_flip((xformed[1], xformed[0]))
00249                 rect = QtCore.QRectF(
00250                     coords[0]-self.CIRCLE_RADIUS/2 + X_OFFSET,
00251                     coords[1]-self.CIRCLE_RADIUS/2 + Y_OFFSET,
00252                     self.CIRCLE_RADIUS,
00253                     self.CIRCLE_RADIUS
00254                 )
00255                 circle = TreeCircleInfo(rect, self.POLYGON_PEN, pt)
00256                 if self.circles:
00257                     nearest = self.circles.search_nn(circle)
00258                     if np.sqrt(nearest.dist(circle)) > SAME_OBJ_THRESH:                    
00259                         self.circles.add(circle)
00260                         self.scene().addItem(circle)
00261                         self.scene().invalidate(rect)
00262                 else:
00263                     self.circles.add(circle)
00264                     self.scene().addItem(circle)
00265                     self.scene().invalidate(rect)
00266 
00267     def intersected_cb(self, msg):
00268         with self.intersected_lock:
00269             objects = read_points_np(msg, masked=False)
00270             if objects.shape[1] == 0:
00271                 return
00272 
00273             self.int_objects = objects
00274             transformed_objects = self.projectPoints(objects, msg.header)
00275             self.int_projected_objects = cv2.perspectiveTransform(transformed_objects, self.H)
00276 
00277     def cursor_cb(self, msg):
00278         self.cursorMoved.emit(msg)
00279 
00280     def hideCursor(self):
00281         self.obj_cursor.hide()
00282         self.scene().invalidate(self.obj_cursor.boundingRect())
00283 
00284     def showCursor(self):
00285         self.obj_cursor.show()
00286         self.scene().invalidate(self.obj_cursor.boundingRect())
00287 
00288     def hideCursorHint(self):
00289         self.obj_cursor_hint.hide()
00290         self.scene().invalidate(self.obj_cursor_hint.boundingRect())
00291 
00292     def showCursorHint(self):
00293         self.obj_cursor_hint.show()
00294         self.scene().invalidate(self.obj_cursor_hint.boundingRect())
00295 
00296     def update_cursor(self, cursor_msg):
00297         with self.cursor_lock:
00298             objects = read_points_np(cursor_msg, masked=False)
00299             if objects.shape[1] == 0:
00300                 return
00301             
00302             self.cursor_header = cursor_msg.header
00303             self.cursor_pts = objects
00304             transformed_pts = self.projectPoints(self.cursor_pts, cursor_msg.header)
00305             self.projected_cursor.extend(cv2.perspectiveTransform(transformed_pts, self.H)[0])
00306 
00307 
00308         with self.cursor_lock:
00309             xformed = np.median(self.projected_cursor, 0)
00310             coords = self.maybe_flip((xformed[1], xformed[0]))
00311             cursor_x = coords[0]
00312             cursor_y = coords[1]
00313 
00314             # if the cursor is on-screen, draw it
00315             if    cursor_x > 0 and cursor_y > 0 \
00316               and cursor_x < self.width()       \
00317               and cursor_y < self.height():
00318 
00319                 if self.obj_cursor_hint.isVisible():
00320                     self.hideCursorHint()
00321 
00322                 cursor_rect = QtCore.QRectF(
00323                     cursor_x-CURSOR_RADIUS/2,# + X_OFFSET,
00324                     cursor_y-CURSOR_RADIUS/2,# + Y_OFFSET,
00325                     CURSOR_RADIUS,
00326                     CURSOR_RADIUS
00327                 )
00328                 self.showCursor()
00329 
00330                 self.obj_cursor.setRect(cursor_rect)
00331                 self.scene().invalidate(cursor_rect)
00332                 self.scene().invalidate(self.last_cursor_rect)
00333                 self.last_cursor_rect = self.obj_cursor.boundingRect()
00334             # otherwise, draw a hint
00335             else:
00336                 if self.obj_cursor.isVisible:
00337                     self.hideCursor()
00338 
00339                 hint_x = cursor_x
00340                 if cursor_x < 0:
00341                     hint_x = 0
00342                 if cursor_x > self.width():
00343                     hint_x = self.width()
00344 
00345                 hint_y = cursor_y
00346                 if cursor_y < 0:
00347                     hint_y = 0
00348                 if cursor_y > self.height():
00349                     hint_y = self.height()
00350 
00351                 head = np.array([hint_x, hint_y])# + [X_OFFSET, Y_OFFSET]
00352                 tail_x, tail_y = 0, 0
00353                 if hint_x == 0:
00354                     tail_x =  50
00355                 if hint_x == self.width():
00356                     tail_x = -50
00357                 if hint_y == 0:
00358                     tail_y =  50
00359                 if hint_y == self.height():
00360                     tail_y = -50
00361                 tail = head + [tail_x, tail_y]
00362                 self.scene().invalidate(self.obj_cursor_hint.boundingRect())
00363                 self.obj_cursor_hint.setLine(head[0], head[1], tail[0], tail[1])
00364                 self.showCursorHint()
00365 
00366         self.updateIntersectedPolys()
00367         self.updateIntersectedCircles() 
00368 
00369 
00370     # TODO this may need a more efficient implementaion that doesn't look at all polygons
00371     def updateIntersectedPolys(self):
00372         with self.polygon_lock:
00373             with self.cursor_lock:
00374                 cursor_center = self.last_cursor_rect.center()
00375             self.resetActiveObject()
00376             for info in self.polygons.values():
00377                 if not info.clicked:
00378                     dirty = False
00379                     if info.item.polygon().containsPoint(cursor_center, QtCore.Qt.OddEvenFill):
00380                         dirty = not info.active 
00381                         info.active = True
00382                         info.item.setPen(self.ACTIVE_POLYGON_PEN)
00383                         info.item.setZValue(500)
00384                         self.active_poly = info
00385                     else:
00386                         dirty = info.active
00387                         info.active = False
00388                         info.item.setPen(self.polygon_pens[info.uid])
00389                         info.item.setZValue(0)
00390                         self.resetClickedObject()
00391                     if dirty:
00392                         self.scene().invalidate(info.item.boundingRect())
00393 
00394     def updateIntersectedCircles(self):
00395         if self.circles:
00396             # don't try to reset a clicked object
00397             if not self.active_object.clicked:
00398                 self.active_object.active = False
00399                 self.active_object.item.setPen(self.POLYGON_PEN)
00400 
00401             self.scene().invalidate(self.active_object.item.boundingRect())
00402             self.resetActiveObject()
00403             with self.object_lock:
00404                 with self.cursor_lock:
00405                     cursor_center = self.last_cursor_rect.center()
00406                     cursor_center_3d = np.median(self.cursor_pts, 0).flatten().tolist()
00407                     nearest = self.circles.search_nn(cursor_center_3d)
00408 
00409                     # if we're requiring that the cursor be within the halo, do that check
00410                     if self.use_selected_thresh:
00411                         nearest = nearest if nearest.data.contains(cursor_center) else None
00412 
00413                     dirty = False 
00414                     # if the object has been clicked, don't touch it here
00415                     if nearest and not nearest.data.clicked: 
00416                         item = nearest.data
00417                         dirty = not item.active
00418                         item.active = True
00419                         item.setPen(self.ACTIVE_POLYGON_PEN)
00420                         item.setZValue(500)
00421                         self.active_object = item # TODO is this right?
00422                     if dirty:
00423                         self.scene().invalidate(item.boundingRect())
00424 
00425 
00426     def projectPoints(self, points, point_header):
00427         pts_out = []
00428         for point in points[0]:
00429             pt = PointStamped()
00430             try:
00431                 pt.point.x, pt.point.y, pt.point.z = point.tolist()
00432             except Exception:
00433                 print 'Error: ', point
00434             # first, transform the point into the camera frame
00435             if point_header.frame_id != self.model.tf_frame:
00436                 stamp = rospy.Time(0)
00437                 pt.header = point_header
00438                 pt.header.stamp = stamp
00439                 pt_out = self.tfl.transformPoint(self.model.tf_frame, pt).point
00440             else:
00441                 pt_out = pt.point
00442             # project it onto the image plane
00443             px = self.model.project3dToPixel((pt_out.x, pt_out.y, pt_out.z))
00444             pts_out.append(px)
00445         return np.array([pts_out])
00446         
00447     def maybe_flip(self, coords):
00448         if self.flip:
00449             return self.width() - coords[0], self.height() - coords[1]
00450         return coords 
00451                  
00452     def hilight_object(self, req):
00453         pt = self.tfl.transformPoint(self.object_header.frame_id, req.object).point
00454         color = QtGui.QColor(req.color.r, req.color.g, req.color.b)
00455         if self.circles:
00456             pt_arr = [pt.x, pt.y, pt.z]
00457             to_hilight = self.circles.search_nn([pt.x, pt.y, pt.z])
00458             # np.spacing(2) is equivalent to eps in matlab (apparently 1 doesn't work)
00459             if to_hilight.dist(pt_arr) < 0.09:
00460                 to_hilight.data.showHilight(color)
00461 
00462     def clear_hilights(self):
00463         for obj in self.circles.inorder():
00464             obj.data.clearHilight()
00465 
00466     def handle_hilight(self, req):
00467         self.objectHighlighted.emit(req)
00468         return srv.HilightObjectResponse()
00469         
00470     def handle_clear_hilight(self, _):
00471         self.hilightsCleared.emit()
00472         return srv.ClearHilightsResponse()
00473 
00474     def handle_get_cursor_stats(self, _):
00475         # wait until the click expires
00476         while not (rospy.Time.now() - self.last_click_time) < self.click_duration:
00477             rospy.sleep(0.05)
00478         with self.cursor_lock:
00479             msg = xyz_array_to_pointcloud2(np.array([list(p) + [0] for p in self.projected_cursor]))
00480             msg.header.frame_id = '/table_marker'
00481             msg.header.stamp = rospy.Time.now()
00482             
00483             pt_msg = PointStamped()
00484             pt_msg.header = msg.header
00485             try:
00486                 pt_msg.point.x, pt_msg.point.y, pt_msg.point.z = self.clicked_object.point3d
00487             except:
00488                 pass # nothing was clicked
00489             return srv.GetCursorStatsResponse(msg, pt_msg)
00490         
00491     def set_selection_method(self, req):
00492         if req.method == req.THRESH:
00493             self.use_selected_thresh = True
00494         elif req.method == req.CLOSEST:
00495             self.use_selected_thresh = False
00496         return srv.SetSelectionMethodResponse()
00497 
00498     def handle_draw_polygon(self, req):
00499         self.polygonAdded.emit(req)
00500         return srv.DrawPolygonResponse()
00501 
00502     def draw_polygon(self, req):
00503         with self.polygon_lock:
00504             if req.id in self.polygons:
00505                 self.clear_polygon(req.id)
00506 
00507             # Project the polygon points onto the interface before saving them
00508             poly = QtGui.QPolygon()
00509             pts_arr = np.array([[(p.x, p.y, p.z) for p in req.polygon.polygon.points]])
00510             points = self.projectPoints(pts_arr, req.polygon.header)
00511             points = cv2.perspectiveTransform(points, self.H)
00512             if self.flip:
00513                 points[0] = ([self.height(), self.width()] - points[0])
00514             for point in points[0]:
00515                 poly.push_back(QtCore.QPoint(point[1], point[0]))
00516 
00517             my_pen = QtGui.QPen(QtGui.QColor(req.color.r, req.color.g, req.color.b), 5)
00518 
00519             poly_item = self.scene().addPolygon(poly, pen=my_pen)
00520 
00521 
00522             textRect = poly.boundingRect()
00523             # Project the text rect points onto the interface
00524             if len(req.text_rect.points) > 0:
00525                 text_rect_points = self.projectPoints(
00526                     np.array([[(p.x,p.y,p.z) for p in req.text_rect.points]]),
00527                     req.polygon.header
00528                 )
00529                 text_rect_points = cv2.perspectiveTransform(text_rect_points, self.H)
00530                 if self.flip:
00531                     text_rect_points[0] = ([self.height(), self.width()] - text_rect_points[0]) 
00532                 text_poly = QtGui.QPolygon()
00533                 for point in text_rect_points[0]:
00534                     text_poly.push_back(QtCore.QPoint(point[1], point[0]))
00535                 textRect = text_poly.boundingRect()
00536                 textRect = poly.boundingRect() # DEBUG!
00537 
00538                 if req.label:
00539                     font = QtGui.QFont('Decorative', 30)
00540                     text_item = QtGui.QGraphicsSimpleTextItem(
00541                         req.label, parent=poly_item,
00542                         scene=self.scene()
00543                     )
00544                     text_item.setFont(font)
00545                     text_item.setBrush(QtGui.QBrush(Colors.WHITE))
00546                     text_item.setPos(textRect.topLeft())
00547 
00548             self.polygon_pens[req.id] = my_pen
00549             self.polygons[req.id] = GraphicsItemInfo(poly_item, req.id, req.label)
00550             self.scene().invalidate(self.polygons[req.id].item.boundingRect())
00551 
00552     def clear_polygon(self, poly_id, remove=True):
00553         poly = self.polygons[poly_id]
00554         self.scene().removeItem(poly.item) 
00555         QtCore.QTimer.singleShot(100, partial(self.scene().invalidate, poly.item.boundingRect()))
00556         QtCore.QTimer.singleShot(100, partial(self.scene().invalidate, poly.item.childrenBoundingRect()))
00557         if remove: del self.polygons[poly_id]
00558 
00559     def clear_polygons(self):
00560         with self.polygon_lock:
00561             for poly_id in self.polygons.keys():
00562                 self.clear_polygon(poly_id, remove=False)
00563             self.polygons.clear()
00564 
00565     def handle_clear_polygons(self, _):
00566         self.polygonsCleared.emit()
00567         return srv.ClearPolygonsResponse()
00568 
00569     def reconfig_cb(self, config, level):
00570         # ignore the first config we get
00571         if self.config_inited:
00572             self.projected_cursor = deque(self.projected_cursor, config['window_size'])
00573             self.cursor_pts_xyz   = deque(self.cursor_pts_xyz,   config['window_size'])
00574 
00575         else:
00576             config['window_size'] = self.projected_cursor.maxlen
00577             self.config_inited = True
00578 
00579         return config
00580 
00581     def checkShutdownRequest(self):
00582         if rospy.is_shutdown():
00583             QtGui.QApplication.quit()
00584 
00585     def __init__(self):
00586         super(Circler, self).__init__()
00587         self.tfl = tf.TransformListener()
00588         r = rospy.Rate(10)
00589         rospy.loginfo('waiting for homography...')
00590         while (not rospy.has_param('/homography')) and (not rospy.is_shutdown()):
00591             r.sleep()
00592         self.H = np.float64(rospy.get_param('/homography')).reshape(3, 3)
00593         self.flip = rospy.get_param('~flip', default=False)
00594 
00595         self.projected_cursor = deque([], rospy.get_param('~window_size', 10))
00596         self.cursor_pts_xyz   = deque([], rospy.get_param('~window_size', 10))
00597         self.circle_objects   = rospy.get_param('~circle_objects', True)
00598 
00599         # self.addKeyHandler(67, QtGui.QApplication.quit)
00600 
00601         self.click.connect(self.handleClick)
00602         self.polygonAdded.connect(self.draw_polygon)
00603         self.polygonsCleared.connect(self.clear_polygons)
00604         self.cursorMoved.connect(self.update_cursor)
00605         self.objectsChanged.connect(self.updateObjects)
00606         self.objectHighlighted.connect(self.hilight_object)
00607         self.hilightsCleared.connect(self.clear_hilights)
00608 
00609         rospy.loginfo('Window size = %s', rospy.get_param('~window_size', 10))
00610         rospy.loginfo('Flip        = %s', self.flip)
00611         rospy.loginfo('Circle      = %s', self.circle_objects)
00612 
00613         rospy.loginfo('got homography')
00614         print self.H
00615         self.initUI()
00616         rospy.Subscriber('object_cloud', PointCloud2, self.object_cb)
00617         rospy.Subscriber('click', Empty, self.click_cb)
00618         rospy.Subscriber('intersected_points', PointCloud2, self.intersected_cb, queue_size=1)
00619         rospy.Subscriber('intersected_points_cursor', PointCloud2, self.cursor_cb)
00620         self.info_sub = rospy.Subscriber('camera_info', CameraInfo, self.info_cb)
00621         rospy.Service('hilight_object', srv.HilightObject, self.handle_hilight)
00622         rospy.Service('clear_hilights', srv.ClearHilights, self.handle_clear_hilight)
00623         rospy.Service('get_cursor_stats', srv.GetCursorStats, self.handle_get_cursor_stats)
00624         rospy.Service('set_selection_method', srv.SetSelectionMethod, self.set_selection_method)
00625         rospy.Service('draw_polygon', srv.DrawPolygon, self.handle_draw_polygon)
00626         rospy.Service('clear_polygons', srv.ClearPolygons, self.handle_clear_polygons)
00627         self.selected_pub = rospy.Publisher('selected_point', PointStamped)
00628 
00629         self.rate_pub = rospy.Publisher('rate', Empty)
00630         self.dur_pub = rospy.Publisher('duration', Duration)
00631 
00632         self.click_stats_pub = rospy.Publisher('click_stats', PointCloud2)
00633         self.clicked_object_pub = rospy.Publisher('clicked_object', String)
00634         DynamicReconfigureServer(InterfaceConfig, self.reconfig_cb)
00635 
00636         self.interrupt_timer = QtCore.QTimer(self)
00637         self.interrupt_timer.setInterval(30)
00638         self.interrupt_timer.timeout.connect(self.checkShutdownRequest)
00639         self.interrupt_timer.start()
00640         
00641         rospy.loginfo('interface started')
00642         app.exec_()
00643         rospy.spin()
00644 
00645 if __name__ == '__main__':
00646     rospy.init_node('object_circler')
00647     print 'Window size is %s' % rospy.get_param('~window_size', 1)
00648     app = QtGui.QApplication(sys.argv)
00649     c = Circler()


projector_interface
Author(s): Daniel Lazewatsky
autogenerated on Mon Oct 6 2014 10:12:36