upsp.cam_cal_utils.visibility
¶
- class VisibilityChecker(grid_path, oblique_angle=70, epsilon=0.0001, debug=False, debug_nogrid=False)[source]¶
Bases:
object
Visibilty object class for occlusion and viewing angle checking
This class creates an object for checking visibility of a list of points with associated normals. The intended use is for the external calibration to check target visibility, and to check visibility of the the model mesh nodes for node-pixel mapping.
For the visibility check, it is assumes that the entire model is within the field of view of the camera. This simplifies the check for 2 reasons:
We don’t need to check if a node is within the field of view
We don’t need to check if an intersection is behind the camera
A ray is drawn from a given point to the camera. If that ray intersects a node, it is deemed not visible. However, if there is a node behind the camera that intersects with the ray, this will still be seen as an intersection and flagged as not visible. Even though the intersection behind the camera does not truly occlude the given point.
- Parameters
grid_path (
str
) – Filepath to the grid fileoblique_angle (
float
, optional) – Maximum allowable oblique viewing angle. Viewing angle for a node pointed directly at the camera and in the center of the field of view of the camera is 0 degreesepsilon (
float
, optional) – Intersection tolerance. For the ray tracing intersection check, the origin of the ray is offset from the model by a distance of epsilon in the direction of the normaldebug (
bool
, optional) – Debug parameter to speed up grid loading. It is suggested to use this debug for all development, and to leave it False for all non-development case. If True, looks for'{{filename}}_primitives.npy'
in ‘.cache’, wherefilename
is the filename from grid_path. If it finds it, loads from the.npy
file rather than reading and processing the grid file. If it doesn’t find it, it will read and process the grid file as normal, and save the numpy array as'{{filename}}_primitives.npy'
in ‘.cache’debug_nogrid (
bool
, optional) – Debug parameter to speed up computation. It is suggested to use this debug for development if occlusions are not needed for development work. There is no reason to leave this parameter for any non-development work. If True, instead of loading a real grid file, it loads a fake one with a single, extremely small primitive (effectively having ‘no grid’). This makes BVH operations much faster.
- angle_between(v1, v2)[source]¶
Returns the angle in radians between vectors v1 and v2
- Parameters
v1 (
numpy.ndarray
,shape (n
,3)
,float
) – Vector 1v2 (
numpy.ndarray
,shape (n
,3)
,float
) – Vector 2
- Returns
angle – Angle (in radians) between v1 and v2
- Return type
See also
unit_vector
Returns the unit vector of the vector
is_back_facing
This is the ‘slow’ version of the back face culling check
- does_intersect(origin, direction, return_pos=False)[source]¶
Function that determines if a point is occluded by the object mesh
Creates a ray from origin with given direction. Checks for intersection of ray with the BVH
- Parameters
origin (
numpy.ndarray
,shape (3
,1)
,float
) – start of raydirection (
numpy.ndarray
,shape (3
,1)
,float
) – direction of ray
- Returns
result – True if node is occluded and False if node is not occluded
- Return type
- get_faces_and_face_normals()[source]¶
Returns the faces and face normals of all grid nodes
- Returns
faces (
numpy.ndarray
,shape (n
,3
,3)
) – Each face is a (3, 3) with (i, 3) corresponding to a node, and each node having an (x, y, z). Faces are ordered counter-clockwise.face_normals (
numpy.ndarray
,shape (n
,3)
) – The face normal is (x, y, z).face_normals[i]
corresponds toface[i]
- get_tvecs_and_norms()[source]¶
Returns the tvecs and tvec normals of all grid nodes
- Returns
tvecs (
numpy.ndarray
,shape (n
,3)
) – Each tvec is corresponds to the (x, y, z) of a node.norms (
numpy.ndarray
,shape (n
,3)
) – Each norm is an (x, y, z) of the node’s normal vectornorms[i]
corresponds totvecs[i]
. The norm is the normal of the first face to contain the tvec. Each tvec can appear in multiple faces, so the first is used. In practice, each face that contains the node will have a different normal vector, but in general the difference is a relatively small angle.
- is_back_facing(t, n)[source]¶
This is the ‘slow’ version of the back face culling check
This function is mostly for legacy/regression purposes
TODO: This does not filter points on the horizon of the model (~90 degrees oblique viewing angle). It does seem to filter those above 70 degrees (might not though, very little testing was done). It might have something to do with the clip in angle between
- Parameters
t (
numpy.ndarray
,shape (3,)
or(3
,n)
,float
) – Translation vector from camera to noden (
numpy.ndarray
,shape (3,)
or(3
,n)
,float
) – Normal of the node
- Returns
back_facing – True if the node is back facing. False if it is not back facing
- Return type
See also
angle_between
Returns the angle in radians between vectors ‘v1’ and ‘v2’
is_back_facing
This is the ‘slow’ version of the back face culling check
is_back_facing_fast_vectorized
Returns array of booleans for which nodes are back facing
- is_back_facing_fast(t, n)[source]¶
Returns True if the node is back facing, otherwise returns False
This re-write is significantly faster than the naive approach, but not as fast as the vectorized approach. This function is mostly for legacy/regression purposes
The node is back facing if angle between vectors < oblique angle
Mathematically this is done as:
\[\arccos\left(\frac{t \cdot n}{\|t\| \|n\|}\right) < \textrm{oblique angle}\]Since
arccos
is an expensive operation, re-write as:\[\frac{t \cdot n}{\|t\| \|n\|} < \cos(\textrm{oblique angle})\]Since division is more expensive than multiplication, re-write as:
\[t \cdot n < \|t\| \|n\| \cos(\textrm{oblique angle})\]Using \(\|a\|^2 = a \cdot a\), we get:
\[(t \cdot n) (|t \cdot n|) < (t \cdot t) (n \cdot n) \cos^2(\textrm{oblique angle})\]Where the absolute value is required on the LHS to preserve sign. All elements of RHS are positive since
t
andn
contain only real numbers\(\cos^2(\textrm{oblique angle})\) is calculated and cached when the oblique angle changes, giving an additional speedup
- Parameters
t (
numpy.ndarray
,shape (3
,1)
or(3,)
,float
) – Translation vector from camera to noden (
numpy.ndarray
,shape (3
,1)
or(3,)
,float
) – Normal of the node
- Returns
back_facing – True if input is back facing (viewing angle > maximum oblique angle). False if input is not back facing (viewing angle <= maximum oblique angle)
- Return type
See also
is_back_facing
This is the ‘slow’ version of the back face culling check
is_back_facing_fast_vectorized
Returns array of booleans for which nodes are back facing
- is_back_facing_fast_vectorized(t, n)[source]¶
Returns array of booleans for which nodes are back facing
See
is_back_facing_fast()
for explaination of math. To vectorize \(a \cdot b\) we usenp.sum(a*b, axis=1)
- Parameters
t (
numpy.ndarray
,shape (N
,3)
,float
) – Array of translation vectors from camera to nodesn (
numpy.ndarray
,shape (N
,3)
,float
) – Array of normal vectors of the nodes
- Returns
back_facing –
output[i]
is True ifnode[i]
is backfacing (viewing angle > maximum oblique angle).output[i]
is False ifnode[i]
is not backfacing (viewing angle <= maximum oblique angle).- Return type
See also
is_back_facing
This is the ‘slow’ version of the back face culling check
is_back_facing_fast
Returns True if the node is back facing, otherwise returns False
- is_visible(tvec_model_to_camera, nodes, normals, return_angles=False)[source]¶
Returns list of nodes that are visible
Currently only checks for oblique viewing angle and occlusion, assumes all nodes are within FOV of camera
- Parameters
tvec_model_to_camera (
numpy.ndarray
,shape (3
,1)
,float
) – translation vector from model to cameranodes (
numpy.ndarray
,shape (N
,3)
,float
) – X, Y, Z position of nodes to be checked.nodes[i]
is associated withnormals[i]
normals (
numpy.ndarray
,shape (N
,3)
,float
) – Normal vectors.normals[i]
is associated withnodes[i]
return_angles (
bool
, optional) – If True, return angles for each visible node as well.
- Returns
visible (
numpy.ndarray
) – Numpy array of the indices of the nodes that are visibleangles (
numpy.ndarray
) – Angles of visible nodes. Only returned whenreturn_angles=True
See also
is_back_facing_fast_vectorized
Returns array of booleans for which nodes are back facing
does_intersect
Function that determines if a point is occluded by the object mesh
- load_mesh(grid_path)[source]¶
Loads the grid file into vertices and indices
- Parameters
grid_path (
string
) – Filepath to the grid file- Returns
t – Dict with keys “vertices” and “indices”.
t["vertices"]
is a (N, 3) array of the model vertices.t["indices"]
is a (N, 3) array of ints where each row refers to a model facei
. The vertices that make up facei
aret["vertices"][n]
, wheren
is (3, 1) fromt["indices"][i]
- Return type
- package_primitives(t)[source]¶
Packages the primitives of the grid file into the BVH format
Converts the vertices and indices into a list of primitives in the form:
[t0p0x, t0p0y, t0p0z, t0p1x, t0p1y, t0p1z, t0p2x, t0p2y, t0p2z, ...]
- Parameters
t (
dict
) – Dict with keys “vertices” and “indices” fromload_mesh()
.- Returns
primitives – Packaged primitives
- Return type
- tri_normal(face)[source]¶
Returns the normal of a face with vertices ordered counter-clockwise
- Parameters
face (
numpy.ndarray
,shape (3
,3)
,float
) – X, Y, Z positions of the face vertices.face[i]
contains x, y, z of vertexi
- Returns
normal – Normal vector of input face
- Return type
numpy.ndarray
,shape (3,)
- unit_vector(vector)[source]¶
Returns the unit vector of the vector
Helper function for
angle_between()
- Parameters
vector (
numpy.ndarray
,shape (n
,3) float
) – Array of vectors- Returns
unit_vector – Unit vector(s) corresponding to vector
- Return type
See also
angle_between
Returns the angle in radians between vectors ‘v1’ and ‘v2’
- update_oblique_angle(oblique_angle)[source]¶
Updates object elements related to the oblique viewing angle
- Parameters
oblique_angle (
float
) – Maximum allowable oblique viewing angle. Viewing angle for a node pointed directly at the camera and in the center of the field of view of the camera is 0 degrees