Convert Pixel Coordinates (U,V) to Pointcloud2 (X, Y Z) (Python)
Hi All,
I am currently writing a python script where I want to take a pixel pair from my depth camera, have it spit out its XYZ coordinates.
I am currently subscribing to two topics, camera/color/image_raw, and camera/depth/color/points.
I am quite new to this, and I had assumed that once I got the pixel position from my image raw, I could do something with that to find the matching depth point; giving me the needed XYZ.
It seems that they don't have the same resolution either, the image is 640x480 whereas the pointcloud is 1280x720.
If someone could help me with this, that would be a great help, I'm really struggling to understand how to get this :)
EDIT: With the help of Ranjit, I have found a solution to my issue.
Using image_geometry.PinholeCameraModel()
and camera_model.projectPixelTo3dRay((U,V))
and then normalising as suggested works well enough for an X Y (accurate to 3cm from 1 meter away with an intel realsense d435).
From here, Instead of using a generator, I put the pointcloud directly into a ros_numpy array like this get_xyz_points(pointcloud2_to_array(data), remove_nans=True, dtype=np.float32)
.
From here, we simply searched through the array using a cDKTree tree = cKDTree(points)
Finally add the Z to the preexisting XY, to get a decent enough result.
EDIT 2: On request, here is the final function created to call the camera, and get the coordinates.
### Callback for converting a pixel XY and depth to XYZ ###
def xyzCallback(self, data):
#get global X&Y and check assignemnt
global intY
global intX
#Get the pointcloud into an array
xyz_array = get_xyz_points(pointcloud2_to_array(data), remove_nans=True, dtype=np.float32)
#Use curetn camera model to get somewhat accurate 3d postiion for X & Y
vector = cam_model.projectPixelTo3dRay((intX,intY))
#Noramlise the 3dray
ray_z = [el / vector[2] for el in vector]
#Assign vector results to easier accessable varaibles
a = vector[0]
b = vector[1]
#Use cKDTree to search for and accurate Z with results closest to the one inputtted
points = xyz_array[:,0:2] # drops the z column
tree = cKDTree(points)
idx = tree.query((a, b))[1] # this returns a tuple, we want the index
result = xyz_array[idx, 2]
#Assign new Z to normalised X Y
ray_z[2] = result
positions = ray_z
print("Final position = ", positions)
Could you kindly share the complete code here? Thanks in advance :)
Of course, here's my GitHub, with the completed code. Specifically, you will want to look at XYZCallback, starting on line 96.
https://github.com/LeeAClift/gazebo_e...
I can't seem to find the repository on your profile. Could you please check if it's the right link or have you made the repo private?
Many apologies, the GitHub is private as it contains work that hasn't been published yet. I will attach the function to the original post though.
Hello @LeeAClift , I'm making a similar project now, and I'm stuck, are you willing to share your python code here? Do you run the python code on a terminal and the moveit launch file on another one? do you know how to visualize x,y,z arrow on rviz/moveit display area? I want it to be like this video (x,y,z arrow appeared on the detected object) : https://www.youtube.com/watch?v=iJWHR...
I'm quite new to this sorry to be such a nuisance with all these questions but I will be really grateful if you could help me !