kopia lustrzana https://github.com/OpenDroneMap/ODM
Fix ply (#1829)
* Create README.md for fix_ply * Create fix_ply.py * Update fix_ply.py to match current * Update README.md to match Jaime's description * Add more descriptionpull/1888/head
rodzic
4aa9cae393
commit
c6d94d6a64
|
@ -0,0 +1,19 @@
|
|||
# Fix Ply
|
||||
|
||||
Use to translate a modified ply into a compatible format for subsequent steps in ODM. Via Jaime Chacoff, https://community.opendronemap.org/t/edited-point-cloud-with-cloudcompare-wont-rerun-from-odm-meshing/21449/6
|
||||
|
||||
The basic idea is to process through ODM until the point cloud is created, use a 3rd party tool, like CloudCompare to edit the point cloud, and then continue processing in OpenDroneMap.
|
||||
|
||||
This useful bit of python will convert the PLY exported from CloudCompare back into a compatible format for continued processing in OpenDroneMap.
|
||||
|
||||
1. Run project in WebODM and add this to your settings: `end-with: odm-filterpoints`
|
||||
1. Once complete, go to your NodeODM container and copy `/var/www/data/[Task ID]/odm-filterpoints` directory
|
||||
1. Open CloudCompare and from `odm-filterpoints` directory you've copied, open `point_cloud.ply`
|
||||
1. In the box that pops up, add a scalar field `vertex - views`
|
||||
1. To see the actual colours again - select the point cloud, then in properties change colours from "Scalar field" to "RGB"
|
||||
1. Make your changes to the point cloud
|
||||
1. Compute normals (Edit > Normals > Compute)
|
||||
1. Save PLY file as ASCII
|
||||
1. Run Python file above to fix PLY file and convert to binary
|
||||
1. Copy `odm_filterpoints` directory (or just `point_cloud.ply`) back into NodeODM container
|
||||
1. Restart project in WebODM "From Meshing" (don't forget to edit settings to remove `end-with: odm-filterpoints` or it's not going to do anything).
|
|
@ -0,0 +1,68 @@
|
|||
import os
|
||||
import logging
|
||||
from plyfile import PlyData, PlyElement
|
||||
import numpy as np
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
|
||||
def pcd_ascii_to_binary_ply(ply_file: str, binary_ply: str) -> None:
|
||||
"""Converts ASCII PLY to binary, ensuring 'views' is present and of type uchar.
|
||||
Raises ValueError if neither 'scalar_views' nor 'views' is found.
|
||||
"""
|
||||
|
||||
try:
|
||||
logging.info(f"Reading ASCII PLY file: {ply_file}")
|
||||
ply_data: PlyData = PlyData.read(ply_file)
|
||||
except FileNotFoundError:
|
||||
logging.error(f"File not found: {ply_file}")
|
||||
return
|
||||
except Exception as e:
|
||||
logging.error(f"Error reading PLY file: {e}")
|
||||
return
|
||||
|
||||
new_elements: list[PlyElement] = []
|
||||
|
||||
for element in ply_data.elements:
|
||||
new_data = element.data.copy()
|
||||
|
||||
if 'scalar_views' in element.data.dtype.names:
|
||||
new_data['views'] = new_data['scalar_views'].astype('u1')
|
||||
del new_data['scalar_views']
|
||||
elif 'views' in element.data.dtype.names:
|
||||
new_data['views'] = new_data['views'].astype('u1')
|
||||
else:
|
||||
raise ValueError(f"Neither 'scalar_views' nor 'views' found - did you import them when opened the file in CloudCompare?")
|
||||
|
||||
|
||||
new_element = PlyElement.describe(new_data, element.name)
|
||||
new_elements.append(new_element)
|
||||
|
||||
new_ply_data = PlyData(new_elements, text=False)
|
||||
|
||||
try:
|
||||
logging.info(f"Writing binary PLY file: {binary_ply}")
|
||||
new_ply_data.write(binary_ply)
|
||||
except Exception as e:
|
||||
logging.error(f"Error writing PLY file: {e}")
|
||||
return
|
||||
|
||||
logging.info("PLY conversion complete.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# Parameters
|
||||
base: str = os.path.dirname(os.path.abspath(__file__))
|
||||
ply_file: str = os.path.join(base, 'point_cloud_ascii.ply')
|
||||
binary_ply_file: str = os.path.join(base, 'point_cloud.ply')
|
||||
|
||||
if not os.path.exists(ply_file):
|
||||
logging.error(f"Input file not found: {ply_file}")
|
||||
exit(1) # Exit with error code
|
||||
|
||||
try:
|
||||
pcd_ascii_to_binary_ply(ply_file, binary_ply_file)
|
||||
except ValueError as e:
|
||||
logging.error(f"PLY conversion failed: {e}")
|
||||
exit(1) # Exit with error code to indicate failure
|
Ładowanie…
Reference in New Issue