Skip to content

Commit

Permalink
Merge branch '165-input-variable-init-disp-grids' into 'release'
Browse files Browse the repository at this point in the history
Resolve "Disparité initiale variable : Mise en place des grilles en entrées"

See merge request 3d/PandoraBox/pandora2d!151
  • Loading branch information
lecontm committed Sep 12, 2024
2 parents 507e8ca + 7ea1686 commit c73a60c
Show file tree
Hide file tree
Showing 18 changed files with 1,144 additions and 158 deletions.
Binary file modified data_samples/images/maricopa.zip
Binary file not shown.
30 changes: 30 additions & 0 deletions data_samples/json_conf_files/a_variable_disparity_pipeline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"input": {
"left": {
"img": "./maricopa/left.tif",
"nodata": -9999
},
"right": {
"img": "./maricopa/right.tif",
"nodata": -9999
},
"col_disparity": {"init": "./maricopa/init_col_disparity_grid.tif", "range": 5},
"row_disparity": {"init": "./maricopa/init_row_disparity_grid.tif", "range": 5}
},
"pipeline": {
"matching_cost": {
"matching_cost_method": "zncc",
"window_size": 5
},
"disparity": {
"disparity_method": "wta",
"invalid_disparity": "NaN"
},
"refinement": {
"refinement_method": "dichotomy",
"iterations": 2,
"filter": {"method": "bicubic"}
}
}
}

7 changes: 7 additions & 0 deletions docs/source/exploring_the_field/initial_disparity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ In the configuration file, the user is required to enter disparity range for row
}
}
.. note::
The "init" key can be either:
- an integer if the initial disparity is common to every point in the image.
- a path to a disparity grid if each point has its own initial disparity value.

(see :ref:`inputs`)

The min and max disparity would then be equal to (example for columns):

.. code:: python
Expand Down
41 changes: 38 additions & 3 deletions docs/source/userguide/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ Image (left and right) and disparity (col_disparity and row_disparity) propertie
- Default value
- Required
* - *init*
- Initial point
- int
- Initial point or path to initial grid
- int or str
-
- Yes
* - *range*
Expand All @@ -92,6 +92,12 @@ Image (left and right) and disparity (col_disparity and row_disparity) propertie
-
- Yes

.. note::
The initial disparity can be either:
- constant for each point in the image, in which case *init* dictionary key is an integer
- variable, in which case *init* is a string which returns the path to a grid containing
an integer initial value for each point in the image.

.. warning::
With sad/ssd matching_cost_method in the pipeline (see :ref:`Sequencing`) , `nodata` only accepts `int` type.

Expand All @@ -101,7 +107,10 @@ Image (left and right) and disparity (col_disparity and row_disparity) propertie
- Value not equal to 0 for invalid pixel


**Example**
Examples
********

**Input with constant initial disparity**

.. code:: json
:name: Input example
Expand All @@ -128,3 +137,29 @@ Image (left and right) and disparity (col_disparity and row_disparity) propertie
}
}
**Input with variable initial disparity**

.. code:: json
:name: Input example with disparity grid
{
"input":
{
"left": {
"img": "./data/left.tif",
"nodata": -9999,
"mask": "./data/mask_left.tif"
},
"right": {
"img": "/data/right.tif",
"nodata": -9999
},
"col_disparity": {"init": "./data/col_disparity_grid.tif", "range": 3},
"row_disparity": {"init": "./data/row_disparity_grid.tif", "range": 3}
}
,
"pipeline" :
{
// pipeline content
}
}
99 changes: 93 additions & 6 deletions pandora2d/check_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
import numpy as np
import xarray as xr
from json_checker import And, Checker, Or
from rasterio.io import DatasetReader

