diff --git a/README.md b/README.md index 69a1787..8c0efb8 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,17 @@ It is a module for [Meshroom](https://alicevision.org/#meshroom). You can [download pre-compiled binaries for the latest release](https://github.com/alicevision/meshroom/releases). -Get the source code and install runtime requirements: +Get the source code and set up the plugin environment: ```bash git clone --recursive https://github.com/alicevision/MeshroomGeolocation.git cd MeshroomGeolocation -pip install -r requirements.txt +python setup.py ``` +`setup.py` creates a `.venv` inside the plugin folder and installs all required dependencies into it. This isolated environment is used automatically by all plugin nodes — no environment variables need to be set. + +> **Note:** Run `setup.py` with a standard Python 3 installation (not Meshroom's bundled Python). + ## Environment variables Custom nodes can be added to Meshroom by setting the environment variable `MESHROOM_NODES_PATH`. @@ -37,6 +41,14 @@ Here `MESHROOM_PIPELINE_TEMPLATES_PATH = path/to/MeshroomGeolocation/pipelines`. All the pipelines will be available in Pipelines category in Meshroom UI. You can learn more about them [here](#pipelines). +### Optional: override the Python interpreter + +By default the plugin uses the `.venv` created by `setup.py`. To use a different Python interpreter, set `MESHROOM_GEOLOC_PYTHON` to its path before launching Meshroom: + +```bash +set MESHROOM_GEOLOC_PYTHON=C:/path/to/python.exe +``` + ## Plugin System Since recently a plugin system has been added to Meshroom. @@ -74,7 +86,7 @@ Here are screenshots of them : ![Map 2d pipeline](./external_files/map2d_pipeline.png) -- **Generate Weather H D R I** is also a simple node with an HDRI downloaded for the weather during the dataset. +- **Generate Weather HDRI** is also a simple node with an HDRI downloaded for the weather during the dataset. ![Weather pipeline](./external_files/weather_pipeline.png) diff --git a/meshroom/geolocation/Download2dMap.py b/meshroom/geolocation/Download2dMap.py index 4fe5782..3ef627e 100644 --- a/meshroom/geolocation/Download2dMap.py +++ b/meshroom/geolocation/Download2dMap.py @@ -16,11 +16,16 @@ class Download2dMap(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/download2dMap.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/meshroom/geolocation/DownloadLidar3dMap.py b/meshroom/geolocation/DownloadLidar3dMap.py index 2c7a02e..67de742 100644 --- a/meshroom/geolocation/DownloadLidar3dMap.py +++ b/meshroom/geolocation/DownloadLidar3dMap.py @@ -16,11 +16,16 @@ class DownloadLidar3dMap(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/downloadLidar3dMap.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/meshroom/geolocation/DownloadTopography3dMap.py b/meshroom/geolocation/DownloadTopography3dMap.py index 8042b5b..f315119 100644 --- a/meshroom/geolocation/DownloadTopography3dMap.py +++ b/meshroom/geolocation/DownloadTopography3dMap.py @@ -16,11 +16,16 @@ class DownloadTopography3dMap(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/DEMto3DFULL.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' diff --git a/meshroom/geolocation/GeolocationLidarLasToMesh.py b/meshroom/geolocation/GeolocationLidarLasToMesh.py index fbf1a8d..c8344bb 100644 --- a/meshroom/geolocation/GeolocationLidarLasToMesh.py +++ b/meshroom/geolocation/GeolocationLidarLasToMesh.py @@ -16,11 +16,16 @@ class GeolocationLidarLasToMesh(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/lidarLasToMesh.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/meshroom/geolocation/MergeLidarLas.py b/meshroom/geolocation/MergeLidarLas.py index 4fb715c..c051f6b 100644 --- a/meshroom/geolocation/MergeLidarLas.py +++ b/meshroom/geolocation/MergeLidarLas.py @@ -10,11 +10,16 @@ class MergeLidarLas(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/mergeLidarLas.py").resolve() - commandLine = pythonPath.as_posix() + ' ' + targetScriptPath.as_posix() + ' {allParams}' + commandLine = pythonPath.as_posix() + ' -E ' + targetScriptPath.as_posix() + ' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/meshroom/geolocation/North.py b/meshroom/geolocation/North.py index e4ccde5..91b152d 100644 --- a/meshroom/geolocation/North.py +++ b/meshroom/geolocation/North.py @@ -16,11 +16,16 @@ class North(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/north.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/meshroom/geolocation/Sun.py b/meshroom/geolocation/Sun.py index 012ab3a..a04ff93 100644 --- a/meshroom/geolocation/Sun.py +++ b/meshroom/geolocation/Sun.py @@ -16,11 +16,16 @@ class Sun(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/sun.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/meshroom/geolocation/WeatherHDRI.py b/meshroom/geolocation/WeatherHDRI.py index e3ee2fb..962c75c 100644 --- a/meshroom/geolocation/WeatherHDRI.py +++ b/meshroom/geolocation/WeatherHDRI.py @@ -16,11 +16,16 @@ class WeatherHDRI(desc.CommandLineNode): currentFilePath = Path(__file__).absolute() currentFileFolderPath = currentFilePath.parent - # Get python environnement or global python - pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", "python")) + # Resolve venv Python if present, then MESHROOM_GEOLOC_PYTHON, then bare 'python' + _plugin_dir = (currentFileFolderPath / "../..").resolve() + _venv_python = next( + (p for p in [_plugin_dir / ".venv/Scripts/python.exe", _plugin_dir / ".venv/bin/python"] if p.exists()), + None + ) + pythonPath = Path(os.environ.get("MESHROOM_GEOLOC_PYTHON", str(_venv_python) if _venv_python else "python")) targetScriptPath = (currentFileFolderPath / "../../scripts/weatherHDRI.py").resolve() - commandLine = pythonPath.as_posix() +' '+ targetScriptPath.as_posix() +' {allParams}' + commandLine = pythonPath.as_posix() +' -E '+ targetScriptPath.as_posix() +' {allParams}' category = 'Geolocation' documentation = ''' diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b3a37d6 --- /dev/null +++ b/setup.py @@ -0,0 +1,25 @@ +""" +Run this script once to create a .venv and install plugin dependencies: + + python setup.py +""" + +import subprocess +import sys +from pathlib import Path + +plugin_dir = Path(__file__).parent +venv_dir = plugin_dir / ".venv" +requirements = plugin_dir / "requirements.txt" + +print(f"Creating virtual environment at {venv_dir} ...") +subprocess.run([sys.executable, "-m", "venv", str(venv_dir)], check=True) + +venv_python = venv_dir / "Scripts" / "python.exe" +if not venv_python.exists(): + venv_python = venv_dir / "bin" / "python" + +print("Installing requirements ...") +subprocess.run([str(venv_python), "-m", "pip", "install", "-r", str(requirements)], check=True) + +print("\nSetup complete. You can now launch Meshroom.")