# vin.geometry.semidense_projection { #aria_nbv.vin.geometry.semidense_projection }
`vin.geometry.semidense_projection`
Semidense point projection helpers shared by VIN scorers.
The active :mod:`aria_nbv.vin.models.scene_myopic` scorer uses semidense ASE/EFM points as
actor-visible scene evidence. This module owns the stateless tensor operations
for that path:
- sample valid ``VinSnippetView.points_world`` rows,
- project world points into PyTorch3D candidate cameras,
- encode scalar projection statistics, and
- build screen-space grids consumed by model-owned CNN encoders.
Keeping those operations outside the scorer class makes the geometry contract
testable without constructing the full model while preserving the neural module
ownership boundary in :class:`aria_nbv.vin.models.scene_myopic.VinModelV3`.
## Functions
| Name | Description |
| --- | --- |
| [build_projection_grid](#aria_nbv.vin.geometry.semidense_projection.build_projection_grid) | Build per-camera semidense projection grids for CNN encoders. |
| [encode_projection_summary](#aria_nbv.vin.geometry.semidense_projection.encode_projection_summary) | Summarize semidense projection coverage, visibility, and depth. |
| [project_points_to_candidate_cameras](#aria_nbv.vin.geometry.semidense_projection.project_points_to_candidate_cameras) | Project world points into a batch of candidate cameras. |
| [sample_semidense_points](#aria_nbv.vin.geometry.semidense_projection.sample_semidense_points) | Sample valid semidense world points from a VIN snippet. |
### build_projection_grid { #aria_nbv.vin.geometry.semidense_projection.build_projection_grid }
```python
vin.geometry.semidense_projection.build_projection_grid(
proj_data,
*,
device,
dtype,
grid_size,
)
```
Build per-camera semidense projection grids for CNN encoders.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|-----------|------------------------------------------------------------------|----------------------------------------------------------|------------|
| proj_data | [dict](`dict`)\[[str](`str`), [Tensor](`torch.Tensor`)\] \| None | Output from :func:`project_points_to_candidate_cameras`. | _required_ |
| device | [torch](`torch`).[device](`torch.device`) | Target device for the grid. | _required_ |
| dtype | [torch](`torch`).[dtype](`torch.dtype`) | Output dtype consumed by the caller-owned CNN. | _required_ |
| grid_size | [int](`int`) | Screen-space bin count per side. | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|--------------------------|------------------------------------------------------------------------|
| | [Tensor](`torch.Tensor`) | ``Tensor["B*N_q C_grid G G", float32]`` containing occupancy, mean |
| | [Tensor](`torch.Tensor`) | camera-frame depth in metres, and depth standard-deviation grids, with |
| | [Tensor](`torch.Tensor`) | ``C_grid == SEMIDENSE_GRID_CHANNELS``. |
### encode_projection_summary { #aria_nbv.vin.geometry.semidense_projection.encode_projection_summary }
```python
vin.geometry.semidense_projection.encode_projection_summary(
proj_data,
*,
batch_size,
num_candidates,
device,
dtype,
grid_size,
obs_count_max,
inv_dist_std_min,
inv_dist_std_p95,
)
```
Summarize semidense projection coverage, visibility, and depth.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|------------------|------------------------------------------------------------------|-------------------------------------------------------------------|------------|
| proj_data | [dict](`dict`)\[[str](`str`), [Tensor](`torch.Tensor`)\] \| None | Output from :func:`project_points_to_candidate_cameras`. | _required_ |
| batch_size | [int](`int`) | Batch size ``B``. | _required_ |
| num_candidates | [int](`int`) | Candidate count ``N_q`` per batch item. | _required_ |
| device | [torch](`torch`).[device](`torch.device`) | Target device for features. | _required_ |
| dtype | [torch](`torch`).[dtype](`torch.dtype`) | Output dtype. | _required_ |
| grid_size | [int](`int`) | Screen-space bin count per side for coverage. | _required_ |
| obs_count_max | [int](`int`) | Saturation point for the ``log1p(n_obs)`` reliability factor. | _required_ |
| inv_dist_std_min | [float](`float`) | Lower bound for inverse depth-uncertainty scaling. | _required_ |
| inv_dist_std_p95 | [float](`float`) | Upper reference percentile for inverse depth-uncertainty scaling. | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|--------------------------|----------------------------------------------|
| | [Tensor](`torch.Tensor`) | ``Tensor["B N_q F_proj", float32]`` with |
| | [Tensor](`torch.Tensor`) | ``F_proj == SEMIDENSE_PROJ_DIM``, ordered by |
| | [Tensor](`torch.Tensor`) | `SEMIDENSE_PROJ_FEATURES`. |
### project_points_to_candidate_cameras { #aria_nbv.vin.geometry.semidense_projection.project_points_to_candidate_cameras }
```python
vin.geometry.semidense_projection.project_points_to_candidate_cameras(
points_world,
p3d_cameras,
*,
batch_size,
num_candidates,
device,
)
```
Project world points into a batch of candidate cameras.
This is the shared projection path for semidense points and pooled voxel
centers. It enforces the PyTorch3D camera batch contract used by
:class:`aria_nbv.vin.models.scene_myopic.VinModelV3`: the camera batch is either
``Nq`` when ``B == 1`` or ``B * Nq`` for true batched inputs.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|----------------|-----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|
| points_world | [Tensor](`torch.Tensor`) \| None | ``Tensor["P C", float32]`` or ``Tensor["B P C", float32]`` in the world frame; XYZ is measured in metres. ``C`` must include XYZ; additional channels are propagated as ``inv_dist_std`` and optional ``obs_count`` when present. | _required_ |
| p3d_cameras | [PerspectiveCameras](`pytorch3d.renderer.cameras.PerspectiveCameras`) | PyTorch3D candidate camera batch with ``image_size``. | _required_ |
| batch_size | [int](`int`) | Batch size ``B``. | _required_ |
| num_candidates | [int](`int`) | Candidate count ``N_q`` per batch item. | _required_ |
| device | [torch](`torch`).[device](`torch.device`) | Target device for projection tensors. | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|----------------------------------------------------------|---------------------------------------------------------------------|
| | [dict](`dict`)\[[str](`str`), [Tensor](`torch.Tensor`)\] | Dictionary with screen coordinates ``x``/``y``, camera depth ``z``, |
| | [dict](`dict`)\[[str](`str`), [Tensor](`torch.Tensor`)\] | ``finite`` and ``valid`` masks, optional reliability channels, |
| | [dict](`dict`)\[[str](`str`), [Tensor](`torch.Tensor`)\] | ``image_size``, and scalar ``num_cams``. |
### sample_semidense_points { #aria_nbv.vin.geometry.semidense_projection.sample_semidense_points }
```python
vin.geometry.semidense_projection.sample_semidense_points(
snippet,
*,
device,
max_points,
)
```
Sample valid semidense world points from a VIN snippet.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|------------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|
| snippet | [Any](`typing.Any`) | Object with the :class:`aria_nbv.data_handling.vin_store.views.VinSnippetView` point contract. It must expose ``points_world`` as ``Tensor["P C", float32]`` or ``Tensor["B P C", float32]`` and optional ``lengths``. XYZ is measured in metres, ``1/sigma_d`` in inverse metres, and optional ``n_obs`` in channel five is a dimensionless count. | _required_ |
| device | [torch](`torch`).[device](`torch.device`) | Target device for the returned tensor. | _required_ |
| max_points | [int](`int`) | Maximum sampled point count per batch item. Batched inputs are padded to this length with NaNs so candidate projection keeps a rectangular ``Tensor["B P_fr C", float32]`` layout. | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|--------------------------|----------------------------------------------------------------------|
| | [Tensor](`torch.Tensor`) | ``Tensor["P_fr C", float32]`` or ``Tensor["B P_max C", float32]`` on |
| | [Tensor](`torch.Tensor`) | ``device``. |
#### Raises {.doc-section .doc-section-raises}
| Name | Type | Description |
|--------|--------------------------------|----------------------------------------------------------------------------------------------------------------|
| | [RuntimeError](`RuntimeError`) | If the snippet has no valid points. |
| | [ValueError](`ValueError`) | If the point tensor has an invalid shape, insufficient channels, mismatched lengths, or non-finite XYZ values. |