00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 from __future__ import with_statement
00016 PKG = 'posedetectiondb'
00017 NAME = 'PoseFromCorrespondences'
00018
00019 import roslib; roslib.load_manifest(PKG)
00020 import os, sys, time, threading, string, struct
00021 from optparse import OptionParser
00022 from numpy import *
00023
00024 import cv, gtk
00025 import rospy, tf
00026 from roslib import rostime
00027 import std_msgs.msg
00028 import posedetection_msgs.msg
00029 import sensor_msgs.msg
00030 import geometry_msgs.msg
00031 from cv_bridge import CvBridge, CvBridgeError
00032
00033 from IterativeClosestPoint import *
00034 import ParseMessages
00035
00036 from openravepy import *
00037
00038 from Tkinter import *
00039 import tkFileDialog
00040 import copy
00041
00042 def FindExtrinsicCameraParams(imagepoints, objectpoints, KK):
00043 """ Use OpenCV to solve for the affine transformation that matches imagepoints to object points
00044 imagepoints - 2xN array
00045 objectpoints - 3xN array
00046 KK - 3x3 array or 4 element array
00047 """
00048 imagepoints = array(imagepoints,float)
00049 objectpoints = array(objectpoints,float)
00050 if len(KK.shape) == 1:
00051 cvKK = cv.CreateMat(3,3,cv.CV_32FC1)
00052 cvKK[0,0] = KK[0]; cvKK[0,1] = 0; cvKK[0,2] = KK[2];
00053 cvKK[1,0] = 0; cvKK[1,1] = KK[1]; cvKK[1,2] = KK[3];
00054 cvKK[2,0] = 0; cvKK[2,1] = 0; cvKK[2,2] = 1;
00055 else:
00056 cvKK = cv.fromarray(KK)
00057 cvDist = cv.CreateMat(4,1,cv.CV_32FC1)
00058 cvDist[0,0] = 0; cvDist[1,0] = 0; cvDist[2,0] = 0; cvDist[3,0] = 0;
00059 rvec = cv.CreateMat(3,1,cv.CV_32FC1)
00060 tvec = cv.CreateMat(3,1,cv.CV_32FC1)
00061 object_points = cv.CreateMatHeader(3,objectpoints.shape[0],cv.CV_32FC1)
00062 cv.SetData(object_points,struct.pack('f'*(objectpoints.shape[0]*3),*transpose(objectpoints).flat),4*objectpoints.shape[0])
00063 image_points = cv.CreateMatHeader(2,imagepoints.shape[0],cv.CV_32FC1)
00064 cv.SetData(image_points,struct.pack('f'*(imagepoints.shape[0]*2),*transpose(imagepoints).flat),4*imagepoints.shape[0])
00065 cv.FindExtrinsicCameraParams2(object_points,image_points,cvKK,cvDist,rvec,tvec)
00066 T = matrixFromAxisAngle((rvec[0,0],rvec[1,0],rvec[2,0]))
00067 T[0:3,3] = [tvec[0,0],tvec[1,0],tvec[2,0]]
00068 return T
00069
00070 class PoseFromCorrespondences(metaclass.AutoReloader):
00071 """
00072 Extracts poses from a set of point correspondences
00073 """
00074 def __init__(self,kinbodyfilename,verboselevel=1,frame_id=None):
00075 self.orenv = Environment()
00076 self.orenv.Load(kinbodyfilename)
00077 self.orbody = self.orenv.GetBodies()[0]
00078 self.orbody.SetTransform(eye(4))
00079 self.trimesh = self.orenv.Triangulate(self.orbody)
00080 self.orenv.SetViewer('qtcoin')
00081 self.eventhandle = self.orenv.GetViewer().RegisterCallback(Viewer.Events.ItemSelection,self.ormousecb)
00082 self.orpoint = None
00083 self.objectpoints = []
00084 self.verboselevel=verboselevel
00085 self.extractionlck = threading.Lock()
00086
00087 self.cvpoint = None
00088 self.Tobjectrel = None
00089 self.imagepoints = []
00090
00091 self.cvwindow = 'ImageDisplay'
00092 cv.NamedWindow(self.cvwindow, cv.CV_WINDOW_AUTOSIZE)
00093 cv.SetMouseCallback(self.cvwindow,self.cvmousecb)
00094
00095 self.bridge = CvBridge()
00096
00097 self.doquit = False
00098 self.gui = threading.Thread(target=self.rungui)
00099 self.gui.start()
00100
00101 self.pattern = (eye(4),None)
00102 self.imagemsg = None
00103 self.KK = None
00104 self.image_sub = rospy.Subscriber("image",sensor_msgs.msg.Image,self.imagecb)
00105 self.camerainfo_sub = rospy.Subscriber("camera_info",sensor_msgs.msg.CameraInfo,self.camerainfocb)
00106 self.frame_id = frame_id
00107 if self.frame_id is None:
00108 self.object_sub = rospy.Subscriber("ObjectDetection",posedetection_msgs.msg.ObjectDetection,self.objectcb)
00109 else:
00110 self.tflistener=tf.TransformListener()
00111 self.pub_relpose = rospy.Publisher("RelativePose", geometry_msgs.msg.Pose)
00112 rospy.init_node(NAME, anonymous=True)
00113
00114 def __del__(self):
00115 try:
00116 self.image_sub.unregister()
00117 except:
00118 pass
00119 try:
00120 self.camerainfo_sub.unregister()
00121 except:
00122 pass
00123 try:
00124 self.object_sub.unregister()
00125 except:
00126 pass
00127 try:
00128 self.pub_relpose.unregister()
00129 except:
00130 pass
00131 self.orenv.Destroy()
00132
00133 def ormousecb(self,link,pos,org):
00134 if link.GetParent().GetNetworkId() == self.orbody.GetNetworkId():
00135 T = linalg.inv(link.GetParent().GetTransform())
00136 bodypos = dot(T[0:3,0:3],pos)+T[0:3,3]
00137 self.orpoint = bodypos
00138 self.ghandle = self.orenv.plot3(points=reshape(bodypos,(1,3)),pointsize=15.0,colors=array((1,0,0)))
00139 return False
00140
00141 def cvmousecb(self,event,x,y,flags,param):
00142 if event == cv.CV_EVENT_LBUTTONUP:
00143 self.cvpoint = (x,y)
00144 if event == cv.CV_EVENT_RBUTTONUP:
00145 self.AddCorrespondence()
00146 if event == cv.CV_EVENT_MBUTTONUP:
00147 self.Reset()
00148
00149 def rungui(self):
00150 self.main = Tk()
00151 self.main.title('Create Object Database - 3 channel image')
00152 self.main.resizable(width=False, height=False)
00153 buttonframe = Frame(self.main)
00154 buttonframe.pack()
00155 b1 = Button(buttonframe, text="Add Correspondence (R-Button)", command=self.AddCorrespondence)
00156 b1.grid(row=1,column=1)
00157 b2 = Button(buttonframe, text="Reset (M-Button)", command=self.Reset)
00158 b2.grid(row=1,column=2)
00159 b2 = Button(buttonframe, text="Quit", command=self.Quit)
00160 b2.grid(row=1,column=3)
00161
00162
00163 entryframe = Frame(self.main)
00164 entryframe.pack()
00165 ltrans = Label(entryframe, text='Transform:')
00166 ltrans.grid(row=1,column=1,sticky=W+E)
00167 self.T_entry = Entry(entryframe,bg='white',width=100)
00168 self.T_entry.grid(row=1,column=2)
00169
00170 self.main.mainloop()
00171
00172 def camerainfocb(self,infomsg):
00173 with self.extractionlck:
00174 self.KK = reshape(infomsg.K,(3,3))
00175 if any([f!=0 for f in infomsg.D]):
00176 print 'Program does not support distorted images'
00177
00178 def imagecb(self,imagemsg):
00179 with self.extractionlck:
00180 self.imagemsg = imagemsg
00181
00182 def objectcb(self,objectmsg):
00183 with self.extractionlck:
00184 if len(objectmsg.objects) > 0:
00185 quat = objectmsg.objects[0].pose.orientation
00186 trans = objectmsg.objects[0].pose.position
00187 self.pattern = (matrixFromPose([quat.w,quat.x,quat.y,quat.z,trans.x,trans.y,trans.z]),objectmsg.header.frame_id)
00188 else:
00189 self.pattern = (None,None)
00190
00191 def AddCorrespondence(self):
00192 with self.extractionlck:
00193 print 'add correspondence'
00194
00195
00196
00197
00198
00199 if self.cvpoint is not None and self.orpoint is not None and self.pattern[0] is not None:
00200 Tpattern_inv = linalg.inv(self.pattern[0])
00201 self.imagepoints.append(array(self.cvpoint))
00202 self.objectpoints.append(array(self.orpoint))
00203 print 'total gathered points: %d'%len(self.imagepoints)
00204 if len(self.imagepoints) >= 4:
00205 print array(self.imagepoints)
00206 print array(self.objectpoints)
00207 print self.pattern[0]
00208 Tcameraobject = FindExtrinsicCameraParams(array(self.imagepoints,float),array(self.objectpoints,float),self.KK)
00209 self.Tobjectrel = dot(Tpattern_inv,Tcameraobject)
00210 print 'camera transform: ', Tcameraobject
00211 values = reshape(self.Tobjectrel[0:3,0:4],(12,))
00212 print "relative transform is: ",self.Tobjectrel
00213 self.T_entry.insert(0, ' '.join(str(f) for f in values))
00214 else:
00215 print 'point data not initialized'
00216
00217 def Reset(self):
00218 print 'reset'
00219 self.imagepoints = []
00220 self.objectpoints = []
00221 self.Tobjectrel = None
00222 def Quit(self):
00223 print 'quitting from gui'
00224 self.doquit = True
00225 self.main.quit()
00226
00227 def drawpart(self,cv_image,T,KK):
00228 N = self.trimesh.vertices.shape[0]
00229 pts = dot(transformPoints(T,self.trimesh.vertices),transpose(KK))
00230 imagepts = pts[0:N,0:2]/reshape(repeat(pts[0:N,2],2),[N,2])
00231 cvimagepts = [tuple(p) for p in array(imagepts,int)]
00232 for tri in self.trimesh.indices:
00233 cv.Line(cv_image,cvimagepts[tri[0]],cvimagepts[tri[1]],(255,255,255))
00234 cv.Line(cv_image,cvimagepts[tri[1]],cvimagepts[tri[2]],(255,255,255))
00235 cv.Line(cv_image,cvimagepts[tri[2]],cvimagepts[tri[0]],(255,255,255))
00236
00237 def drawcoordsys(self,cv_image,T,KK):
00238 points3d = array(((0,0,0),(0.05,0,0),(0,0.05,0),(0,0,0.05)))
00239 projpts = dot(transformPoints(T,points3d),transpose(KK))
00240 x = array(projpts[:,0]/projpts[:,2],int)
00241 y = array(projpts[:,1]/projpts[:,2],int)
00242 cv.Line(cv_image,(x[0],y[0]),(x[1],y[1]),(0,0,255),1)
00243 cv.Line(cv_image,(x[0],y[0]),(x[2],y[2]),(0,255,0),1)
00244 cv.Line(cv_image,(x[0],y[0]),(x[3],y[3]),(255,0,0),1)
00245
00246 def keycb(self, char):
00247 a=1
00248 if (char != -1):
00249 with self.extractionlck:
00250 minangle=pi/200
00251 mintranslation=.001
00252 if char==1113955:
00253 R=rotationMatrixFromAxisAngle(array([1,0,0]),minangle)
00254 T=array([0,0,0])
00255 elif char==1114111:
00256 R=rotationMatrixFromAxisAngle(array([1,0,0]),-minangle)
00257 T=array([0,0,0])
00258 elif char==1113936:
00259 R=rotationMatrixFromAxisAngle(array([0,1,0]),minangle)
00260 T=array([0,0,0])
00261 elif char==1113943:
00262 R=rotationMatrixFromAxisAngle(array([0,1,0]),-minangle)
00263 T=array([0,0,0])
00264 elif char==1113941:
00265 R=rotationMatrixFromAxisAngle(array([0,0,1]),minangle)
00266 T=array([0,0,0])
00267 elif char==1113942:
00268 R=rotationMatrixFromAxisAngle(array([0,0,1]),-minangle)
00269 T=array([0,0,0])
00270 elif char==65379:
00271 R=eye(3)
00272 T=array([1,0,0])
00273 elif char==65535:
00274 R=eye(3)
00275 T=array([-1,0,0])
00276 elif char==65360:
00277 R=eye(3)
00278 T=array([0,1,0])
00279 elif char==65367:
00280 R=eye(3)
00281 T=array([0,-1,0])
00282 elif char==65365:
00283 R=eye(3)
00284 T=array([0,0,1])
00285 elif char==65366:
00286 R=eye(3)
00287 T=array([0,0,-1])
00288 else:
00289 a=0
00290 if a==1:
00291 self.Tobjectrel[:3,:3]=dot(R,self.Tobjectrel[:3,:3])
00292 self.Tobjectrel[:3,3]=self.Tobjectrel[:3,3]+mintranslation*T
00293 print "relative: ",self.Tobjectrel
00294
00295 def spin(self):
00296 while not rospy.is_shutdown() and not self.doquit:
00297 with self.extractionlck:
00298 imagemsg = copy.copy(self.imagemsg)
00299 KK = array(self.KK)
00300 Tobjectrel = array(self.Tobjectrel) if self.Tobjectrel is not None else None
00301 Tpattern = array(self.pattern[0]) if self.pattern[0] is not None else None
00302
00303 if KK is None or imagemsg is None:
00304 time.sleep(0.1)
00305 continue
00306
00307 try:
00308 cv_image = self.bridge.imgmsg_to_cv(imagemsg, "bgr8")
00309 except CvBridgeError, e:
00310 print e
00311
00312 if Tpattern is not None:
00313 if Tobjectrel is not None:
00314 self.drawpart(cv_image,dot(Tpattern,Tobjectrel),KK)
00315 self.drawcoordsys(cv_image,Tpattern,KK)
00316 if self.cvpoint is not None:
00317 cv.Circle(cv_image,self.cvpoint,2,(0,0,255),2)
00318
00319 if Tobjectrel is not None:
00320 posemsg = geometry_msgs.msg.Pose()
00321 posemsg.orientation.w, posemsg.orientation.x, posemsg.orientation.y, posemsg.orientation.z, posemsg.position.x, posemsg.position.y, posemsg.position.z = poseFromMatrix(Tobjectrel)
00322 self.pub_relpose.publish(posemsg)
00323 gtk.gdk.threads_enter()
00324 cv.ShowImage(self.cvwindow, cv_image)
00325 char=cv.WaitKey(20)
00326 self.keycb(char)
00327 gtk.gdk.threads_leave()
00328 time.sleep(1.0)
00329 print 'quitting spin'
00330
00331 if __name__== '__main__':
00332 parser = OptionParser(description='Estiamtes the pose of an openrave object by specifying manual correspondeces between the image and the openrave environment. If a separate ObjectDetection pattern is added, will publish the pose of the object with respect to the pattern.')
00333 parser.add_option('--quiet',action='store_true', dest='quiet',default=False,
00334 help="If set will not print extraction output and times.")
00335 parser.add_option('--kinbody', action='store', type='string', dest='kinbody',
00336 help='OpenRAVE Kinbody file to load')
00337
00338
00339 parser.add_option('--Tobjectrel', action='store', type='string', dest='Tobjectrel',default=None,
00340 help='Initial estimate of Tobject (3x4 matrix serialized by row-order)')
00341 (options, args) = parser.parse_args()
00342 if not options.kinbody:
00343 print('Error: Need to specify a template')
00344 sys.exit(1)
00345
00346 gtk.gdk.threads_init()
00347
00348 try:
00349 processor = PoseFromCorrespondences(options.kinbody)
00350 if options.Tobjectrel is not None:
00351 processor.Tobjectrel = r_[reshape([float(s) for s in options.Tobjectrel.split()[0:12]],[3,4]),[[0,0,0,1]]]
00352 processor.spin()
00353 except KeyboardInterrupt, e:
00354 pass