Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plot bundle adjust pointmap geodiff results #27

Merged
merged 10 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 51 additions & 18 deletions asp_plot/bundle_adjust.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,31 @@
from asp_plot.utils import ColorBar, Plotter, save_figure


class ReadResiduals:
class ReadBundleAdjustFiles:
def __init__(self, directory, bundle_adjust_directory):
self.directory = directory
self.bundle_adjust_directory = bundle_adjust_directory

def get_init_final_residuals_csvs(self):
def get_csv_paths(self, geodiff_files=False):
filenames = [
"*-initial_residuals_pointmap.csv",
"*-final_residuals_pointmap.csv",
]

if geodiff_files:
filenames = [f.replace(".csv", "-diff.csv") for f in filenames]

paths = [
glob.glob(
os.path.join(self.directory, self.bundle_adjust_directory, filename)
)[0]
for filename in filenames
glob.glob(os.path.join(self.directory, self.bundle_adjust_directory, f))[0]
for f in filenames
]

for path in paths:
if not os.path.isfile(path):
raise ValueError(f"Residuals CSV file not found: {path}")
raise ValueError(f"CSV file not found: {path}")

resid_init_path, resid_final_path = paths
return resid_init_path, resid_final_path
initial, final = paths
return initial, final

def get_residuals_gdf(self, csv_path):
cols = [
Expand Down Expand Up @@ -66,11 +67,38 @@ def get_residuals_gdf(self, csv_path):
resid_gdf.filename = os.path.basename(csv_path)
return resid_gdf

def get_init_final_residuals_gdfs(self):
resid_init_path, resid_final_path = self.get_init_final_residuals_csvs()
resid_init_gdf = self.get_residuals_gdf(resid_init_path)
def get_geodiff_gdf(self, csv_path):
cols = [
"lon",
"lat",
"height_diff_meters",
]

geodiff_df = pd.read_csv(csv_path, skiprows=7, names=cols)

geodiff_gdf = gpd.GeoDataFrame(
geodiff_df,
geometry=gpd.points_from_xy(
geodiff_df["lon"], geodiff_df["lat"], crs="EPSG:4326"
),
)

geodiff_gdf.filename = os.path.basename(csv_path)
return geodiff_gdf

def get_initial_final_residuals_gdfs(self):
resid_initial_path, resid_final_path = self.get_csv_paths()
resid_initial_gdf = self.get_residuals_gdf(resid_initial_path)
resid_final_gdf = self.get_residuals_gdf(resid_final_path)
return resid_init_gdf, resid_final_gdf
return resid_initial_gdf, resid_final_gdf

def get_initial_final_geodiff_gdfs(self):
geodiff_initial_path, geodiff_final_path = self.get_csv_paths(
geodiff_files=True
)
geodiff_initial_gdf = self.get_geodiff_gdf(geodiff_initial_path)
geodiff_final_gdf = self.get_geodiff_gdf(geodiff_final_path)
return geodiff_initial_gdf, geodiff_final_gdf

def get_mapproj_residuals_gdf(self):
path = glob.glob(
Expand Down Expand Up @@ -123,18 +151,18 @@ def get_propagated_triangulation_uncert_df(self):
return resid_triangulation_uncert_df


class PlotResiduals(Plotter):
class PlotBundleAdjustFiles(Plotter):
def __init__(self, geodataframes, **kwargs):
super().__init__(**kwargs)
if not isinstance(geodataframes, list):
raise ValueError("Input must be a list of GeoDataFrames")
self.geodataframes = geodataframes

def get_residual_stats(self, gdf, column_name="mean_residual"):
def gdf_percentile_stats(self, gdf, column_name="mean_residual"):
stats = gdf[column_name].quantile([0.25, 0.50, 0.84, 0.95]).round(2).tolist()
return stats

def plot_n_residuals(
def plot_n_gdfs(
self,
column_name="mean_residual",
cbar_label="Mean Residual (m)",
Expand Down Expand Up @@ -175,10 +203,15 @@ def plot_n_residuals(
clim=clim,
column_name=column_name,
cbar_label=cbar_label,
cmap=cmap,
)
else:
self.plot_geodataframe(
ax=axa[i], gdf=gdf, column_name=column_name, cbar_label=cbar_label
ax=axa[i],
gdf=gdf,
column_name=column_name,
cbar_label=cbar_label,
cmap=cmap,
)

ctx.add_basemap(ax=axa[i], **ctx_kwargs)
Expand All @@ -187,7 +220,7 @@ def plot_n_residuals(
axa[i].autoscale(False)

# Show some statistics and information
stats = self.get_residual_stats(gdf, column_name)
stats = self.gdf_percentile_stats(gdf, column_name)
stats_text = f"(n={gdf.shape[0]})\n" + "\n".join(
f"{quantile*100:.0f}th: {stat}"
for quantile, stat in zip([0.25, 0.50, 0.84, 0.95], stats)
Expand Down
63 changes: 44 additions & 19 deletions asp_plot/cli/asp_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import subprocess
import click
import contextily as ctx
from itertools import count
from asp_plot.processing_parameters import ProcessingParameters
from asp_plot.scenes import ScenePlotter, SceneGeometryPlotter
from asp_plot.bundle_adjust import ReadResiduals, PlotResiduals
from asp_plot.bundle_adjust import ReadBundleAdjustFiles, PlotBundleAdjustFiles
from asp_plot.stereo import StereoPlotter
from asp_plot.utils import compile_report

Expand Down Expand Up @@ -44,7 +45,7 @@
@click.option(
"--plots_directory",
prompt=True,
default="asp_plots",
default="asp_plots_for_report",
help="Directory to put output plots. Default: asp_plots",
)
@click.option(
Expand All @@ -68,20 +69,23 @@ def main(
os.makedirs(plots_directory, exist_ok=True)
report_pdf_path = os.path.join(directory, report_filename)

figure_counter = count(0)

# Geometry plot
plotter = SceneGeometryPlotter(directory)

plotter.dg_geom_plot(save_dir=plots_directory, fig_fn="00_geometry.png")
plotter.dg_geom_plot(save_dir=plots_directory, fig_fn=f"{next(figure_counter):02}.png")

# Scene plot
plotter = ScenePlotter(directory, stereo_directory, title="Mapprojected Scenes")

plotter.plot_orthos(save_dir=plots_directory, fig_fn="01_orthos.png")
plotter.plot_orthos(save_dir=plots_directory, fig_fn=f"{next(figure_counter):02}.png")

# Bundle adjustment plots
residuals = ReadResiduals(directory, bundle_adjust_directory)
resid_init_gdf, resid_final_gdf = residuals.get_init_final_residuals_gdfs()
resid_mapprojected_gdf = residuals.get_mapproj_residuals_gdf()
ba_files = ReadBundleAdjustFiles(directory, bundle_adjust_directory)
resid_initial_gdf, resid_final_gdf = ba_files.get_initial_final_residuals_gdfs()
geodiff_initial_gdf, geodiff_final_gdf = ba_files.get_initial_final_geodiff_gdfs()
resid_mapprojected_gdf = ba_files.get_mapproj_residuals_gdf()

ctx_kwargs = {
"crs": map_crs,
Expand All @@ -90,48 +94,69 @@ def main(
"alpha": 0.5,
}

plotter = PlotResiduals(
[resid_init_gdf, resid_final_gdf],
plotter = PlotBundleAdjustFiles(
[resid_initial_gdf, resid_final_gdf],
lognorm=True,
title="Bundle Adjust Initial and Final Residuals (Log Scale)",
)

plotter.plot_n_residuals(
plotter.plot_n_gdfs(
column_name="mean_residual",
cbar_label="Mean Residual (m)",
map_crs=map_crs,
save_dir=plots_directory,
fig_fn="02_ba_residuals_log.png",
fig_fn=f"{next(figure_counter):02}.png",
**ctx_kwargs,
)

plotter.lognorm = False
plotter.title = "Bundle Adjust Initial and Final Residuals (Linear Scale)"

plotter.plot_n_residuals(
plotter.plot_n_gdfs(
column_name="mean_residual",
cbar_label="Mean Residual (m)",
common_clim=False,
map_crs=map_crs,
save_dir=plots_directory,
fig_fn="03_ba_residuals_linear.png",
fig_fn=f"{next(figure_counter):02}.png",
**ctx_kwargs,
)

plotter = PlotResiduals(
plotter = PlotBundleAdjustFiles(
[resid_mapprojected_gdf],
title="Bundle Adjust Midpoint distance between\nfinal interest points projected onto reference DEM",
)

plotter.plot_n_residuals(
plotter.plot_n_gdfs(
column_name="mapproj_ip_dist_meters",
cbar_label="Interest point distance (m)",
map_crs=map_crs,
save_dir=plots_directory,
fig_fn="04_ba_residuals_mapproj_dist.png",
fig_fn=f"{next(figure_counter):02}.png",
**ctx_kwargs,
)

plotter = PlotBundleAdjustFiles(
[geodiff_initial_gdf, geodiff_final_gdf],
lognorm=False,
title="Bundle Adjust Initial and Final Geodiff vs. Reference DEM"
)

clim = (float(geodiff_initial_gdf["height_diff_meters"].quantile(0.05)), float(geodiff_initial_gdf["height_diff_meters"].quantile(0.95)))
abs_max = max(abs(clim[0]), abs(clim[1]))
clim = (-abs_max, abs_max)

plotter.plot_n_gdfs(
column_name="height_diff_meters",
cbar_label="Height difference (m)",
map_crs=map_crs,
cmap="RdBu",
clim=clim,
save_dir=plots_directory,
fig_fn=f"{next(figure_counter):02}.png",
**ctx_kwargs
)

# Stereo plots
plotter = StereoPlotter(
directory,
Expand All @@ -143,7 +168,7 @@ def main(

plotter.plot_match_points(
save_dir=plots_directory,
fig_fn="05_stereo_match_points.png",
fig_fn=f"{next(figure_counter):02}.png",
)

plotter.title = "Disparity (pixels)"
Expand All @@ -152,14 +177,14 @@ def main(
unit="pixels",
quiver=True,
save_dir=plots_directory,
fig_fn="06_disparity_pixels.png",
fig_fn=f"{next(figure_counter):02}.png",
)

plotter.title = "Stereo DEM Results"

plotter.plot_dem_results(
save_dir=plots_directory,
fig_fn="07_stereo_dem_results.png",
fig_fn=f"{next(figure_counter):02}.png",
)

# Compile report
Expand Down
144 changes: 92 additions & 52 deletions notebooks/bundle_adjust_plots.ipynb

Large diffs are not rendered by default.

18 changes: 13 additions & 5 deletions notebooks/scene_plots.ipynb

Large diffs are not rendered by default.

27 changes: 6 additions & 21 deletions notebooks/stereo_plots.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
"source": [
"import os\n",
"from asp_plot.stereo import StereoPlotter\n",
"from asp_plot.processing_parameters import ProcessingParameters\n",
"from asp_plot.utils import compile_report"
"from asp_plot.processing_parameters import ProcessingParameters"
]
},
{
Expand All @@ -23,10 +22,8 @@
"ba_directory = \"ba/\"\n",
"reference_dem = \"/Users/ben/Dropbox/UW_Shean/COP/COP30_utqiagvik_lzw-adj_proj.tif\"\n",
"\n",
"plots_directory = os.path.join(directory, \"stereo_report_plots\")\n",
"os.makedirs(plots_directory, exist_ok=True)\n",
"\n",
"report_pdf_path = os.path.join(directory, \"asp_report_WV03_20220417.pdf\")\n"
"plots_directory = os.path.join(directory, \"asp_plots\")\n",
"os.makedirs(plots_directory, exist_ok=True)"
]
},
{
Expand Down Expand Up @@ -63,7 +60,7 @@
"\n",
"plotter.plot_match_points(\n",
" save_dir=plots_directory,\n",
" fig_fn=\"05_stereo_match_points.png\",\n",
" fig_fn=\"stereo_match_points.png\",\n",
")"
]
},
Expand Down Expand Up @@ -122,7 +119,7 @@
" unit=\"pixels\",\n",
" quiver=True,\n",
" save_dir=plots_directory,\n",
" fig_fn=\"06_disparity_pixels.png\",\n",
" fig_fn=\"disparity_pixels.png\",\n",
")"
]
},
Expand Down Expand Up @@ -155,7 +152,7 @@
"\n",
"plotter.plot_dem_results(\n",
" save_dir=plots_directory,\n",
" fig_fn=\"07_stereo_dem_results.png\",\n",
" fig_fn=\"stereo_dem_results.png\",\n",
")"
]
},
Expand Down Expand Up @@ -191,18 +188,6 @@
" diff_clim=(-5, 5),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"processing_parameters = ProcessingParameters(directory, ba_directory, stereo_directory)\n",
"processing_parameters_dict = processing_parameters.from_log_files()\n",
"\n",
"compile_report(plots_directory, processing_parameters_dict, report_pdf_path)"
]
}
],
"metadata": {
Expand Down
Loading