from pandora.img_tools import get_metadata
from pandora.img_tools import get_metadata, rasterio_open
from pandora.check_configuration import (
check_dataset,
check_images,
Expand Down Expand Up @@ -102,13 +103,99 @@ def check_input_section(user_cfg: Dict[str, dict], estimation_config: dict = Non

if estimation_config is None:
left_image_metadata = get_metadata(cfg["input"]["left"]["img"])
check_disparity_ranges_are_inside_image(
left_image_metadata, cfg["input"]["row_disparity"], cfg["input"]["col_disparity"]
)
check_disparity(left_image_metadata, cfg["input"])

return cfg


def check_disparity(image_metadata: xr.Dataset, input_cfg: Dict) -> None:
"""
All checks on disparity
:param image_metadata: only metadata on the left image
:type image_metadata: xr.Dataset
:param input_cfg: input configuration
:type input_cfg: Dict
"""

# Check that disparities are dictionaries or grids
if not (isinstance(input_cfg["row_disparity"], dict) and isinstance(input_cfg["col_disparity"], dict)):
raise AttributeError("The disparities in rows and columns must be given as 2 dictionaries.")

if isinstance(input_cfg["row_disparity"]["init"], str) and isinstance(input_cfg["col_disparity"]["init"], str):

# Read disparity grids
disparity_row_reader = rasterio_open(input_cfg["row_disparity"]["init"])
disparity_col_reader = rasterio_open(input_cfg["col_disparity"]["init"])

# Check disparity grids size and number of bands
check_disparity_grids(image_metadata, disparity_row_reader)
check_disparity_grids(image_metadata, disparity_col_reader)

# Get correct disparity dictionaries from init disparity grids to give as input of
# the check_disparity_ranges_are_inside_image method
row_disp_dict = get_dictionary_from_init_grid(disparity_row_reader, input_cfg["row_disparity"]["range"])
col_disp_dict = get_dictionary_from_init_grid(disparity_col_reader, input_cfg["col_disparity"]["range"])

elif isinstance(input_cfg["row_disparity"]["init"], int) and isinstance(input_cfg["col_disparity"]["init"], int):
row_disp_dict = input_cfg["row_disparity"]
col_disp_dict = input_cfg["col_disparity"]

else:
raise ValueError("Initial columns and row disparity values must be two strings or two integers")

# Check that disparity ranges are not totally out of the image
check_disparity_ranges_are_inside_image(image_metadata, row_disp_dict, col_disp_dict)


def check_disparity_grids(image_metadata: xr.Dataset, disparity_reader: DatasetReader) -> None:
"""
Check that disparity grids contains two bands and are
the same size as the input image
:param image_metadata:
:type image_metadata: xr.Dataset
:param disparity_reader: disparity grids
:type disparity_reader: rasterio.io.DatasetReader
"""

# Check that disparity grids are 1-channel grids
if disparity_reader.count != 1:
raise AttributeError("Initial disparity grid must be a 1-channel grid")

# Check that disparity grids are the same size as the input image
if (disparity_reader.height, disparity_reader.width) != (
image_metadata.sizes["row"],
image_metadata.sizes["col"],
):
raise AttributeError("Initial disparity grids and image must have the same size")


def get_dictionary_from_init_grid(disparity_reader: DatasetReader, disp_range: int) -> Dict:
"""
Get correct dictionaries to give as input of check_disparity_ranges_are_inside_image method
from initial disparity grids.
:param disparity_reader: initial disparity grid
:type disparity_reader: rasterio.io.DatasetReader
:param disp_range: range of exploration
:type disp_range: int
:return: a disparity dictionary to give to check_disparity_ranges_are_inside_image() method
:rtype: Dict
"""

init_disp_grid = disparity_reader.read(1)

# Get dictionary with integer init value corresponding to the maximum absolute value of init_disp_grid
disp_dict = {
"init": np.max(np.abs(init_disp_grid)),
"range": disp_range,
}

return disp_dict


def check_disparity_ranges_are_inside_image(
image_metadata: xr.Dataset, row_disparity: Dict, col_disparity: Dict
) -> None:
Expand Down Expand Up @@ -283,8 +370,8 @@ def get_roi_config(user_cfg: Dict[str, dict]) -> Dict[str, dict]:
"nodata": Or(int, lambda input: np.isnan(input), lambda input: np.isinf(input)),
"mask": And(Or(str, lambda input: input is None), rasterio_can_open),
},
"col_disparity": {"init": int, "range": And(int, lambda x: x >= 0)},
"row_disparity": {"init": int, "range": And(int, lambda x: x >= 0)},
"col_disparity": {"init": Or(int, rasterio_can_open), "range": And(int, lambda x: x >= 0)},
"row_disparity": {"init": Or(int, rasterio_can_open), "range": And(int, lambda x: x >= 0)},
}

