GeoLens
Differentiable multi-element refractive lens via geometric ray tracing.
GeoLens is the primary lens model in DeepLens: it ray-traces through a stack of
optical surfaces to compute PSFs, render images, and optimize
lens geometry end-to-end.
deeplens.GeoLens
GeoLens(
filename=None,
device=None,
dtype=torch.float32,
primary_wvln=DEFAULT_WAVE,
wvln_rgb=WAVE_RGB,
obj_depth=DEPTH,
)
Bases: GeoLensPSF, GeoLensRender, GeoLensEval, GeoLensOptim, GeoLensOps, GeoLensVis, GeoLensIO, GeoLensVis3D, Lens
Differentiable geometric lens using vectorised ray tracing.
The primary lens model in DeepLens. Supports multi-element refractive
(and partially reflective) systems loaded from JSON, Zemax .zmx, or
Code V .seq files. Accuracy is aligned with Zemax OpticStudio.
Uses a mixin architecture: eight specialised mixin classes are composed
at class-definition time to keep each concern isolated: GeoLensPSF
(PSF computation), GeoLensRender (image simulation: render dispatch
and reverse ray tracing), GeoLensEval
(spot/MTF/distortion/vignetting evaluation), GeoLensOptim
(losses and gradient-based optimisation), GeoLensOps (in-place lens
operations), GeoLensVis (2-D layout/ray visualisation), GeoLensIO
(JSON/Zemax read-write), and GeoLensVis3D (3-D mesh visualisation).
Attributes:
| Name | Type | Description |
|---|---|---|
surfaces |
list[Surface]
|
Ordered list of optical surfaces. |
d_sensor |
Tensor
|
Derived distance from the first surface to the sensor plane [mm]. |
foclen |
float
|
Effective focal length [mm]. |
fnum |
float
|
F-number. |
rfov |
float
|
Real half-diagonal field of view [radians]. |
sensor_size |
tuple
|
Physical sensor size (W, H) [mm]. |
sensor_res |
tuple
|
Sensor resolution (W, H) [pixels]. |
pixel_size |
float
|
Pixel pitch [mm]. |
Reference
Xinge Yang et al., "Curriculum learning for ab initio deep learned refractive optics," Nature Communications 2024.
Initialize a refractive lens.
There are two ways to initialize a GeoLens
- Read a lens from .json/.zmx/.seq file
- Initialize a lens with no lens file, then manually add surfaces
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path to lens file (.json, .zmx, or .seq). Defaults to None. |
None
|
device
|
device
|
Device for tensor computations. Defaults to None. |
None
|
dtype
|
dtype
|
Data type for computations. Defaults to torch.float32. |
float32
|
primary_wvln
|
float
|
Primary design wavelength [µm].
Used as fallback when a method is called without an explicit
|
DEFAULT_WAVE
|
wvln_rgb
|
sequence of float
|
Three wavelengths used
for RGB computations, ordered |
WAVE_RGB
|
obj_depth
|
float
|
Default object depth [mm], used
when a method is called without an explicit |
DEPTH
|
Source code in deeplens-src/deeplens/geolens.py
d_sensor
property
writable
Global axial position of the sensor plane [mm].
Surface 0 is the origin. The sensor position is derived by summing each
surface's d_next, so the image plane remains part of the same
differentiable sequential thickness chain.
read_lens
Read a GeoLens from a file.
Supported file formats
- .json: DeepLens native JSON format
- .zmx: Zemax lens file format
- .seq: CODE V sequence file format
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path to the lens file. |
required |
Note
Sensor size and resolution will usually be overwritten by values from the file.
Source code in deeplens-src/deeplens/geolens.py
post_computation
Compute derived optical properties after loading or modifying lens.
Calculates and caches
- Effective focal length (EFL)
- Entrance and exit pupil positions and radii
- Field of view (FoV) in horizontal, vertical, and diagonal directions
- F-number
- Lens design constraints (edge/center thickness bounds, etc.)
Note
This method should be called after any changes to the lens geometry.
Source code in deeplens-src/deeplens/geolens.py
__call__
Trace rays through the lens system (callable shorthand for trace).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ray_out |
Ray
|
Ray after propagation through the surfaces. |
ray_o_record |
list or None
|
Recorded ray positions, or None. |
Source code in deeplens-src/deeplens/geolens.py
sample_grid_rays
sample_grid_rays(
depth=float("inf"),
num_grid=(11, 11),
num_rays=SPP_PSF,
wvln=None,
uniform_fov=True,
sample_more_off_axis=False,
scale_pupil=1.0,
)
Sample a grid of rays spanning the field of view from object space.
If depth is infinite, samples collimated rays at evenly-spaced field
angles; if depth is finite, samples diverging point-source rays from a
grid of object points. Used for PSF maps, RMS error maps, and spot
diagrams.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
float
|
Object distance in mm. Use |
float('inf')
|
num_grid
|
int or tuple
|
Number of grid points as (num_x, num_y), or a single int for both. Defaults to (11, 11). |
(11, 11)
|
num_rays
|
int
|
Number of rays per grid point. Defaults to SPP_PSF. |
SPP_PSF
|
wvln
|
float
|
Wavelength in µm. When None (default),
falls back to |
None
|
uniform_fov
|
bool
|
If True, sample uniform FoV angles; otherwise sample a uniform object grid. Defaults to True. |
True
|
sample_more_off_axis
|
bool
|
If True, concentrate grid samples toward off-axis fields. Defaults to False. |
False
|
scale_pupil
|
float
|
Scale factor for pupil radius. Defaults to 1.0. |
1.0
|
Returns:
| Name | Type | Description |
|---|---|---|
rays |
Ray
|
Sampled rays with shape [num_grid[1], num_grid[0], num_rays, 3]. |
Source code in deeplens-src/deeplens/geolens.py
sample_radial_rays
sample_radial_rays(
num_field=5,
depth=float("inf"),
num_rays=SPP_PSF,
wvln=None,
direction="y",
fov_max=None,
)
Sample radial rays at evenly-spaced field angles along a chosen direction.
The sampled angles are radial field angles: for "diagonal" the
per-axis components are atan(tan(fov) / sqrt(2)) so that a field
listed as fov really lands at radial angle fov, matching the
"x" and "y" directions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_field
|
int
|
Number of field angles from on-axis to full-field. Defaults to 5. |
5
|
depth
|
float
|
Object distance in mm. Use |
float('inf')
|
num_rays
|
int
|
Rays per field position. Defaults to |
SPP_PSF
|
wvln
|
float
|
Wavelength in µm. When |
None
|
direction
|
str
|
Sampling direction —
|
'y'
|
fov_max
|
float
|
Full-field radial angle [radians]. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Ray object with shape |
Source code in deeplens-src/deeplens/geolens.py
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | |
sample_from_points
sample_from_points(
points=[[0.0, 0.0, -10000.0]],
num_rays=SPP_PSF,
wvln=None,
entrance_pupil=True,
scale_pupil=1.0,
)
Sample rays from point sources in object space (absolute physical coordinates).
Rays originate at the given object points and fan out toward the entrance pupil. Used for PSF and chief-ray calculation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
list or Tensor
|
Object-space ray origins [mm] with shape [3], [N, 3], or [Nx, Ny, 3]. Defaults to [[0.0, 0.0, -10000.0]]. |
[[0.0, 0.0, -10000.0]]
|
num_rays
|
int
|
Number of rays per point. Defaults to SPP_PSF. |
SPP_PSF
|
wvln
|
float
|
Wavelength in µm. When None (default), falls back to
|
None
|
entrance_pupil
|
bool
|
If True (default), aim rays at the entrance pupil; otherwise at surface 0. |
True
|
scale_pupil
|
float
|
Scale factor for pupil radius. Defaults to 1.0. |
1.0
|
Returns:
| Name | Type | Description |
|---|---|---|
rays |
Ray
|
Sampled rays with shape [*points.shape[:-1], num_rays, 3]. |
Source code in deeplens-src/deeplens/geolens.py
sample_from_fov
sample_from_fov(
fov_x=[0.0],
fov_y=[0.0],
depth=float("inf"),
num_rays=SPP_CALC,
wvln=None,
entrance_pupil=True,
scale_pupil=1.0,
)
Sample rays from object space at given field angles.
For infinite depth, generates collimated parallel rays: origins are distributed on the entrance pupil and all rays in a field share the same direction determined by the FOV angle.
For finite depth, generates diverging point-source rays: the point source position is determined by FOV angle and depth, and rays fan out toward the entrance pupil.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fov_x
|
float or list
|
Field angle(s) in the xz plane (degrees). |
[0.0]
|
fov_y
|
float or list
|
Field angle(s) in the yz plane (degrees). |
[0.0]
|
depth
|
float
|
Object distance in mm. |
float('inf')
|
num_rays
|
int
|
Number of rays per field point. |
SPP_CALC
|
wvln
|
float
|
Wavelength in µm. When |
None
|
entrance_pupil
|
bool
|
If True, sample on entrance pupil; otherwise on surface 0. Default: True. |
True
|
scale_pupil
|
float
|
Scale factor for pupil radius. |
1.0
|
Returns:
| Name | Type | Description |
|---|---|---|
rays |
Ray
|
Rays with shape |
Source code in deeplens-src/deeplens/geolens.py
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | |
sample_circle
Sample points uniformly inside a circle on a constant-z plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
r
|
float
|
Radius of the circle [mm]. |
required |
z
|
float
|
Z-coordinate shared by all sampled points [mm]. |
required |
shape
|
list
|
Shape of the point grid (excluding the trailing coordinate dimension). Defaults to [16, 16, 512]. |
[16, 16, 512]
|
Returns:
| Name | Type | Description |
|---|---|---|
points |
Tensor
|
Sampled points with shape [*shape, 3]. |
Source code in deeplens-src/deeplens/geolens.py
trace
Trace rays through the lens.
Forward or backward tracing is selected automatically from the sign of the ray z-direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
surf_range
|
range
|
Range of surface indices to trace through. When None (default), traces through all surfaces. |
None
|
record
|
bool
|
If True, record ray positions at each surface. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
ray_out |
Ray
|
Ray after propagation through the surfaces. |
ray_o_record |
list or None
|
Recorded ray positions at each surface, or None when record is False. |
Source code in deeplens-src/deeplens/geolens.py
trace2obj
Trace rays through the lens toward object space.
Convenience wrapper around trace that discards the position record.
Typically called with sensor-side (backward-propagating) rays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Ray after propagation through the lens. |
Source code in deeplens-src/deeplens/geolens.py
trace2sensor
Forward trace rays through the lens and propagate them to the sensor plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
record
|
bool
|
If True, record ray positions at each surface. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Ray propagated to the sensor plane. When record is True, returns a tuple (ray, ray_o_record) where ray_o_record is the list of recorded ray positions at each surface (invalid points set to NaN). |
Source code in deeplens-src/deeplens/geolens.py
trace2exit_pupil
Forward trace rays through the lens to exit pupil plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Ray object propagated to the exit pupil plane. |
Source code in deeplens-src/deeplens/geolens.py
forward_tracing
Trace forward using sequential per-surface reference frames.
Rays enter and leave in global coordinates. Interactions happen with
each vertex at local z=0; after a surface, the ray origin is shifted by
-d_next to express it in the next surface's frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
surf_range
|
range
|
Range of surface indices to trace through. |
required |
record
|
bool
|
If True, record ray positions at each surface. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ray_out |
Ray
|
Ray after propagation through all surfaces. |
ray_o_record |
list or None
|
Ray positions at each surface, or None if record is False. |
Source code in deeplens-src/deeplens/geolens.py
backward_tracing
Trace backward through the inverse sequential frame steps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray
|
Ray
|
Ray object to trace. |
required |
surf_range
|
range
|
Range of surface indices to trace through. |
required |
record
|
bool
|
If True, record ray positions at each surface. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ray_out |
Ray
|
Ray after backward propagation through all surfaces. |
ray_o_record |
list or None
|
Ray positions at each surface, or None if record is False. |
Source code in deeplens-src/deeplens/geolens.py
calc_foclen
Compute effective focal length (EFL) by paraxial ray tracing.
Traces the paraxial marginal ray of an object at infinity through the surfaces with the y-nu recursion, using the reduced slope \(\omega = n u\):
where the surface power \(\phi\) comes from each surface's
paraxial_power. This is the first-order convention used by Zemax and
CODE V: only vertex geometry contributes, so conic constants, aspheric
coefficients and freeform departures do not affect the result, and the
sensor position is irrelevant. Launching \(y = 1\), \(\omega = 0\) gives
\(EFL = -n'_k / \omega'_k\) and \(BFL = -y_k n'_k / \omega'_k\).
Returns:
| Name | Type | Description |
|---|---|---|
eff_foclen |
float
|
Effective focal length [mm]. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the system is afocal, so the focal length is
undefined. Failing here avoids writing an infinite |
Note
Also caches self.efl (effective focal length [mm]), self.foclen
(alias of self.efl), and self.bfl (paraxial back focal length,
the distance from the last surface to the rear focal point [mm]).
Reference
[1] W. Smith, "Modern Optical Engineering", the y-nu paraxial raytrace. [2] https://optics.ansys.com/hc/en-us/articles/42661756008083-Understanding-paraxial-ray-tracing
Source code in deeplens-src/deeplens/geolens.py
calc_numerical_aperture
Compute numerical aperture (NA).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
float
|
Refractive index. Defaults to 1.0. |
1.0
|
Returns:
| Name | Type | Description |
|---|---|---|
NA |
float
|
Numerical aperture. |
Reference
[1] https://en.wikipedia.org/wiki/Numerical_aperture
Source code in deeplens-src/deeplens/geolens.py
calc_focal_plane
Compute the focus distance in the object space. Ray starts from sensor center and traces to the object space.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
wvln
|
float
|
Wavelength in µm. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
focal_plane |
float
|
Object-space focus distance [mm] (negative z, in front of the lens). |
Source code in deeplens-src/deeplens/geolens.py
calc_sensor_plane
Calculate in-focus sensor plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
float
|
Depth of the object plane. Defaults to float("inf"). |
float('inf')
|
Returns:
| Name | Type | Description |
|---|---|---|
d_sensor |
Tensor
|
In-focus sensor z-position [mm] in image space (scalar tensor). |
Source code in deeplens-src/deeplens/geolens.py
calc_fov
Compute field of view (FoV) of the lens in radians.
Calculates FoV using two methods
- Perspective projection — from focal length and sensor size (effective FoV, ignoring distortion).
- Forward ray tracing — sweeps FOV angles from object side, traces to sensor, and finds the angle whose centroid image height matches the sensor half-diagonal. This avoids the failure of the old backward-tracing approach on wide-angle lenses where pupil aberration at full field leaves zero valid rays.
Note
Caches the following attributes (all FoV values in radians):
self.vfov (vertical FoV), self.hfov (horizontal FoV),
self.dfov (diagonal FoV), self.rfov_eff (effective paraxial
half-diagonal FoV, ignoring distortion), self.rfov (real
half-diagonal FoV from ray tracing, accounts for distortion),
self.real_dfov (real diagonal FoV from ray tracing), and
self.eqfl (35 mm equivalent focal length [mm]).
Reference
[1] https://en.wikipedia.org/wiki/Angle_of_view_(photography)
Source code in deeplens-src/deeplens/geolens.py
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 | |
calc_scale
Calculate the scale factor (object height / image height).
Uses the pinhole camera model to compute magnification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
float
|
Object distance from the lens (negative z direction). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
scale |
float
|
Scale factor relating object height to image height. |
Source code in deeplens-src/deeplens/geolens.py
calc_pupil
Compute entrance and exit pupil positions and radii.
The entrance and exit pupils must be recalculated whenever
- First-order parameters change (e.g., field of view, object height, image height),
- Lens geometry or materials change (e.g., surface curvatures, refractive indices, thicknesses),
- Or generally, any time the lens configuration is modified.
Note
Caches self.aper_idx (aperture surface index),
self.exit_pupilz/self.exit_pupilr (real exit pupil position and
radius [mm]), self.entr_pupilz/self.entr_pupilr (real entrance
pupil position and radius [mm]),
self.exit_pupilz_parax/self.exit_pupilr_parax and
self.entr_pupilz_parax/self.entr_pupilr_parax (paraxial pupils),
and self.fnum (F-number from focal length and entrance pupil).
Source code in deeplens-src/deeplens/geolens.py
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 | |
get_entrance_pupil
Get entrance pupil location and radius.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paraxial
|
bool
|
If True, return paraxial approximation values. If False, return real ray-traced values. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
pupilz |
float
|
Entrance pupil z-position [mm]. |
pupilr |
float
|
Entrance pupil radius [mm]. |
Source code in deeplens-src/deeplens/geolens.py
get_exit_pupil
Get exit pupil location and radius.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paraxial
|
bool
|
If True, return paraxial approximation values. If False, return real ray-traced values. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
pupilz |
float
|
Exit pupil z-position [mm]. |
pupilr |
float
|
Exit pupil radius [mm]. |
Source code in deeplens-src/deeplens/geolens.py
calc_pupil_paraxial
Image the aperture stop through the surfaces on one side of it.
The pupils are the first-order images of the stop, so they follow from
the same y-nu recursion as calc_foclen rather than from tracing real
rays. A ray is launched from the axial point of the stop (\(y = 0\),
\(\omega = n u = 1\)) and propagated through the surfaces after the stop
(exit pupil) or backwards through those before it (entrance pupil);
where it re-crosses the axis is the pupil plane. Stop and pupil are
conjugate, so the transverse magnification is given by the
Smith-Helmholtz relation
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reverse
|
bool
|
Trace backwards through the surfaces before the stop (entrance pupil) instead of forwards through those after it (exit pupil). Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
pupilz |
float
|
Pupil z-position [mm]. |
pupilr |
float
|
Pupil radius [mm]. |
Source code in deeplens-src/deeplens/geolens.py
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 | |
calc_exit_pupil_rayaiming
Calculate exit pupil location and radius from real rays.
Rays are emitted from the edge of the aperture stop in large quantities
and traced to the last surface; the exit pupil position and radius come
from the intersection points of those rays. Slower than
calc_pupil_paraxial and affected by aperture-related aberrations.
Returns:
| Name | Type | Description |
|---|---|---|
avg_pupilz |
float
|
z coordinate of exit pupil. |
avg_pupilr |
float
|
radius of exit pupil. |
Reference
[1] Exit pupil: how many rays can come from sensor to object space. [2] https://en.wikipedia.org/wiki/Exit_pupil
Source code in deeplens-src/deeplens/geolens.py
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | |
calc_entrance_pupil_rayaiming
Calculate entrance pupil of the lens from real rays.
The entrance pupil is the optical image of the physical aperture stop, as seen through the optical elements in front of the stop. We sample backward rays from the aperture stop edge and trace them to the first surface, then find the intersection points of the reverse extension of the rays. The average of the intersection points defines the entrance pupil position and radius. Slower than calc_pupil_paraxial and affected by aperture-related aberrations.
Returns:
| Name | Type | Description |
|---|---|---|
avg_pupilz |
float
|
Entrance pupil z-position [mm]. |
avg_pupilr |
float
|
Entrance pupil radius [mm]. |
Note
[1] Use calc_pupil_paraxial unless precise ray aiming is required.
[2] This function only works for object at a far distance. For microscopes, this function usually returns a negative entrance pupil.
Reference
[1] Entrance pupil: how many rays can come from object space to sensor. [2] https://en.wikipedia.org/wiki/Entrance_pupil: "In an optical system, the entrance pupil is the optical image of the physical aperture stop, as 'seen' through the optical elements in front of the stop." [3] Zemax LLC, OpticStudio User Manual, Version 19.4, Document No. 2311, 2019.
Source code in deeplens-src/deeplens/geolens.py
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 | |
compute_intersection_points_2d
staticmethod
Compute the intersection points of 2D lines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
origins
|
Tensor
|
Origins of the lines. Shape: [N, 2] |
required |
directions
|
Tensor
|
Directions of the lines. Shape: [N, 2] |
required |
Returns:
| Name | Type | Description |
|---|---|---|
points |
Tensor
|
Intersection points. Shape: [N*(N-1)/2, 2] |
Source code in deeplens-src/deeplens/geolens.py
surf_d
Return the derived global vertex position of surface idx [mm].
surf_d(0) is zero and surf_d(i) is the differentiable prefix sum
of d_next for surfaces before i. Passing len(surfaces) returns the
sensor position. Negative indices follow Python surface indexing.
Source code in deeplens-src/deeplens/geolens.py
refocus
Refocus the lens to a depth distance by changing sensor position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
foc_dist
|
float
|
Object focus distance [mm].
Use |
float('inf')
|
Note
In DSLR, phase detection autofocus (PDAF) is a popular and efficient method. But here we simplify the problem by calculating the in-focus position of green light.
Source code in deeplens-src/deeplens/geolens.py
set_fnum
Set F-number and aperture radius using binary search.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fnum
|
float
|
target F-number. |
required |
Source code in deeplens-src/deeplens/geolens.py
set_target_fov_fnum
Set FoV, image height, and F-number as design targets.
Only use this method to assign design targets (it overwrites the cached first-order quantities directly rather than measuring them).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rfov
|
float
|
Half-diagonal FoV. Interpreted as radians; if the value is greater than \(\pi\) it is treated as degrees and converted to radians. |
required |
fnum
|
float
|
Target F-number. |
required |
Source code in deeplens-src/deeplens/geolens.py
set_fov
Set half-diagonal field of view as a design target.
Unlike calc_fov() which derives FoV from focal length and sensor
size, this method directly assigns the target FoV for lens optimisation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rfov
|
float
|
Half-diagonal FoV in radians. |
required |
Source code in deeplens-src/deeplens/geolens.py
Components
GeoLens uses a mixin architecture — its functionality is split across the
focused classes below. You normally interact only with GeoLens itself; these
are documented for reference.
deeplens.geolens_pkg.psf_compute.GeoLensPSF
Mixin providing PSF computation for GeoLens.
Exposes three PSF models through a single psf dispatcher: incoherent
geometric ray tracing, coherent exit-pupil diffraction (ASM propagation),
and Huygens-Fresnel integration. The geometric and coherent models are
differentiable; Huygens is not. This class is not instantiated directly;
it is mixed into GeoLens.
psf
Compute the Point Spread Function (PSF) for given point sources.
Dispatches to one of three PSF models
- geometric: incoherent intensity ray tracing (fast, differentiable).
- coherent: coherent tracing to exit pupil + ASM propagation (accurate, differentiable, single point).
- huygens: Huygens-Fresnel integration (accurate, not differentiable, single point).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor
|
Normalized point source positions. Shape [N, 3] with x, y in [-1, 1] and z in [-Inf, 0]. The coherent and huygens models accept only a single point ([3] or [1, 3]). |
required |
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
ks
|
int
|
Output kernel size in pixels. Defaults to PSF_KS. |
PSF_KS
|
**kwargs
|
Model-specific options: spp (int): Rays sampled per source. If None, uses the model-specific default (SPP_PSF / SPP_COHERENT). recenter (bool): If True (default), center the PSF on the chief ray; otherwise on the pinhole projection. model (str): One of 'geometric' (default), 'coherent', 'huygens'. return_field (bool): For the coherent and Huygens models, return the energy-normalized complex sensor-plane field instead of intensity. Defaults to False. |
{}
|
Returns:
| Type | Description |
|---|---|
|
torch.Tensor: Intensity PSF normalized to sum to 1, or an
energy-normalized complex field when |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
psf_geometric
Compute the single-wavelength geometric PSF by incoherent ray binning.
Samples rays from each object point, traces them incoherently to the
sensor, and bins the hit positions into a ks × ks intensity kernel.
This model is fast and differentiable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor
|
Normalized point source positions. Shape [N, 3] with x, y in [-1, 1] and z in [-Inf, 0]. |
required |
ks
|
int
|
Output kernel size in pixels. Defaults to PSF_KS. |
PSF_KS
|
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
spp
|
int
|
Rays sampled per source. Defaults to SPP_PSF. |
SPP_PSF
|
recenter
|
bool
|
If True (default), center on the chief ray; otherwise on the pinhole projection. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
psf |
Tensor
|
PSF normalized to sum to 1. Shape [ks, ks] for a single point, or [N, ks, ks] for N points. |
Reference
[1] https://optics.ansys.com/hc/en-us/articles/42661723066515-What-is-a-Point-Spread-Function
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
psf_coherent
Compute the coherent exit-pupil PSF (alias for psf_pupil_prop).
Traces coherent rays to the exit pupil and propagates the wavefront to
the sensor with the Angular Spectrum Method (ASM). See psf_pupil_prop
for full argument and return documentation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor
|
Single normalized point source [3] or [1, 3] with x, y in [-1, 1] and z in [-Inf, 0]. |
required |
ks
|
int
|
Output kernel size in pixels. Defaults to PSF_KS. |
PSF_KS
|
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
spp
|
int
|
Rays sampled. Defaults to SPP_COHERENT. |
SPP_COHERENT
|
recenter
|
bool
|
If True (default), center on the chief ray. |
True
|
return_field
|
bool
|
Return the energy-normalized complex sensor-plane field instead of intensity. Defaults to False. |
False
|
Returns:
| Type | Description |
|---|---|
|
torch.Tensor: Intensity PSF normalized to sum to 1, or an
energy-normalized complex field when |
Note
The complex field has an arbitrary global phase because optical path length is measured relative to a reference; relative phase is meaningful.
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
psf_pupil_prop
Compute the single-point monochromatic PSF via the exit-pupil diffraction model.
Steps
- Compute the complex wavefront at the exit-pupil plane by coherent ray tracing.
- Propagate to the sensor plane with the Angular Spectrum Method (ASM) and return either its field or intensity. This function is differentiable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor or list
|
Single normalized point source [3] or [1, 3] with x, y in [-1, 1] and z in [-Inf, 0]. |
required |
ks
|
int
|
Size of the output PSF patch in pixels. If None, the full propagated intensity field is returned uncropped. Defaults to PSF_KS. |
PSF_KS
|
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
spp
|
int
|
Number of rays to sample. Defaults to SPP_COHERENT. |
SPP_COHERENT
|
recenter
|
bool
|
If True (default), center on the chief ray; otherwise on the pinhole projection. |
True
|
return_field
|
bool
|
Return the energy-normalized complex sensor-plane field instead of intensity. Defaults to False. |
False
|
Returns:
| Type | Description |
|---|---|
|
torch.Tensor: Intensity PSF normalized to sum to 1, or an
energy-normalized complex field when |
Reference
[1] "End-to-End Hybrid Refractive-Diffractive Lens Design with Differentiable Ray-Wave Model", SIGGRAPH Asia 2024.
Note
Similar to the ZEMAX FFT PSF, but free-space propagation uses the Angular Spectrum Method (ASM) instead of a single FFT. ASM is more accurate because the FFT approach assumes a far-field condition (e.g., chief ray perpendicular to the image plane). The complex field has an arbitrary global phase because optical path length is measured relative to a reference; relative phase is meaningful.
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | |
pupil_field
Compute the complex wavefront at the exit-pupil plane by coherent ray tracing.
The wavefront is xy-flipped for subsequent PSF calculation and binned at
the sensor pixel size onto a square [H, H] grid (H = sensor height in
pixels). This function is differentiable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor or list
|
Single normalized point source [3] or [1, 3] with x, y in [-1, 1] and z in [-Inf, 0]. |
required |
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
spp
|
int
|
Number of rays to sample. Must be at least 1,000,000 for accurate coherent simulation. Defaults to SPP_COHERENT. |
SPP_COHERENT
|
recenter
|
bool
|
If True (default), center on the chief ray; otherwise on the pinhole projection. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
wavefront |
Tensor
|
Complex wavefront at the exit pupil, binned at pixel size. Shape [H, H]. |
psf_center |
list
|
Normalized PSF center [x, y] on the sensor in [-1, 1]. |
Note
Default dtype must be torch.float64 for accurate phase calculation.
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | |
psf_huygens
Compute the single-wavelength Huygens PSF by spherical-wave integration.
Not differentiable, due to the heavy computational cost.
Steps
- Trace coherent rays to the exit-pupil plane.
- Treat every ray as a secondary point source emitting a spherical wave, and coherently sum these waves over the PSF pixel grid. Each contribution uses the Huygens-Fresnel obliquity factor \(0.5 (1 + \cos\theta)\) and \(1/r\) spherical-wave amplitude decay.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor
|
Single normalized point source [3] or [1, 3] with x, y in [-1, 1] and z in [-Inf, 0]. |
required |
ks
|
int
|
Output kernel size in pixels. Defaults to PSF_KS. |
PSF_KS
|
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
spp
|
int
|
Rays sampled. Defaults to SPP_COHERENT. |
SPP_COHERENT
|
recenter
|
bool
|
If True (default), center on the chief ray; otherwise on the pinhole projection. |
True
|
return_field
|
bool
|
Return the energy-normalized complex sensor-plane field instead of intensity. Defaults to False. |
False
|
Returns:
| Type | Description |
|---|---|
|
torch.Tensor: Intensity PSF normalized to sum to 1, or an
energy-normalized complex field when |
Reference
[1] "Optical Aberrations Correction in Postprocessing Using Imaging Simulation", TOG 2021.
Note
Different from the ZEMAX Huygens PSF, which traces rays to the image plane and performs plane-wave integration. The complex field has an arbitrary global phase because optical path length is measured relative to a reference; relative phase is meaningful.
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | |
psf_map
Compute the geometric PSF map across the field of view at a given depth.
Overrides the base Lens method to improve efficiency by tracing all
field points in parallel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
float
|
Object plane depth [mm]. When None (default),
falls back to |
None
|
grid
|
int or tuple
|
Grid size (grid_w, grid_h); an int is broadcast to a square grid. Defaults to (7, 7). |
(7, 7)
|
ks
|
int
|
Output kernel size in pixels. Defaults to PSF_KS. |
PSF_KS
|
spp
|
int
|
Rays sampled per source. Defaults to SPP_PSF. |
SPP_PSF
|
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
recenter
|
bool
|
If True (default), center on the chief ray. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
psf_map |
Tensor
|
PSF map. Shape [grid_h, grid_w, 1, ks, ks]. |
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
psf_center
Compute the reference PSF center on the sensor for a given point source.
With method "chief_ray" it returns the negated sensor intercept of the sampled real ray closest to the physical aperture-stop centre. Invalid chief rays fall back to the pinhole model independently per field, as does the whole computation when the lens has no aperture stop. With "pinhole" it uses an ideal perspective projection (no distortion).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points_obj
|
Tensor
|
Un-normalized object-plane point(s), shape [..., 3][mm], spanning [-Inf, Inf] x [-Inf, Inf] x [-Inf, 0]. |
required |
method
|
str
|
"chief_ray" or "pinhole". Defaults to "chief_ray". |
'chief_ray'
|
ray
|
Ray
|
Bundle already traced to the sensor from
|
None
|
Returns:
| Name | Type | Description |
|---|---|---|
psf_center |
Tensor
|
Un-normalized PSF center on the sensor plane [mm], shape [..., 2]. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in deeplens-src/deeplens/geolens_pkg/psf_compute.py
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | |
For coherent and Huygens models, pass return_field=True to psf() to get
the energy-normalized complex sensor-plane field instead of intensity. Its
global phase is arbitrary; relative phase is meaningful.
deeplens.geolens_pkg.eval.GeoLensEval
Mixin that adds classical optical evaluation methods to GeoLens.
This class is never instantiated on its own. It is mixed into
GeoLens via multiple inheritance, so every method can access lens
geometry (self.d_sensor, self.rfov, …) and ray-tracing routines
(self.trace(), self.trace2sensor(), …) directly through self.
All evaluation functions follow the same pattern
- Sample rays from object space (parallel / grid / radial).
- Trace rays through the lens (
self.traceorself.trace2sensor). - Analyze ray positions / directions at the sensor plane.
- Optionally produce a matplotlib figure saved to disk.
Results are accuracy-aligned with Zemax OpticStudio for the same lens prescriptions and ray-sampling densities.
Attributes consumed from GeoLens (via self):
d_sensor (float): Axial position of the sensor plane (mm).
sensor_size (tuple[float, float]): Sensor (width, height) in mm.
pixel_size (float): Pixel pitch in mm.
sensor_res (tuple[int, int]): Sensor resolution (W, H) in pixels.
rfov (float): Half field-of-view in radians.
foclen (float): Equivalent focal length in mm.
fnum (float): F-number.
aper_idx (int): Index of the aperture stop surface.
device (torch.device): Compute device (CPU / CUDA).
calc_chief_ray
calc_chief_ray(
points_obj=None,
*,
ray=None,
fov=None,
plane="meridional",
num_rays=SPP_CALC,
wvln=None,
scale_pupil=1.0,
record=False,
)
Calculate one real, physical-stop-centred chief ray per field.
DeepLens uses the classical physical definition: the chief ray is the
real ray through the centre of the aperture stop. Because the tracer
samples a finite bundle, this method returns the sampled ray closest to
the stop centre rather than a synthetic bundle centroid. The selection
residual scales as ~1/sqrt(num_rays) of the stop radius; raise
num_rays when tighter stop centring is needed (e.g. relative
distortion at small field angles, where the residual is amplified by
the small ideal image height).
Exactly one input mode must be supplied:
points_objsamples and traces rays from object-space points to the sensor before extracting the chief ray (finite conjugates).fovtraces a collimated bundle at the given field angles (infinite conjugates) in theplanedirection.rayextracts from an already traced bundle that crossed the aperture stop, avoiding duplicate tracing.
Selection happens before final validity is checked. If the closest
stop-centred ray is clipped after the stop, it remains the selected ray
and is returned as invalid rather than being replaced by a farther ray.
The result's stop_dist is its distance from the stop centre in
stop radii. If no sample has a finite recorded distance, including an
untraced bundle, the result is invalid with stop_dist=inf. Multiply
a recorded distance by the stop radius used for tracing to obtain
the distance in millimetres.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points_obj
|
Tensor | list | None
|
Physical object points in
millimetres, shape |
None
|
ray
|
Ray | None
|
Already traced ray bundle that crossed the
aperture stop, shape |
None
|
fov
|
float | list | Tensor | None
|
Field angle(s) in
degrees for infinite-conjugate chief rays, shape |
None
|
plane
|
str
|
|
'meridional'
|
num_rays
|
int
|
Samples per field in |
SPP_CALC
|
wvln
|
float | None
|
Wavelength in micrometres for the sampling modes. Defaults to the lens primary wavelength. |
None
|
scale_pupil
|
float
|
Entrance-pupil sampling-radius multiplier in the sampling modes. Defaults to 1.0. |
1.0
|
record
|
bool
|
Return |
False
|
Returns:
| Type | Description |
|---|---|
|
Ray | tuple[Ray, list[torch.Tensor]]: One selected chief ray per |
|
|
field, with shape |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the input modes are invalid, sampling parameters are invalid, the supplied bundle is empty, or path recording is requested for a supplied bundle. |
TypeError
|
If |
Note
This method is discrete and decorated with torch.no_grad(). It
is intended for evaluation and PSF centring, not gradient losses.
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | |
spot_points
Trace rays from object points to sensor and return the traced Ray.
Samples rays from each physical object point toward the entrance pupil, traces through all lens surfaces (refraction + clipping), and returns the resulting Ray object on the sensor plane.
This is the shared computational core for spot diagrams
(draw_spot_radial, draw_spot_map) and RMS error maps
(rms_map, rms_map_rgb).
Algorithm
self.sample_from_points(points, num_rays, wvln)generates a fan ofnum_raysrays per object point, aimed at the entrance pupil.self.trace2sensor()propagates through all surfaces and clips vignetted rays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor
|
Physical 3D object-space coordinates with
shape |
required |
num_rays
|
int
|
Number of rays sampled per object point.
Defaults to |
SPP_PSF
|
wvln
|
float
|
Wavelength in µm. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Traced ray on the sensor plane, with shape
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
draw_spot_radial
draw_spot_radial(
save_name="./lens_spot_radial.png",
num_fov=5,
depth=None,
num_rays=SPP_PSF,
wvln_list=None,
direction="y",
show=False,
)
Draw spot diagrams at evenly-spaced field angles along a chosen direction.
A spot diagram visualizes the transverse ray-intercept distribution on the sensor plane for a point source at a given field angle and depth. It reveals the combined effect of all aberrations (spherical, coma, astigmatism, field curvature, chromatic, …).
Field positions are sampled by field angle uniformly from on-axis
(0) to full-field (self.rfov), so the FoV 1.0 subplot reaches
the full image height — consistent with analysis_spot().
Algorithm
For each wavelength in wvln_list:
1. self.sample_radial_rays(direction) samples rays at
num_fov field angles in [0, self.rfov] along the
chosen direction.
2. self.trace2sensor() traces them to the sensor.
3. Valid ray (x, y) positions are scatter-plotted per subplot.
All wavelengths are overlaid in a single figure with RGB coloring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_name
|
str
|
File path for the output PNG.
Defaults to |
'./lens_spot_radial.png'
|
num_fov
|
int
|
Number of field positions sampled uniformly from on-axis (0) to full-field. Defaults to 5. |
5
|
depth
|
float
|
Object distance in mm (negative = real object).
When |
None
|
num_rays
|
int
|
Rays per field position per wavelength.
Defaults to |
SPP_PSF
|
wvln_list
|
list[float]
|
Wavelengths in µm. When |
None
|
direction
|
str
|
Sampling direction —
|
'y'
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | |
draw_spot_map
draw_spot_map(
save_name="./lens_spot_map.png",
num_grid=5,
depth=None,
num_rays=SPP_PSF,
wvln_list=None,
show=False,
)
Draw a 2-D grid of spot diagrams across the full field of view.
Unlike draw_spot_radial (which samples only a radial slice),
this method samples a num_grid × num_grid grid of field positions
covering both the x (sagittal) and y (meridional) axes, revealing
off-axis aberrations that are invisible in a 1-D radial scan.
Grid field positions are sampled by field angle, spanning the full
field on both axes so the corner cells reach the full image height —
consistent with draw_spot_radial / analysis_spot.
Algorithm
For each wavelength in wvln_list:
1. self.sample_grid_rays() samples a grid_h × grid_w
field-angle grid spanning horizontal [-hfov/2, hfov/2]
and vertical [-vfov/2, vfov/2] angles.
2. self.trace2sensor() traces them to the sensor.
3. Valid (x, y) positions are scatter-plotted in the
corresponding subplot of the num_grid × num_grid figure.
All wavelengths are overlaid with RGB coloring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_name
|
str
|
File path for the output PNG.
Defaults to |
'./lens_spot_map.png'
|
num_grid
|
int | tuple[int, int]
|
Number of grid points along each
axis. Total subplots = |
5
|
depth
|
float
|
Object distance in mm. When |
None
|
num_rays
|
int
|
Rays per grid cell per wavelength.
Defaults to |
SPP_PSF
|
wvln_list
|
list[float]
|
Wavelengths in µm. When |
None
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | |
rms_map
Compute per-field-position RMS spot radius for a single wavelength.
Traces SPP_PSF rays per grid cell and computes the root-mean-square
distance of valid ray hits from a reference centroid. When center
is None, each cell uses its own centroid (monochromatic blur).
When an external center is provided (e.g. the green-channel
centroid), the RMS includes the chromatic shift from that reference.
Algorithm
self.point_source_grid(normalized=False)generates physical object points on a[num_grid, num_grid]field grid.self.spot_points()samplesSPP_PSFrays per point and traces to sensor.- If
centerisNone, compute per-cell centroidc = mean(valid ray_xy); otherwise use the providedcenter. RMS = sqrt( mean( ||ray_xy - c||^2 ) ).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_grid
|
int | tuple[int, int]
|
Spatial resolution of the field sampling grid. Defaults to 32. |
32
|
depth
|
float
|
Object distance in mm. When |
None
|
wvln
|
float
|
Wavelength in µm. When |
None
|
center
|
Tensor | None
|
External reference centroid with shape
|
None
|
Returns:
| Name | Type | Description |
|---|---|---|
rms |
Tensor
|
RMS spot error map, shape |
centroid |
Tensor
|
Per-cell centroid used as reference, shape
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
rms_map_rgb
Compute per-field-position RMS spot radius for R, G, B wavelengths.
The RMS spot radius is a standard measure of geometrical image quality.
For each field position in a num_grid × num_grid grid, this method
traces SPP_PSF rays per wavelength and computes the root-mean-square
distance of valid ray hits from a common reference centroid.
The reference centroid is the green-channel centroid. Using a common reference means the returned RMS values include lateral chromatic aberration (the shift between R/G/B centroids), making the map useful as a polychromatic image-quality metric.
Algorithm
- Call
rms_map(wvln=green)to get the green RMS map and the green centroid. - Call
rms_map(wvln=red, center=green_centroid)andrms_map(wvln=blue, center=green_centroid)to measure R/B blur relative to the green reference. - Stack as
[R, G, B].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_grid
|
int or tuple[int, int]
|
Spatial resolution of the field sampling grid. Defaults to 32. |
32
|
depth
|
float
|
Object distance in mm. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
rms_rgb |
Tensor
|
RMS spot error map with shape
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
calc_distortion_radial
Compute fractional distortion at evenly-spaced field angles along the meridional direction.
Distortion is defined as (h_actual - h_ideal) / h_ideal, where
h_ideal = f * tan(theta) (rectilinear projection) and h_actual
is the chief-ray image height on the sensor. A positive value means
pincushion distortion; negative means barrel distortion.
This is the computational counterpart to draw_spot_radial: it
samples num_points field angles uniformly from 0 to self.rfov
and returns both the sampled angles and the corresponding distortion
values, making it easy to pair with other radial evaluation functions.
Algorithm
- Derive
rfov_degfromself.rfov(radians → degrees). - Sample
num_pointsfield angles uniformly in[0, rfov_deg]. The on-axis sample (0°) is replaced by a tiny positive angle to avoid 0/0. - Compute
h_ideal = foclen * tan(angle)for each sample. - Compute the physical-stop chief ray at the sensor via
calc_chief_ray(fov=...). - Extract
h_actualfrom the appropriate transverse coordinate (x for sagittal, y for meridional). - Return
(h_actual - h_ideal) / h_ideal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_points
|
int
|
Number of evenly-spaced field-angle samples from
on-axis (0°) to full-field ( |
GEO_GRID
|
wvln
|
float
|
Wavelength in µm. When |
None
|
plane
|
str
|
|
'meridional'
|
num_rays
|
int
|
Pupil samples per field angle for chief-ray
selection. The chief-ray residual (and hence the distortion
noise floor, amplified at small field angles by the small
ideal image height) scales as |
SPP_CALC
|
Returns:
| Name | Type | Description |
|---|---|---|
rfov_samples |
ndarray
|
Field angles in degrees, shape
|
distortions |
ndarray
|
Fractional distortion at each angle, shape
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | |
draw_distortion_radial
draw_distortion_radial(
save_name=None, num_points=GEO_GRID, wvln=None, plane="meridional", show=False
)
Draw distortion-vs-field-angle curve in Zemax style.
Produces a plot with field angle on the y-axis and percent distortion on the x-axis, matching the layout convention used in Zemax OpticStudio. Useful for quick visual assessment of barrel / pincushion distortion.
Algorithm
- Call
calc_distortion_radialto obtain field angles and fractional distortion values. - Convert distortion to percent and plot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_name
|
str | None
|
File path for the output PNG. If |
None
|
num_points
|
int
|
Number of field-angle samples.
Defaults to |
GEO_GRID
|
wvln
|
float
|
Wavelength in µm. When |
None
|
plane
|
str
|
|
'meridional'
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | |
calc_distortion_map
Compute a 2-D distortion grid mapping ideal to actual image positions.
For each cell in a num_grid × num_grid field grid, rays are traced
to the sensor and the physical-stop chief-ray position is extracted
(fields without a valid chief ray fall back to the bundle centroid).
The position is then normalized to [-1, 1] sensor coordinates,
producing a map that shows how each ideal image point is displaced by
lens distortion.
This map can be used with torch.nn.functional.grid_sample to warp
or unwarp rendered images.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_grid
|
int
|
Grid resolution along each axis. Defaults to 16. |
16
|
depth
|
float
|
Object distance in mm. When |
None
|
wvln
|
float
|
Wavelength in µm. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
distortion_grid |
Tensor
|
Distortion grid with shape
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
calc_inv_distortion_map
Compute a grid for applying lens distortion with grid_sample.
For each point on the distorted sensor grid, backward rays are traced
through the lens to the target object-depth plane. The traced object
intersections are converted to normalized ideal image coordinates.
Passing this grid to torch.nn.functional.grid_sample samples an
undistorted image and produces a distorted image.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_grid
|
int or tuple
|
Grid resolution. If a tuple is supplied,
it is interpreted as |
16
|
depth
|
float
|
Object distance in mm. When |
None
|
wvln
|
float
|
Wavelength in µm. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
inv_distortion_grid |
Tensor
|
Inverse distortion grid with
shape |
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
distortion_center
Compute the distorted image position for arbitrary normalized object points.
Given object points in normalized coordinates, this method converts them
to physical object-space positions, traces rays from each point through
the lens, and returns the physical-stop chief-ray position on the sensor
(bundle-centroid fallback for fields without a valid chief ray) in
normalized [-1, 1] coordinates. This is the inverse mapping needed
for distortion correction (unwarping).
Algorithm
- Convert normalized
(x, y)∈ [-1, 1] to physical object-space positions usingself.calc_scale(depth)andself.sensor_size. self.sample_from_points()generates rays from each point.self.trace2sensor()propagates rays.- Extract the chief-ray position and normalize back to
[-1, 1].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Tensor
|
Normalized point source positions with shape
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
distortion_center |
Tensor
|
Normalized distortion centroid
positions with shape |
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
draw_distortion_map
Draw a scatter plot of the distortion grid.
Visualizes the output of calc_distortion_map() as a scatter plot on
[-1, 1] normalized sensor coordinates. An undistorted lens would
show a perfect rectilinear grid; deviations reveal barrel or pincushion
distortion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_name
|
str | None
|
File path for the output PNG. If |
None
|
num_grid
|
int
|
Grid resolution per axis. Defaults to 16. |
16
|
depth
|
float
|
Object distance in mm. When |
None
|
wvln
|
float
|
Wavelength in µm. When |
None
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | |
mtf
Compute the geometric MTF at a single field position.
The Modulation Transfer Function describes how well the lens preserves contrast as a function of spatial frequency. MTF = 1 at low frequencies (perfect contrast) and falls toward 0 near the diffraction limit or the Nyquist frequency of the sensor.
This implementation uses the geometric (ray-based) approach:
1. Compute the PSF at the given field position via self.psf().
2. Convert PSF → MTF via psf2mtf() (project onto tangential and
sagittal axes, then take the magnitude of the 1-D FFT).
Tangential MTF captures resolution in the meridional (radial) direction; sagittal MTF captures resolution perpendicular to it. The difference between the two indicates astigmatism.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fov
|
float
|
Field angle in radians. Internally mapped to a
normalized point |
required |
wvln
|
float
|
Wavelength in µm. When |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
freq |
ndarray
|
Spatial frequency axis in cycles/mm (positive frequencies only, excluding DC). |
mtf_tan |
ndarray
|
Tangential (meridional) MTF values, normalized so that MTF → 1 at low frequency. |
mtf_sag |
ndarray
|
Sagittal MTF values, same normalization. |
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
psf2mtf
staticmethod
Convert a 2-D point-spread function to tangential and sagittal MTF curves.
The MTF is the magnitude of the optical transfer function (OTF), which
is the Fourier transform of the PSF. For separable 1-D analysis:
1. Integrate the PSF along the x-axis → tangential line-spread
function (LSF_tan).
2. Integrate the PSF along the y-axis → sagittal LSF_sag.
3. Take |FFT(LSF)| and normalize by the DC component so that
MTF(0) = 1.
Only positive frequencies (excluding DC) are returned, following the convention used in Zemax MTF plots.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
psf
|
Tensor | ndarray
|
2-D PSF with shape |
required |
pixel_size
|
float
|
Pixel pitch in mm. Determines the frequency
axis scaling: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
freq |
ndarray
|
Spatial frequency in cycles/mm (positive,
excluding DC). Length is roughly |
mtf_tan |
ndarray
|
Tangential MTF, normalized to 1 at DC. |
mtf_sag |
ndarray
|
Sagittal MTF, normalized to 1 at DC. |
References
- https://en.wikipedia.org/wiki/Optical_transfer_function
- Edmund Optics: Introduction to Modulation Transfer Function.
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | |
draw_mtf
draw_mtf(
save_name="./lens_mtf.png",
relative_fov_list=[0.0, 0.7, 1.0],
depth_list=None,
psf_ks=128,
show=False,
)
Draw a grid of MTF curves for multiple depths and field positions.
Produces a len(depth_list) × len(relative_fov_list) subplot grid.
Each subplot shows the tangential (T, solid) and sagittal (S, dashed)
MTF for R, G, B wavelengths plus a vertical line at the sensor Nyquist
frequency (0.5 / pixel_size cycles/mm).
Algorithm per subplot
- Compute the RGB PSF via
self.psf_rgb()at the specified(depth, relative_fov)with kernel sizepsf_ks. - For each wavelength channel, call
psf2mtf()to obtain the tangential and sagittal MTF curves. - Plot frequency vs MTF with RGB coloring (T solid, S dashed).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_name
|
str
|
File path for the output PNG.
Defaults to |
'./lens_mtf.png'
|
relative_fov_list
|
list[float]
|
Relative field positions in
|
[0.0, 0.7, 1.0]
|
depth_list
|
list[float]
|
Object distances in mm.
|
None
|
psf_ks
|
int
|
PSF kernel size in pixels (controls frequency resolution of the resulting MTF). Defaults to 128. |
128
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 | |
vignetting
Compute the relative-illumination (vignetting) map across the field.
Vignetting measures how much light is lost at each field position due to rays being clipped by lens apertures or barrel edges. It is computed as the fraction of traced rays that remain valid (not vignetted) at each grid cell, normalized by the total number of launched rays.
A value of 1.0 means all rays reach the sensor (no vignetting); 0.0 means complete light blockage. Real lenses typically show 1.0 on-axis and fall off toward the field edges due to mechanical vignetting and the cos⁴ illumination law.
Algorithm
self.sample_grid_rays()withuniform_fov=False(uniform image-space sampling) to ensure correct sensor-plane mapping.self.trace2sensor()propagates rays and marks clipped ones as invalid.- Per-cell throughput =
count(valid) / num_rays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
float
|
Object distance in mm. When |
None
|
num_grid
|
int
|
Grid resolution per axis. Defaults to 32. |
32
|
num_rays
|
int
|
Rays launched per grid cell. Higher values reduce Monte-Carlo noise. Defaults to 512. |
512
|
Returns:
| Name | Type | Description |
|---|---|---|
vignetting |
Tensor
|
Vignetting map with shape
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
draw_vignetting
Draw the vignetting map as a grayscale image with a colorbar.
Computes the vignetting map via self.vignetting(), bilinearly
upsamples it to resolution × resolution, and displays it as a
grayscale image where white = no vignetting and black = fully vignetted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str | None
|
File path for the output PNG. If |
None
|
depth
|
float
|
Object distance in mm. When |
None
|
resolution
|
int
|
Output image size in pixels (square). Defaults to 512. |
512
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
analysis_rendering
analysis_rendering(
img_org,
save_name=None,
depth=None,
spp=SPP_RENDER,
unwarp=False,
method="ray_tracing",
show=False,
)
Render a test image through the lens and report PSNR / SSIM.
Simulates what the sensor would capture if the given image were placed
at the specified object distance. The rendering accounts for all
geometric aberrations (blur, distortion, vignetting, chromatic effects).
Optionally applies an inverse distortion warp (unwarp) and reports
quality metrics for both the raw and unwarped renderings.
Algorithm
- Convert
img_orgto a[1, 3, H, W]float tensor and temporarily set the sensor resolution to match. - Call
self.render()with the chosen method (ray tracing or PSF-map / PSF-patch convolution). - Compute PSNR and SSIM between the original and rendered images.
- If
unwarp=True, applyself.unwarp()to correct geometric distortion and report metrics again. - Restore the original sensor resolution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img_org
|
ndarray | Tensor
|
Source image with shape
|
required |
save_name
|
str | None
|
Path prefix for saved PNGs. If not
|
None
|
depth
|
float
|
Object distance in mm. When |
None
|
spp
|
int
|
Samples (rays) per pixel for rendering.
Defaults to |
SPP_RENDER
|
unwarp
|
bool
|
If |
False
|
method
|
str
|
Rendering backend — |
'ray_tracing'
|
show
|
bool
|
If |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
img_render |
Tensor
|
Rendered (and optionally unwarped) image
with shape |
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 | |
analysis_spot
Compute RMS and geometric spot radii at multiple field positions for RGB.
Traces rays at num_field evenly-spaced field positions along the
meridional direction for three wavelengths (R, G, B), and computes
polychromatic RMS and geometric spot radii referenced to the
combined centroid across all wavelengths (matching Zemax's
default "RMS Spot Radius w.r.t. Centroid").
This provides a quick polychromatic spot-size summary used for design
comparisons and printed to stdout during analysis().
Algorithm (per field point):
1. Trace R, G, B rays through the lens to the sensor.
2. Pool all valid ray intercepts (across all three wavelengths)
and compute one combined centroid c.
3. RMS = sqrt(mean(||xy - c||²)) over all pooled rays — a single
polychromatic RMS that includes lateral chromatic aberration.
4. radius = max(||xy - c||) over all pooled rays.
5. Convert from mm to μm (× 1000).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_field
|
int
|
Number of field positions sampled from on-axis to full-field. Defaults to 3. |
3
|
depth
|
float
|
Object distance in mm. Use |
float('inf')
|
Returns:
| Name | Type | Description |
|---|---|---|
rms_results |
dict[str, dict[str, float]]
|
Spot analysis results
keyed by field position string (e.g., |
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 | |
analysis
analysis(
save_name="./lens",
depth=float("inf"),
full_eval=False,
render=False,
render_unwarp=False,
lens_title=None,
show=False,
)
Run a comprehensive optical analysis pipeline for the lens.
This is the main entry point for evaluating a lens design. It chains
multiple evaluation steps in order, saving all plots with a common
save_name prefix.
Execution flow
- Always: draw the lens layout (
draw_layout) and compute polychromatic spot RMS/radius (analysis_spot). - If
full_eval=True: additionally generate: - Spot diagram (
draw_spot_radial). - MTF grid (
draw_mtf). - Distortion curve (
draw_distortion_radial). - Vignetting map (
draw_vignetting). - If
render=True: render a test chart image through the lens and report PSNR/SSIM (analysis_rendering).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_name
|
str
|
Path prefix for all output files. Each plot
appends a suffix (e.g., |
'./lens'
|
depth
|
float
|
Object distance in mm. |
float('inf')
|
full_eval
|
bool
|
If |
False
|
render
|
bool
|
If |
False
|
render_unwarp
|
bool
|
If |
False
|
lens_title
|
str | None
|
Title string for the layout plot.
Defaults to |
None
|
show
|
bool
|
If |
False
|
Source code in deeplens-src/deeplens/geolens_pkg/eval.py
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 | |
deeplens.geolens_pkg.optim.GeoLensOptim
Mixin providing differentiable optimisation for GeoLens.
Implements gradient-based lens design using PyTorch autograd:
- Loss functions – RMS spot error, focus, surface regularity, gap constraints, material validity.
- Constraint initialisation – edge-thickness and self-intersection guards.
- Optimizer helpers – parameter groups with per-type learning rates and cosine annealing schedules.
- High-level
optimize()– curriculum-learning training loop.
This class is not instantiated directly; it is mixed into
GeoLens.
References
Xinge Yang et al., "Curriculum learning for ab initio deep learned refractive optics," Nature Communications 2024.
init_constraints
Initialize geometry, ray-angle, and distortion constraints for the lens.
Selects a cellphone or camera constraint preset based on whether the sensor radius is below 12 mm, sets the air-gap, thickness, BFL, TTL, surface-shape, CRA, bend-angle, and distortion limits, and propagates the bend-angle limit onto every surface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
constraint_params
|
dict
|
Constraint parameters. Currently unused (reserved for future overrides). Defaults to None. |
None
|
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
loss_reg
Compute combined regularization loss for lens design.
Aggregates multiple constraint losses to keep the lens physically valid during gradient-based optimisation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
w_focus
|
float
|
Weight for focus loss. Defaults to 1.0. |
1.0
|
w_cra
|
float
|
Weight for chief ray angle loss. Defaults to 1.0. |
1.0
|
w_ray_bend
|
float
|
Weight for per-surface bend penalty. Defaults to 1.0. |
1.0
|
w_clearance
|
float
|
Weight for the clearance penalty (min air gap, min thickness, min BFL, min TTL). Defaults to 1.0. |
1.0
|
w_envelope
|
float
|
Weight for the envelope penalty (max air gap, max thickness, max BFL, max TTL). Defaults to 1.0. |
1.0
|
w_profile
|
float
|
Weight for per-surface profile feasibility (sag, slope). Defaults to 1.0. |
1.0
|
Returns:
| Name | Type | Description |
|---|---|---|
loss_reg |
Tensor
|
Scalar combined regularization loss. |
loss_dict |
dict
|
Per-component loss values for logging. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
loss_infocus
Sample on-axis parallel rays and penalize the sensor-plane spot RMS.
Traces a zero-field ray bundle to the sensor and applies a one-sided penalty \(\mathrm{relu}(\text{rms} - \text{target})\) that activates only when the RMS spot radius exceeds the target.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
float
|
Target on-axis RMS spot radius in mm. Defaults to 0.005. |
0.005
|
wvln
|
float
|
Wavelength in µm. When None (default),
falls back to the green channel of |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
loss |
Tensor
|
Scalar focus penalty (at least 0). |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
loss_profile
Penalize infeasible per-surface profile shapes.
The "profile" is the z(r) curve of a single surface. This loss makes
sure each surface is physically manufacturable by checking:
1. Sag-to-diameter ratio exceeding sag2diam_max.
2. Maximum surface slope angle exceeding surf_angle_max (deg).
Returns:
| Name | Type | Description |
|---|---|---|
loss |
Tensor
|
Scalar profile feasibility penalty. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
loss_bound
Penalize geometry-bound violations in a single surface-sampling pass.
Each surface pair is sampled once and its distances feed both the clearance (min) and envelope (max) relu penalties for air gaps, glass thickness, BFL, and TTL.
Returns:
| Name | Type | Description |
|---|---|---|
loss_clearance |
Tensor
|
Scalar clearance penalty for parts that are too close / too thin. |
loss_envelope |
Tensor
|
Scalar envelope penalty for the overall assembly growing beyond its spatial budget. Returned separately so callers can weight the two independently. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | |
loss_cra
Penalize chief ray angle at sensor exceeding chief_ray_angle_max.
Uses a near-paraxial pupil sample (scale_pupil=0.2) over the full FoV.
The penalty is \(\mathrm{relu}(\cos\theta_\text{ref} - \cos\theta_\text{CRA})\),
valid-ray averaged, where $\cos\theta = $ ray.d[..., 2].
Returns:
| Name | Type | Description |
|---|---|---|
loss |
Tensor
|
Scalar CRA penalty (at least 0). |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
loss_ray_bend
Penalize accumulated per-surface bend angles exceeding bend_angle_max.
Reads ray.bend_penalty, an additive sum of per-surface relu
contributions collected during trace2sensor. Each surface
contributes independently, so large bends at one surface are not hidden
by small bends at another. Uses a full-pupil sample (scale_pupil=1.0).
Returns:
| Name | Type | Description |
|---|---|---|
loss |
Tensor
|
Scalar bend penalty (at least 0). |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
loss_mat
Penalize material parameters outside manufacturable ranges.
Constrains refractive index n to [1.5, 1.9] and Abbe number V to [30, 70] for each non-air surface material.
Returns:
| Name | Type | Description |
|---|---|---|
loss_mat |
Tensor
|
Scalar material penalty loss. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
loss_rms
Compute the RGB spot-size RMS loss over a grid of field points.
Traces R, G, B ray bundles (green first) to the sensor and measures the spot radius against the green pinhole center. The green spot error sets a detached per-field weight mask that emphasises harder fields.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_grid
|
int
|
Number of field-grid points per axis. Defaults to GEO_GRID. |
GEO_GRID
|
depth
|
float
|
Object-plane depth in mm. When None
(default), falls back to |
None
|
num_rays
|
int
|
Number of rays per field point. Defaults to SPP_PSF. |
SPP_PSF
|
sample_more_off_axis
|
bool
|
If True, concentrate field samples toward the field edge. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
avg_rms_error |
Tensor
|
Scalar RMS spot error in mm, averaged over the R, G, B wavelengths. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
sample_ring_arm_rays
sample_ring_arm_rays(
num_ring=8,
num_arm=2,
spp=2048,
depth=None,
wvln=None,
scale_pupil=1.0,
sample_more_off_axis=True,
)
Sample rays from object space using a ring-arm pattern.
This method distributes sampling points (origins of ray bundles) on a polar grid in the object plane,
defined by field of view. This is useful for capturing lens performance across the full field.
The points include the center and num_ring rings with num_arm points on each.
Uses self.rfov (ray-traced real FoV, accounts for distortion) rather than
self.rfov_eff (paraxial pinhole FoV) so the full distorted field is covered.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
num_ring
|
int
|
Number of rings to sample in the field of view. Defaults to 8. |
8
|
num_arm
|
int
|
Number of arms (spokes) sampled per ring. Defaults to 2. |
2
|
spp
|
int
|
Number of rays sampled per field point. Defaults to 2048. |
2048
|
depth
|
float
|
Depth of the object plane in mm. When None
(default), falls back to |
None
|
wvln
|
float
|
Wavelength in µm. When None (default), falls
back to |
None
|
scale_pupil
|
float
|
Scale factor for the entrance pupil radius. Defaults to 1.0. |
1.0
|
sample_more_off_axis
|
bool
|
If True, warp ring field angles by a square-root profile to concentrate samples toward the field edge. Defaults to True. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
rays |
Ray
|
Ray bundle with field points laid out as
[num_ring, num_arm] and |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
optimize
optimize(
lrs=[0.001, 0.0001, 0.1, 0.0001],
iterations=5000,
test_per_iter=100,
optim_mat=False,
shape_control=True,
sample_more_off_axis=False,
result_dir=None,
)
Optimise the lens by minimising RGB RMS spot errors.
Runs a curriculum-learning training loop with Adam optimiser and cosine annealing. Periodically evaluates the lens, saves intermediate results, and optionally corrects surface shapes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lrs
|
list
|
Learning rates for [d_next, c, k, a] parameter groups. Defaults to [1e-3, 1e-4, 1e-1, 1e-4]. |
[0.001, 0.0001, 0.1, 0.0001]
|
iterations
|
int
|
Total training iterations. Defaults to 5000. |
5000
|
test_per_iter
|
int
|
Evaluate and save every N iterations. Defaults to 100. |
100
|
optim_mat
|
bool
|
If True, include material parameters (n, V) in optimisation. Defaults to False. |
False
|
shape_control
|
bool
|
If True, call |
True
|
sample_more_off_axis
|
bool
|
If True, concentrate ray samples
toward the edge of the field to improve off-axis correction.
Passed directly to |
False
|
result_dir
|
str
|
Directory to save results. If None, auto-generates a timestamped directory. Defaults to None. |
None
|
Note
Debug hints: 1. Slowly optimise with small learning rate. 2. FoV and thickness should match well. 3. Keep parameter ranges reasonable. 4. Higher aspheric order is better but more sensitive. 5. More iterations with larger ray sampling improves convergence.
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | |
find_diff_surf
Get differentiable/optimizable surface indices.
Returns a list of surface indices that can be optimized during lens design. Excludes the aperture surface from optimization.
Returns:
| Name | Type | Description |
|---|---|---|
diff_surf_range |
list or range
|
Surface indices excluding the aperture. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
get_optimizer_params
Build per-surface Adam parameter groups with per-type learning rates.
Collects trainable parameters for every surface (dispatching on surface type), plus the sensor distance, into a list of optimizer param groups.
Recommendation
For cellphone lens: [d_next, c, k, a], [1e-4, 1e-4, 1e-1, 1e-4]. For camera lens: [d_next, c, 0, 0], [1e-3, 1e-4, 0, 0].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lrs
|
list
|
Learning rates for the [d_next, c, k, a] parameter groups. Defaults to [1e-4, 1e-4, 1e-2, 1e-4]. |
[0.0001, 0.0001, 0.01, 0.0001]
|
optim_mat
|
bool
|
Whether to optimize material parameters. Defaults to False. |
False
|
optim_surf_range
|
list or None
|
Surface indices to optimize. When None, all surfaces are used. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
params |
list
|
List of optimizer parameter-group dicts. |
Raises:
| Type | Description |
|---|---|
Exception
|
If a surface type is not supported for optimization. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | |
get_optimizer
Build an Adam optimizer over all trainable lens parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lrs
|
list
|
Learning rates for the [d_next, c, k, ai] parameter groups. Defaults to [1e-4, 1e-4, 1e-1, 1e-4]. |
[0.0001, 0.0001, 0.1, 0.0001]
|
optim_surf_range
|
list or None
|
Surface indices to optimize. When None, all surfaces are included. Defaults to None. |
None
|
optim_mat
|
bool
|
Whether to include material parameters (n, V). Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
optimizer |
Adam
|
Configured Adam optimizer. |
Source code in deeplens-src/deeplens/geolens_pkg/optim.py
deeplens.geolens_pkg.ops.GeoLensOps
Mixin providing in-place lens operations for GeoLens.
Bundles methods that modify a lens during design optimization: sizing
clear apertures by ray tracing (pruning) and correcting lens geometry.
Intended to be mixed into the GeoLens class, so all methods access lens
state (self.surfaces, self.d_sensor, self.rfov, etc.) on the host.
Key methods
prune_surf: Size clear apertures by ray tracing. correct_shape: Fix lens geometry during optimization.
prune_surf
Prune surface radii so all valid rays pass through, then enforce manufacturability.
Traces 16 meridional fields from 0 to the full FoV to find the maximum
ray height [mm] on each surface, expands it by a mounting margin, then
caps the proposed radii to satisfy an edge-sag limit and edge-clearance
(air-gap / edge-thickness) constraints with neighbouring surfaces.
Aperture surfaces are not resized. The capped radii are committed via
each surface's update_r.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mounting_margin
|
float or None
|
Absolute mounting margin
[mm] added to the ray-traced clear-aperture radius. If |
None
|
Source code in deeplens-src/deeplens/geolens_pkg/ops.py
38 39 40 41 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
correct_shape
Correct invalid lens shape during lens design optimization.
The first surface is always at z=0 under sequential geometry, so shape correction only needs to prune surfaces to let valid rays pass.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mounting_margin
|
float or None
|
Absolute mounting margin
[mm] for surface pruning, passed through to |
None
|
Source code in deeplens-src/deeplens/geolens_pkg/ops.py
match_materials
Match each surface's material to the nearest entry in a glass catalog.
Replaces every surface's mat2 glass with the closest real catalog
glass in-place, making an idealised design manufacturable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mat_table
|
str
|
Glass catalog name. Supported values are 'CDGM' (default catalog) and 'PLASTIC'. Defaults to 'CDGM'. |
'CDGM'
|
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If |
Source code in deeplens-src/deeplens/geolens_pkg/ops.py
deeplens.geolens_pkg.render.GeoLensRender
Mixin providing image simulation for GeoLens.
Hosts render, the entry point that dispatches to reverse ray tracing or
to the PSF-convolution methods inherited from Lens. The ray-tracing path
is implemented here: rays are sampled at the sensor, traced backward
through the lens to the object plane, and integrated against the object
image. warp/unwarp apply and remove the corresponding geometric
distortion, which the PSF path needs because its kernels are locally
shift-invariant.
render
Differentiable image simulation.
Image simulation methods
[1] PSF map block convolution. [2] PSF patch convolution. [3] Ray tracing rendering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img_obj
|
Tensor
|
Input image object in raw space. Shape [N, C, H, W]. |
required |
depth
|
float
|
Object depth [mm]. When None (default),
falls back to |
None
|
method
|
str
|
Image simulation method. One of 'psf_map', 'psf_patch',
or 'ray_tracing'. When None (default), falls back to
|
None
|
**kwargs
|
Additional arguments for different methods: - psf_grid (tuple): Grid size for PSF map method. Defaults to (10, 10). - psf_ks (int): Kernel size for PSF methods. Defaults to PSF_KS. - psf_spp (int): Rays per PSF for PSF map method. Defaults to SPP_PSF. - warp_grid (int): Inverse-distortion grid resolution for PSF map method. Defaults to 128. - patch_center (tuple): Center position for PSF patch method. Defaults to (0.0, 0.0). - spp (int): Samples per pixel for ray tracing. Defaults to SPP_RENDER. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
img_render |
Tensor
|
Rendered image tensor. Shape of [N, C, H, W]. |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
sample_sensor
Sample rays from sensor pixels (backward rays). Used for ray-tracing based rendering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spp
|
int
|
sample per pixel. Defaults to 64. |
64
|
wvln
|
float
|
ray wvln in µm. When |
None
|
sub_pixel
|
bool
|
whether to sample multiple points inside the pixel. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Ray object. Shape [H, W, spp, 3] |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
render_raytracing
Render an RGB image using ray-tracing rendering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Tensor
|
RGB image tensor. Shape [N, 3, H, W]. |
required |
depth
|
float
|
Object depth [mm]. When None (default),
falls back to |
None
|
spp
|
int
|
Samples per pixel. Defaults to SPP_RENDER. |
SPP_RENDER
|
vignetting
|
bool
|
Whether to model the vignetting effect. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
img_render |
Tensor
|
Rendered RGB image tensor. Shape [N, 3, H, W]. |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
render_raytracing_mono
Render a monochrome image at a single wavelength using ray-tracing rendering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Tensor
|
Monochrome image tensor. Shape [N, 1, H, W] or [N, H, W]. |
required |
wvln
|
float
|
Wavelength in µm. |
required |
depth
|
float
|
Object depth [mm]. When None (default),
falls back to |
None
|
spp
|
int
|
Samples per pixel. Defaults to 64. |
64
|
vignetting
|
bool
|
Whether to model the vignetting effect. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
img_mono |
Tensor
|
Rendered monochrome image tensor. Shape [N, 1, H, W] or [N, H, W]. |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
render_compute_image
Compute ray-image-plane intersections and integrate them into a rendered image.
Propagates the traced rays to the object plane, intersects them with the scaled object image, and accumulates radiance following the rendering equation. Back-propagation gradient flow: image -> w_i -> u -> p -> ray -> surface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Tensor
|
Object image tensor. Shape [N, C, H, W] or [N, H, W]. |
required |
depth
|
float
|
Object depth [mm]. |
required |
scale
|
float
|
Object-to-image scale factor. |
required |
ray
|
Ray
|
Traced sensor rays. Shape [H, W, spp, 3]. |
required |
vignetting
|
bool
|
Whether to model the vignetting effect. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
image |
Tensor
|
Rendered image tensor. Shape [N, C, H, W] or [N, H, W]. |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
warp
Apply lens distortion to an image using inverse distortion mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Tensor
|
Undistorted image tensor, shape [B, C, H, W]. |
required |
depth
|
float
|
Object depth [mm]. When None (default),
falls back to |
None
|
num_grid
|
int or tuple
|
Resolution of the inverse distortion grid. |
128
|
Returns:
| Name | Type | Description |
|---|---|---|
img_warped |
Tensor
|
Distorted image tensor, shape |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
unwarp
Unwarp (remove distortion from) a rendered image using the distortion map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
img
|
Tensor
|
Rendered image tensor. Shape [N, C, H, W]. |
required |
depth
|
float
|
Object depth [mm]. When None (default),
falls back to |
None
|
num_grid
|
int
|
Resolution of the distortion grid. Defaults to 128. |
128
|
crop
|
bool
|
Whether to crop the image. Defaults to True. |
True
|
flip
|
bool
|
Whether to flip the distortion map. Defaults to True. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
img_unwarpped |
Tensor
|
Unwarped image tensor. Shape [N, C, H, W]. |
Source code in deeplens-src/deeplens/geolens_pkg/render.py
deeplens.geolens_pkg.io.GeoLensIO
Mixin providing lens-file I/O for GeoLens.
Adds read/write methods for three lens prescription formats: DeepLens
native JSON, Zemax sequential (.zmx), and Code V sequential (.seq). The
JSON format is primary and human-readable, with parenthesised keys (e.g.
"(d_sensor)") marking optimisable parameters. This class is not
instantiated directly; it is mixed into GeoLens, and its methods read
from and write to the host lens's state (surfaces, d_sensor,
r_sensor, enpd, rfov_eff, etc.).
read_lens_zmx
Load the lens from a Zemax .zmx sequential lens file.
Parses STANDARD and EVENASPH surface types, glass materials, field
definitions (YFLN, in degrees), and entrance pupil settings
(ENPD/FLOA). Populates self.surfaces, self.d_sensor [mm],
self.r_sensor [mm], self.enpd, self.float_enpd, and
self.rfov_eff [rad].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path to the .zmx file. Both UTF-8 and UTF-16 encodings are accepted. Defaults to './test.zmx'. |
'./test.zmx'
|
Returns:
| Name | Type | Description |
|---|---|---|
self |
GeoLens
|
The updated lens (for chaining). |
Source code in deeplens-src/deeplens/geolens_pkg/io.py
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | |
write_lens_zmx
Write the lens to a Zemax .zmx sequential lens file.
Exports surfaces (STANDARD or EVENASPH), materials, field definitions (YFLN at 0, 0.707, and 0.99 of the effective half-FoV, in degrees), RGB wavelengths, and entrance-pupil settings in Zemax OpticStudio format. An extra image (sensor) surface is appended.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Output file path. Defaults to './test.zmx'. |
'./test.zmx'
|
Source code in deeplens-src/deeplens/geolens_pkg/io.py
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | |
read_lens_seq
Load the lens from a Code V .seq sequential file.
Parses standard and aspheric surfaces (conic K and polynomial
coefficients A-I, mapped to even-aspheric terms ai[1]-ai[9]), entrance
pupil diameter (EPD), field angles (YAN, in degrees), aperture stop
(STO), and the image surface (SI). Populates self.surfaces,
self.d_sensor [mm], self.r_sensor [mm], self.enpd, self.hfov
[deg], and self.rfov_eff [rad]. Progress is printed to stdout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path to the .seq file. Both UTF-8 and Latin-1 encodings are accepted. Defaults to './test.seq'. |
'./test.seq'
|
Returns:
| Name | Type | Description |
|---|---|---|
self |
GeoLens
|
The updated lens (for chaining). |
Source code in deeplens-src/deeplens/geolens_pkg/io.py
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | |
write_lens_seq
Write the lens to a Code V .seq sequential file.
Exports refractive surfaces (spheric and aspheric; pure apertures are skipped), materials, field angles (YAN at 0, 0.707, and 0.99 of the effective half-FoV, in degrees), entrance pupil diameter, and the image surface in Code V format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Output file path. Defaults to './test.seq'. |
'./test.seq'
|
Returns:
| Name | Type | Description |
|---|---|---|
self |
GeoLens
|
The updated lens (for chaining). |
Source code in deeplens-src/deeplens/geolens_pkg/io.py
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 | |
read_lens_json
Read the lens from a DeepLens native JSON file.
Loads the surface list, sensor geometry, entrance pupil, and lens info,
rebuilding each surface from its type field via init_from_dict.
Absolute surface positions and self.d_sensor are derived from the
per-surface d_next prefix sums.
Sets self.r_sensor [mm], self.enpd, and self.float_enpd, then
configures the sensor resolution from sensor_res (default
2000 x 2000).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path to the JSON lens file. Defaults to './test.json'. |
'./test.json'
|
Raises:
| Type | Description |
|---|---|
Exception
|
If a surface |
Note
After loading, the lens is moved to self.device.
Source code in deeplens-src/deeplens/geolens_pkg/io.py
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 | |
write_lens_json
Write the lens to a DeepLens native JSON file.
Saves lens info, focal length [mm], F-number, entrance pupil diameter,
sensor radius/size [mm] and resolution, and all surfaces (each via
surf_dict) with their per-surface spacing d_next [mm]. Numeric
values are rounded to 4 decimal places.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path for the output JSON file. Defaults to './test.json'. |
'./test.json'
|
Source code in deeplens-src/deeplens/geolens_pkg/io.py
deeplens.geolens_pkg.vis.GeoLensVis
Mixin providing 2D lens layout and ray visualization for GeoLens.
Generates publication-quality cross-section plots showing lens surfaces and traced ray bundles in either the meridional or sagittal plane.
This class is not instantiated directly; it is mixed into
GeoLens.
sample_parallel_2D
sample_parallel_2D(
fov=0.0, num_rays=7, wvln=None, plane="meridional", entrance_pupil=True, depth=0.0
)
Sample parallel rays (2D) in object space.
Used for (1) drawing lens setup, (2) 2D geometric optics calculation, for example, refocusing to infinity
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fov
|
float
|
Incident angle [degree]. Defaults to 0.0. |
0.0
|
num_rays
|
int
|
Number of rays. Defaults to 7. |
7
|
wvln
|
float or None
|
Ray wavelength [µm]. When None,
falls back to |
None
|
plane
|
str
|
Sampling plane, "meridional" (y-z plane) or "sagittal" (x-z plane). Defaults to "meridional". |
'meridional'
|
entrance_pupil
|
bool
|
If True, sample on the entrance pupil; otherwise sample on the first surface aperture. Defaults to True. |
True
|
depth
|
float
|
Sampling depth [mm] to propagate rays to. Defaults to 0.0. |
0.0
|
Returns:
| Name | Type | Description |
|---|---|---|
rays |
Ray
|
Sampled rays with origin/direction tensors of shape [num_rays, 3]. |
Source code in deeplens-src/deeplens/geolens_pkg/vis.py
sample_point_source_2D
Sample point source rays (2D) in object space.
Used for (1) drawing lens setup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fov
|
float
|
Incident angle [degree]. Defaults to 0.0. |
0.0
|
depth
|
float or None
|
Object-plane depth [mm]. When None,
falls back to |
None
|
num_rays
|
int
|
Number of rays. Defaults to 7. |
7
|
wvln
|
float or None
|
Ray wavelength [µm]. When None,
falls back to |
None
|
entrance_pupil
|
bool
|
If True, aim rays at the entrance pupil; otherwise aim at the first surface aperture. Defaults to True. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
ray |
Ray
|
Sampled rays with origin/direction tensors of shape [num_rays, 3]. |
Source code in deeplens-src/deeplens/geolens_pkg/vis.py
draw_layout
draw_layout(
filename,
depth=float("inf"),
zmx_format=True,
multi_plot=False,
lens_title=None,
show=False,
return_fig=False,
)
Plot 2D lens layout with ray tracing.
The title is auto-generated when lens_title is None: it includes
focal length, F-number, FoV, IMGH, RGB wavelengths, and a second line
with per-FoV RMS spot radii from analysis_spot().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Output filename. |
required |
depth
|
float
|
Object distance for ray tracing [mm]. Use |
float('inf')
|
zmx_format
|
bool
|
If True, draw surfaces in Zemax style. Defaults to True. |
True
|
multi_plot
|
bool
|
If True, create one sub-plot per wavelength. Defaults to False. |
False
|
lens_title
|
str or None
|
Title string. If None, auto-generated. Defaults to None. |
None
|
show
|
bool
|
If True, display the figure interactively instead of saving. Defaults to False. |
False
|
return_fig
|
bool
|
If True, return the axes and figure without
saving or closing them (for overlay drawing by callers such as
|
False
|
Returns:
| Name | Type | Description |
|---|---|---|
result |
tuple or None
|
When |
Source code in deeplens-src/deeplens/geolens_pkg/vis.py
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | |
draw_lens_2d
Draw lens cross-section layout in a 2D plot.
Renders each surface profile, connects lens elements with edge lines, and draws the sensor plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ax
|
Axes
|
Existing axes to draw on. If None, creates a new figure. Defaults to None. |
None
|
fig
|
Figure
|
Existing figure. Defaults to None. |
None
|
color
|
str
|
Line colour for lens outlines. Defaults to 'k'. |
'k'
|
linestyle
|
str
|
Line style. Defaults to '-'. |
'-'
|
zmx_format
|
bool
|
If True, draw stepped edge connections matching Zemax layout style. Defaults to False. |
False
|
fix_bound
|
bool
|
If True, use fixed axis limits [-1,7]x[-4,4]. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
ax |
Axes
|
The axes with the lens layout drawn. |
fig |
Figure
|
The figure. |
Source code in deeplens-src/deeplens/geolens_pkg/vis.py
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | |
draw_ray_2d
Plot ray paths onto an existing 2D layout.
Each recorded ray origin is a [num_rays, 3] (or [num_view, num_rays, 3]) tensor; stacking them yields [num_view, num_rays, num_path, 3] where the last axis holds (x, y, z) in [mm]. The z (axial) and x (radial) components are drawn as polylines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ray_o_record
|
list
|
List of ray-origin tensors, one per traced surface, each of shape [num_rays, 3] or [num_view, num_rays, 3]. |
required |
ax
|
Axes
|
Matplotlib axes to draw on. |
required |
fig
|
Figure
|
Matplotlib figure. |
required |
color
|
str
|
Line colour for the ray paths. Defaults to 'b'. |
'b'
|
Returns:
| Name | Type | Description |
|---|---|---|
ax |
Axes
|
The axes with ray paths drawn. |
fig |
Figure
|
The figure. |
Source code in deeplens-src/deeplens/geolens_pkg/vis.py
create_barrier
Draw a lens barrel (barrier) overlay on the 2D lens layout and save it.
Computes barrier segments spanning each air gap (extending to the midpoint
of the following air space, or to the sensor for the last segment), overlays
them in green on the layout from draw_layout, and saves the figure as a PNG.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path to save the output PNG figure. |
required |
barrier_thickness
|
float
|
Barrier thickness [mm]. Defaults to 1.0. |
1.0
|
ring_height
|
float
|
Annular ring height [mm]. Currently unused (ring drawing is not implemented). Defaults to 0.5. |
0.5
|
ring_size
|
float
|
Annular ring size [mm]. Currently unused (ring drawing is not implemented). Defaults to 1.0. |
1.0
|
Source code in deeplens-src/deeplens/geolens_pkg/vis.py
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | |
deeplens.geolens_pkg.vis3d.GeoLensVis3D
Mixin providing 3D mesh visualization for GeoLens.
Creates lens surface, aperture, barrier, sensor, and ray-path meshes as
polygon data and optionally renders them with PyVista. All geometry is
expressed in millimetres [mm] and stored as CrossPoly (vertex/face)
objects that can be saved to .obj files for external renderers.
This class is not instantiated directly; it is mixed into GeoLens.
create_mesh
Build surface, bridge, and sensor meshes for the whole lens.
Surfaces are grouped into optical elements (split wherever a surface
borders air). Adjacent surfaces within an element are joined by bridge
face strips; with is_wrap the bridges are projected to form a
cylindrical barrel between elements of differing radii.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mesh_rings
|
int
|
Number of rings per surface mesh. Defaults to 32. |
32
|
mesh_arms
|
int
|
Number of arms per surface mesh. Defaults to 128. |
128
|
is_wrap
|
bool
|
Whether to wrap the lens barrel around the elements as a cylinder. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
surf_meshes_cvt |
List[FaceMesh]
|
Per-surface face meshes. |
bridge_meshes |
List[List[FaceMesh]]
|
Per-element lists of bridge face meshes (empty list for single-surface elements). |
element_groups |
List[List[int]]
|
Surface-index groups, one per optical element. |
sensor_mesh |
RectangleMesh
|
The rectangular sensor mesh. |
Source code in deeplens-src/deeplens/geolens_pkg/vis3d.py
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | |
draw_lens_3d
draw_lens_3d(
plotter=None,
save_dir: Optional[str] = None,
mesh_rings: int = 32,
mesh_arms: int = 128,
surface_color: List[float] = [0.06, 0.3, 0.6],
draw_rays: bool = True,
fovs: List[float] = [0.0],
fov_phis: List[float] = [0.0],
ray_rings: int = 6,
ray_arms: int = 8,
is_wrap: bool = False,
)
Render the 3D lens layout (surfaces, sensor, and optional rays) with PyVista.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plotter
|
Plotter
|
Existing plotter to draw into. A new one is created when None. Defaults to None. |
None
|
save_dir
|
str
|
Directory to save the rendered screenshot
|
None
|
mesh_rings
|
int
|
Number of rings per surface mesh. Defaults to 32. |
32
|
mesh_arms
|
int
|
Number of arms per surface mesh. Defaults to 128. |
128
|
surface_color
|
List[float]
|
RGB surface color, each in [0, 1]. Defaults to [0.06, 0.3, 0.6]. |
[0.06, 0.3, 0.6]
|
draw_rays
|
bool
|
Whether to trace and draw rays. Defaults to True. |
True
|
fovs
|
List[float]
|
Field-of-view angles to sample [degree]. Defaults to [0.0]. |
[0.0]
|
fov_phis
|
List[float]
|
Field azimuthal angles to sample [degree]. Defaults to [0.0]. |
[0.0]
|
ray_rings
|
int
|
Number of pupil rings to sample. Defaults to 6. |
6
|
ray_arms
|
int
|
Number of pupil arms to sample. Defaults to 8. |
8
|
is_wrap
|
bool
|
Whether to wrap the lens barrel as a cylinder. Defaults to False. |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
plotter |
Plotter
|
The plotter with all meshes added. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If PyVista is not installed (imported lazily here). |
Note
PyVista is imported lazily only when this method is called.
Source code in deeplens-src/deeplens/geolens_pkg/vis3d.py
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 | |
save_lens_obj
save_lens_obj(
save_dir: str,
mesh_rings: int = 64,
mesh_arms: int = 128,
save_rays: bool = False,
fovs: List[float] = [0.0],
fov_phis: List[float] = [0.0],
ray_rings: int = 6,
ray_arms: int = 8,
is_wrap: bool = False,
save_elements: bool = True,
)
Save lens geometry, sensor, and optional rays as Wavefront .obj files.
Writes lens.obj (all surfaces and bridges merged, apertures excluded)
and sensor.obj. When save_elements is True, also writes one
element_{i}.obj per optical element; when save_rays is True, writes
one lens_rays_fov_{i}.obj per traced field bundle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
save_dir
|
str
|
Directory to write the |
required |
mesh_rings
|
int
|
Number of rings per surface mesh. Defaults to 64. |
64
|
mesh_arms
|
int
|
Number of arms per surface mesh. Defaults to 128. |
128
|
save_rays
|
bool
|
Whether to trace and save rays. Defaults to False. |
False
|
fovs
|
List[float]
|
Field-of-view angles to sample [degree]. Defaults to [0.0]. |
[0.0]
|
fov_phis
|
List[float]
|
Field azimuthal angles to sample [degree]. Defaults to [0.0]. |
[0.0]
|
ray_rings
|
int
|
Number of pupil rings to sample. Defaults to 6. |
6
|
ray_arms
|
int
|
Number of pupil arms to sample. Defaults to 8. |
8
|
is_wrap
|
bool
|
Whether to wrap the lens barrel as a cylinder. Defaults to False. |
False
|
save_elements
|
bool
|
Whether to additionally save per-element
|
True
|
Note
Use #F2F7FFFF as the lens color when rendering in Blender. This
routine writes .obj files directly and does not require PyVista.
Source code in deeplens-src/deeplens/geolens_pkg/vis3d.py
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 | |