zivid / zivid-python

Official Python package for Zivid 3D cameras
BSD 3-Clause "New" or "Revised" License
40 stars 14 forks source link

Export different files format in one hdr capture #273

Closed robinmoon2 closed 2 months ago

robinmoon2 commented 2 months ago

Hello, I'm on a script to load the settings that I want to use for the hdr and I'm doing multiple hdr to compare the point cloud later between them. But I not only want the file in .pcd, I also want the RGB and depth files wich are in png.

How can I register this different files into my folder as well as the point cloud file ? This is my code : `app = zivid.Application() camera = app.connect_camera()

user_options = _options(camera)

settingsPath = Path(user_options.settings_path)
settings = zivid.Settings.load(settingsPath)

for j in range(0,i): 
    nom = 1+i 
    os.mkdir(f"{nom}")
    with camera.capture(settings) as frame : 
        data_file = f"{nom}/Frame.pcd"
        frame.save(data_file)

`

Thanks in advance !

eskaur commented 2 months ago

Hi! You can get the rgb and point-cloud/depth-map as numpy arrays from:

rgb = frame.point_cloud().copy_data("rgb")
xyz = frame.point_cloud().copy_data("xyz")
z = frame.point_cloud().copy_data("z")

you can then save those as png with one of many tools, for example opencv.

robinmoon2 commented 2 months ago

It works well for the z and rgb files. But I tried something for the xyz file that I don't nat in .png but in .xyz and I all my coordonates are "nan nan nan". Here is my code :

` Code :

with camera.capture(settings) as frame : 

      data_file = f"{nom_dossier}/Frame.zdf"
      rgb = frame.point_cloud().copy_data("bgra")
      xyz = np.array(frame.point_cloud().copy_data("xyz"))

      z = frame.point_cloud().copy_data("z")
      point_cloud = f"{nom_dossier}/Frame.pcd"
      frame.save(point_cloud)
      frame.save(data_file)
      cv2.imwrite(f"{nom_dossier}/rgb.png", rgb)
      cv2.imwrite(f"{nom_dossier}/depth.png",z)
      with open(f"{nom_dossier}/point_cloud.xyz", "w") as f:
          for point in xyz:
              f.write(f"{point[0]} {point[1]} {point[2]}\n")

`

Do you have a solution to direclty save the xyz file or do I need to take the informations from the .zdf file ?

eskaur commented 2 months ago

First of all, you should know that the slice xyz[:,:,2] is the exact same data as z. So if one contains some NaNs, so does the other.

The reason why the xyz data contains some NaNs is that it's a structured point cloud, meaning that it has one xyz point for each pixel of the camera [i,j]. We cannot successfully find the xyz values for every single pixel, because some camera pixels point at regions of your scene that is in the projector shadow. Those indices in the array still need to contain something, so we fill them with NaN.

An .xyz file that you are trying to make is an unstructured point cloud, meaning that this is merely a linear list of points with no association with camera pixels [i,k]. In this case you can (and should) just ignore the NaN points. So to solve your issue, I believe you should do something like:

for point in xyz:
    if not np.isnan(point[0]):
        f.write(f"{point[0]} {point[1]} {point[2]}\n")

i.e. merely skip the NaN points.

robinmoon2 commented 2 months ago

The solution doesn't work. I have the error : ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

eskaur commented 2 months ago

Sorry, I forgot that for point in xyz: will be wrong because xyz is a 3D array. This should work:

xyz = frame.point_cloud().copy_data("xyz")
height = xyz.shape[0]
width = xyz.shape[1]

for row in range(height):
    for col in range(width):
        point = xyz[row, col, :]
        if not np.isnan(point[0]):
            f.write(f"{point[0]} {point[1]} {point[2]}\n")

alternatively:

xyz = frame.point_cloud().copy_data("xyz")
xyz_flat = xyz.reshape(-1, 3)

for point in xyz_flat:
    if not np.isnan(point[0]):
        f.write(f"{point[0]} {point[1]} {point[2]}\n")
robinmoon2 commented 2 months ago

I will test this solution but for the moment I find something that works : I open a zdf file then I use it to copy the data of xyz points like a xyz file :

frame = zivid.Frame(file)
  xyz = frame.point_cloud().copy_data('xyz')
  points = np.nan_to_num(xyz)

Then, I can go through each pixel of the matrix and get the tuple of the coordinates of the point. thanks for helping me ;)

eskaur commented 2 months ago

I will test this solution but for the moment I find something that works : I open a zdf file then I use it to copy the data of xyz points like a xyz file :

frame = zivid.Frame(file)
  xyz = frame.point_cloud().copy_data('xyz')
  points = np.nan_to_num(xyz)

Then, I can go through each pixel of the matrix and get the tuple of the coordinates of the point. thanks for helping me ;)

That should work, but be aware that this will yield [0,0,0] points for all the missing NaN points, not actually remove them.