default_short_configuration_input = {
Expand Down
56 changes: 42 additions & 14 deletions pandora2d/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,28 @@ def set_out_of_row_disparity_range_to_other_value(
# WARNING: if one day we switch disp_row with disp_col index should be -2
ndisp_row = data[data_var_name].shape[-1]

for disp_row in range(ndisp_row):
masking = np.nonzero(
np.logical_or(
data.coords["disp_row"].data[disp_row] < min_disp_grid,
data.coords["disp_row"].data[disp_row] > max_disp_grid,
# We want to put special value on points that are not in the global disparity range (row_disparity_source)
if data_var_name == "cost_volumes":
for disp_row in range(ndisp_row):
masking = np.nonzero(
np.logical_or(
(data.coords["disp_row"].data[disp_row] < min_disp_grid)
& (data.coords["disp_row"].data[disp_row] >= data.attrs["row_disparity_source"][0]),
(data.coords["disp_row"].data[disp_row] > max_disp_grid)
& (data.coords["disp_row"].data[disp_row] <= data.attrs["row_disparity_source"][1]),
)
)
)
data[data_var_name].data[masking[0], masking[1], :, disp_row] = value
data[data_var_name].data[masking[0], masking[1], :, disp_row] = value

else:
for disp_row in range(ndisp_row):
masking = np.nonzero(
np.logical_or(
data.coords["disp_row"].data[disp_row] < min_disp_grid,
data.coords["disp_row"].data[disp_row] > max_disp_grid,
)
)
data[data_var_name].data[masking[0], masking[1], :, disp_row] = value


def set_out_of_col_disparity_range_to_other_value(
Expand Down Expand Up @@ -259,11 +273,25 @@ def set_out_of_col_disparity_range_to_other_value(
# WARNING: if one day we switch disp_row with disp_col index should be -1
ndisp_col = data[data_var_name].shape[-2]

for disp_col in range(ndisp_col):
masking = np.nonzero(
np.logical_or(
data.coords["disp_col"].data[disp_col] < min_disp_grid,
data.coords["disp_col"].data[disp_col] > max_disp_grid,
# We want to put special value on points that are not in the global disparity range (col_disparity_source)
if data_var_name == "cost_volumes":
for disp_col in range(ndisp_col):
masking = np.nonzero(
np.logical_or(
(data.coords["disp_col"].data[disp_col] < min_disp_grid)
& (data.coords["disp_col"].data[disp_col] >= data.attrs["col_disparity_source"][0]),
(data.coords["disp_col"].data[disp_col] > max_disp_grid)
& (data.coords["disp_col"].data[disp_col] <= data.attrs["col_disparity_source"][1]),
)
)
data[data_var_name].data[masking[0], masking[1], disp_col, :] = value

else:
for disp_col in range(ndisp_col):
masking = np.nonzero(
np.logical_or(
data.coords["disp_col"].data[disp_col] < min_disp_grid,
data.coords["disp_col"].data[disp_col] > max_disp_grid,
)
)
)
data[data_var_name].data[masking[0], masking[1], disp_col, :] = value
data[data_var_name].data[masking[0], masking[1], disp_col, :] = value
Loading

0 comments on commit c73a60c

Please sign in to comment.