feature_register op• Data kinds: points × normals → descriptor
• Call: import fullseye as fs; fs.ledger.shot_descriptor(points, normals, kp_idx, tree, radius, n_azim=8, n_elev=2, n_rad=2, n_cos=11) (to call the implementation directly, import feat_shot; feat_shot.shot_descriptor(points, normals, kp_idx, tree, radius, n_azim=8, n_elev=2, n_rad=2, n_cos=11); from the registry, ops3d.get("shot_descriptor"))
The SHOT descriptor (Tombari 2010). It builds a local reference frame at each keypoint and takes a spherical support.
The support is divided into radial 2 × elevation 2 × azimuth 8 = 32 spatial cells; in each cell, the "cosine of the angle between the LRF z axis and the neighbour point normal" is accumulated by quadrilinear interpolation into a histogram of n_cos=11 bins → the 32×11=352 dimensions are L2-normalised. Returns (Kp,352). Points without a valid LRF get a zero vector.
Raises ValueError: if the row count of normals does not match points (mixing in the normals of another point cloud makes neighbour indices go out of range and raise a raw IndexError — the same class as compute_fpfh).
Arguments: points (N,3), normals (N,3) unit normals, kp_idx are the point indices of the keypoints (output of iss_keypoints), tree is a scipy.spatial.cKDTree built from points (prepared by the caller), radius is the support radius (used both for LRF estimation and for gathering neighbours). Changing n_azim, n_elev, n_rad, n_cos makes the dimension n_azim*n_elev*n_rad*n_cos.
Procedure: the LRF takes the eigenvectors of the covariance with distance weight max(radius-d, 0) (x = largest, z = smallest eigenvalue), aligns them to the sign of the neighbour majority and makes the frame right-handed. Keypoints with fewer than 5 neighbours, or whose LRF is degenerate, stay zero vectors (they are excluded on the matching side). Each neighbour point is linearly interpolated in radius, elevation (arccos(qz/r)/π) and normal cosine angle with bin centres at 0.5, while azimuth is wrapped around the circle and accumulated; finally each row is L2-normalised. Returns float64 (len(kp_idx), n_azim*n_elev*n_rad*n_cos) (352 by default). When comparing 2 clouds, use the same radius and the same normal sign rule on both sides (if the normal orientation is flipped, the cosine-angle histogram is mirrored). register_shot applies this function to both clouds and goes on through matching and RANSAC.
• blas_threads_and_memory — Why matrix decompositions are slow — BLAS threads, caches, memory layout
• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).
• Operator provenance and references — the sources of the research/methods this op family came from.
• feature_register — py -3.11 examples_3d/feature_register.py
descriptor as input)fuse_to_voxel · shape_distance
feature_register)harris3d_keypoints · iss_keypoints · compute_fpfh · register_spin · register_fpfh · register_shot
*Provenance: feat_shot.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.