Module: Gsplat::Utils
- Defined in:
- lib/gsplat/utils.rb
Overview
Point-cloud initialization and scene geometry utilities.
Constant Summary collapse
- SH_C0 =
Degree-zero real spherical-harmonic basis constant.
0.28209479177387814
Class Method Summary collapse
-
.init_from_points(points, colors, **options) ⇒ Object
Initializes raw trainable Gaussian parameters from colored 3D points.
-
.knn(points, k: 4) ⇒ Object
Brute-force Euclidean nearest-neighbor distances, including self at zero.
-
.rgb_to_sh(rgb) ⇒ Object
rubocop:enable Naming/MethodParameterName.
-
.scene_scale(camera_to_worlds) ⇒ Object
Maximum camera-center distance from the mean center.
-
.sh_to_rgb(coefficients) ⇒ Numo::NArray
Converts degree-zero SH coefficients back to RGB values.
Class Method Details
.init_from_points(points, colors, **options) ⇒ Object
Initializes raw trainable Gaussian parameters from colored 3D points. rubocop:disable Metrics/AbcSize
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/gsplat/utils.rb', line 42 def init_from_points(points, colors, **) sh_degree = .fetch(:sh_degree, 3) init_opacity = .fetch(:init_opacity, 0.1) init_scale = .fetch(:init_scale, 1.0) rng = .fetch(:rng, Gsplat.rng) validate_initialization!(points, colors, sh_degree, init_opacity, init_scale) count = points.shape[0] neighbor_count = [4, count].min squared = knn(points, k: neighbor_count)[true, 1...neighbor_count]**2 distance = Numo::NMath.sqrt(squared.mean(axis: 1)) epsilon = points.is_a?(Numo::DFloat) ? 1e-12 : 1e-6 distance[distance.lt(epsilon)] = epsilon log_scales = Numo::NMath.log(distance * init_scale).reshape(count, 1) scales = points.class.zeros(count, 3) scales[true, true] = log_scales quaternions = points.class.cast(Array.new(count * 4) { rng.rand }).reshape(count, 4) opacity = ::Math.log(init_opacity / (1 - init_opacity)) sh0 = rgb_to_sh(points.class.cast(colors)).reshape(count, 1, 3) shn = points.class.zeros(count, ((sh_degree + 1)**2) - 1, 3) { means: variable(points.dup), scales: variable(scales), quats: variable(quaternions), opacities: variable(points.class.ones(count) * opacity), sh0: variable(sh0), shN: variable(shn) } end |
.knn(points, k: 4) ⇒ Object
Brute-force Euclidean nearest-neighbor distances, including self at zero. rubocop:disable Naming/MethodParameterName
13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/gsplat/utils.rb', line 13 def knn(points, k: 4) validate_points!(points) unless k.is_a?(Integer) && k.between?(1, points.shape[0]) raise ArgumentError, "k must be in 1..#{points.shape[0]}" end output = points.class.zeros(points.shape[0], k) points.shape[0].times do |index| distances = Numo::NMath.sqrt(((points - points[index, true])**2).sum(axis: 1)) output[index, true] = distances.sort[0...k] end output end |
.rgb_to_sh(rgb) ⇒ Object
rubocop:enable Naming/MethodParameterName
28 29 30 |
# File 'lib/gsplat/utils.rb', line 28 def rgb_to_sh(rgb) (rgb - 0.5) / SH_C0 end |
.scene_scale(camera_to_worlds) ⇒ Object
Maximum camera-center distance from the mean center.
73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/gsplat/utils.rb', line 73 def scene_scale(camera_to_worlds) unless camera_to_worlds.is_a?(Numo::NArray) && camera_to_worlds.ndim == 3 && camera_to_worlds.shape[1..] == [4, 4] actual = camera_to_worlds.respond_to?(:shape) ? camera_to_worlds.shape.inspect : camera_to_worlds.class raise ShapeError, "expected camera_to_worlds [C,4,4], got #{actual}" end locations = camera_to_worlds[true, 0...3, 3] center = locations.mean(axis: 0) Numo::NMath.sqrt(((locations - center)**2).sum(axis: 1)).max.to_f end |
.sh_to_rgb(coefficients) ⇒ Numo::NArray
Converts degree-zero SH coefficients back to RGB values.
36 37 38 |
# File 'lib/gsplat/utils.rb', line 36 def sh_to_rgb(coefficients) (coefficients * SH_C0) + 0.5 end |