photonlibpy 2025.0.0b2__py3-none-any.whl → 2025.0.0b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- photonlibpy/estimation/openCVHelp.py +117 -7
- photonlibpy/estimation/rotTrlTransform3d.py +43 -1
- photonlibpy/estimation/targetModel.py +126 -80
- photonlibpy/estimation/visionEstimation.py +26 -4
- photonlibpy/generated/MultiTargetPNPResultSerde.py +7 -1
- photonlibpy/generated/PhotonPipelineMetadataSerde.py +6 -1
- photonlibpy/generated/PhotonPipelineResultSerde.py +9 -1
- photonlibpy/generated/PhotonTrackedTargetSerde.py +7 -1
- photonlibpy/generated/PnpResultSerde.py +6 -1
- photonlibpy/generated/TargetCornerSerde.py +6 -1
- photonlibpy/networktables/NTTopicSet.py +11 -2
- photonlibpy/photonCamera.py +69 -2
- photonlibpy/simulation/photonCameraSim.py +127 -51
- photonlibpy/simulation/simCameraProperties.py +184 -63
- photonlibpy/simulation/visionSystemSim.py +104 -7
- photonlibpy/simulation/visionTargetSim.py +10 -0
- photonlibpy/targeting/TargetCorner.py +2 -2
- photonlibpy/targeting/multiTargetPNPResult.py +4 -15
- photonlibpy/targeting/photonPipelineResult.py +4 -3
- photonlibpy/targeting/photonTrackedTarget.py +2 -2
- photonlibpy/version.py +2 -2
- {photonlibpy-2025.0.0b2.dist-info → photonlibpy-2025.0.0b4.dist-info}/METADATA +8 -9
- photonlibpy-2025.0.0b4.dist-info/RECORD +36 -0
- photonlibpy-2025.0.0b2.dist-info/RECORD +0 -36
- {photonlibpy-2025.0.0b2.dist-info → photonlibpy-2025.0.0b4.dist-info}/WHEEL +0 -0
- {photonlibpy-2025.0.0b2.dist-info → photonlibpy-2025.0.0b4.dist-info}/top_level.txt +0 -0
@@ -11,7 +11,22 @@ from ..estimation import RotTrlTransform3d
|
|
11
11
|
|
12
12
|
|
13
13
|
class SimCameraProperties:
|
14
|
-
|
14
|
+
"""Calibration and performance values for this camera.
|
15
|
+
|
16
|
+
The resolution will affect the accuracy of projected(3d to 2d) target corners and similarly
|
17
|
+
the severity of image noise on estimation(2d to 3d).
|
18
|
+
|
19
|
+
The camera intrinsics and distortion coefficients describe the results of calibration, and how
|
20
|
+
to map between 3d field points and 2d image points.
|
21
|
+
|
22
|
+
The performance values (framerate/exposure time, latency) determine how often results should
|
23
|
+
be updated and with how much latency in simulation. High exposure time causes motion blur which
|
24
|
+
can inhibit target detection while moving. Note that latency estimation does not account for
|
25
|
+
network latency and the latency reported will always be perfect.
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(self):
|
29
|
+
"""Default constructor which is the same as {@link #PERFECT_90DEG}"""
|
15
30
|
self.resWidth: int = -1
|
16
31
|
self.resHeight: int = -1
|
17
32
|
self.camIntrinsics: np.ndarray = np.zeros((3, 3)) # [3,3]
|
@@ -24,63 +39,52 @@ class SimCameraProperties:
|
|
24
39
|
self.latencyStdDev: seconds = 0.0
|
25
40
|
self.viewplanes: list[np.ndarray] = [] # [3,1]
|
26
41
|
|
27
|
-
|
28
|
-
self.setCalibration(960, 720, fovDiag=Rotation2d(math.radians(90.0)))
|
29
|
-
else:
|
30
|
-
raise Exception("not yet implemented")
|
31
|
-
|
32
|
-
def setCalibration(
|
33
|
-
self,
|
34
|
-
width: int,
|
35
|
-
height: int,
|
36
|
-
*,
|
37
|
-
fovDiag: Rotation2d | None = None,
|
38
|
-
newCamIntrinsics: np.ndarray | None = None,
|
39
|
-
newDistCoeffs: np.ndarray | None = None,
|
40
|
-
):
|
41
|
-
# Should be an inverted XOR on the args to differentiate between the signatures
|
42
|
-
|
43
|
-
has_fov_args = fovDiag is not None
|
44
|
-
has_matrix_args = newCamIntrinsics is not None and newDistCoeffs is not None
|
42
|
+
self.setCalibrationFromFOV(960, 720, fovDiag=Rotation2d(math.radians(90.0)))
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
def setCalibrationFromFOV(
|
45
|
+
self, width: int, height: int, fovDiag: Rotation2d
|
46
|
+
) -> None:
|
47
|
+
if fovDiag.degrees() < 1.0 or fovDiag.degrees() > 179.0:
|
48
|
+
fovDiag = Rotation2d.fromDegrees(max(min(fovDiag.degrees(), 179.0), 1.0))
|
49
|
+
logging.error("Requested invalid FOV! Clamping between (1, 179) degrees...")
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
)
|
56
|
-
logging.error(
|
57
|
-
"Requested invalid FOV! Clamping between (1, 179) degrees..."
|
58
|
-
)
|
51
|
+
resDiag = math.sqrt(width * width + height * height)
|
52
|
+
diagRatio = math.tan(fovDiag.radians() / 2.0)
|
53
|
+
fovWidth = Rotation2d(math.atan((diagRatio * (width / resDiag)) * 2))
|
54
|
+
fovHeight = Rotation2d(math.atan(diagRatio * (height / resDiag)) * 2)
|
59
55
|
|
60
|
-
|
61
|
-
|
62
|
-
fovWidth = Rotation2d(math.atan((diagRatio * (width / resDiag)) * 2))
|
63
|
-
fovHeight = Rotation2d(math.atan(diagRatio * (height / resDiag)) * 2)
|
56
|
+
# assume no distortion
|
57
|
+
newDistCoeffs = np.zeros((8, 1))
|
64
58
|
|
65
|
-
|
59
|
+
# assume centered principal point (pixels)
|
60
|
+
cx = width / 2.0 - 0.5
|
61
|
+
cy = height / 2.0 - 0.5
|
66
62
|
|
67
|
-
|
68
|
-
|
63
|
+
# use given fov to determine focal point (pixels)
|
64
|
+
fx = cx / math.tan(fovWidth.radians() / 2.0)
|
65
|
+
fy = cy / math.tan(fovHeight.radians() / 2.0)
|
69
66
|
|
70
|
-
|
71
|
-
|
67
|
+
# create camera intrinsics matrix
|
68
|
+
newCamIntrinsics = np.array([[fx, 0.0, cx], [0.0, fy, cy], [0.0, 0.0, 1.0]])
|
72
69
|
|
73
|
-
|
70
|
+
self.setCalibrationFromIntrinsics(
|
71
|
+
width, height, newCamIntrinsics, newDistCoeffs
|
72
|
+
)
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
def setCalibrationFromIntrinsics(
|
75
|
+
self,
|
76
|
+
width: int,
|
77
|
+
height: int,
|
78
|
+
newCamIntrinsics: np.ndarray,
|
79
|
+
newDistCoeffs: np.ndarray,
|
80
|
+
) -> None:
|
78
81
|
|
79
82
|
self.resWidth = width
|
80
83
|
self.resHeight = height
|
81
84
|
self.camIntrinsics = newCamIntrinsics
|
82
85
|
self.distCoeffs = newDistCoeffs
|
83
86
|
|
87
|
+
# left, right, up, and down view planes
|
84
88
|
p = [
|
85
89
|
Translation3d(
|
86
90
|
1.0,
|
@@ -126,16 +130,33 @@ class SimCameraProperties:
|
|
126
130
|
self.errorStdDevPx = newErrorStdDevPx
|
127
131
|
|
128
132
|
def setFPS(self, fps: hertz):
|
133
|
+
"""
|
134
|
+
:param fps: The average frames per second the camera should process at. :strong:`Exposure time limits
|
135
|
+
FPS if set!`
|
136
|
+
"""
|
137
|
+
|
129
138
|
self.frameSpeed = max(1.0 / fps, self.exposureTime)
|
130
139
|
|
131
140
|
def setExposureTime(self, newExposureTime: seconds):
|
141
|
+
"""
|
142
|
+
:param newExposureTime: The amount of time the "shutter" is open for one frame. Affects motion
|
143
|
+
blur. **Frame speed(from FPS) is limited to this!**
|
144
|
+
"""
|
145
|
+
|
132
146
|
self.exposureTime = newExposureTime
|
133
147
|
self.frameSpeed = max(self.frameSpeed, self.exposureTime)
|
134
148
|
|
135
149
|
def setAvgLatency(self, newAvgLatency: seconds):
|
150
|
+
"""
|
151
|
+
:param newAvgLatency: The average latency (from image capture to data published) in milliseconds
|
152
|
+
a frame should have
|
153
|
+
"""
|
136
154
|
self.vgLatency = newAvgLatency
|
137
155
|
|
138
156
|
def setLatencyStdDev(self, newLatencyStdDev: seconds):
|
157
|
+
"""
|
158
|
+
:param latencyStdDevMs: The standard deviation in milliseconds of the latency
|
159
|
+
"""
|
139
160
|
self.latencyStdDev = newLatencyStdDev
|
140
161
|
|
141
162
|
def getResWidth(self) -> int:
|
@@ -171,31 +192,72 @@ class SimCameraProperties:
|
|
171
192
|
def getLatencyStdDev(self) -> seconds:
|
172
193
|
return self.latencyStdDev
|
173
194
|
|
174
|
-
def getContourAreaPercent(self, points:
|
175
|
-
|
176
|
-
|
177
|
-
|
195
|
+
def getContourAreaPercent(self, points: np.ndarray) -> float:
|
196
|
+
"""The percentage(0 - 100) of this camera's resolution the contour takes up in pixels of the
|
197
|
+
image.
|
198
|
+
|
199
|
+
:param points: Points of the contour
|
200
|
+
"""
|
201
|
+
|
202
|
+
return cv.contourArea(cv.convexHull(points)) / self.getResArea() * 100.0
|
178
203
|
|
179
204
|
def getPixelYaw(self, pixelX: float) -> Rotation2d:
|
205
|
+
"""The yaw from the principal point of this camera to the pixel x value. Positive values left."""
|
180
206
|
fx = self.camIntrinsics[0, 0]
|
207
|
+
# account for principal point not being centered
|
181
208
|
cx = self.camIntrinsics[0, 2]
|
182
209
|
xOffset = cx - pixelX
|
183
210
|
return Rotation2d(fx, xOffset)
|
184
211
|
|
185
212
|
def getPixelPitch(self, pixelY: float) -> Rotation2d:
|
213
|
+
"""The pitch from the principal point of this camera to the pixel y value. Pitch is positive down.
|
214
|
+
|
215
|
+
Note that this angle is naively computed and may be incorrect. See {@link
|
216
|
+
#getCorrectedPixelRot(Point)}.
|
217
|
+
"""
|
218
|
+
|
186
219
|
fy = self.camIntrinsics[1, 1]
|
220
|
+
# account for principal point not being centered
|
187
221
|
cy = self.camIntrinsics[1, 2]
|
188
222
|
yOffset = cy - pixelY
|
189
223
|
return Rotation2d(fy, -yOffset)
|
190
224
|
|
191
|
-
def getPixelRot(self, point: typing.
|
225
|
+
def getPixelRot(self, point: cv.typing.Point2f) -> Rotation3d:
|
226
|
+
"""Finds the yaw and pitch to the given image point. Yaw is positive left, and pitch is positive
|
227
|
+
down.
|
228
|
+
|
229
|
+
Note that pitch is naively computed and may be incorrect. See {@link
|
230
|
+
#getCorrectedPixelRot(Point)}.
|
231
|
+
"""
|
232
|
+
|
192
233
|
return Rotation3d(
|
193
234
|
0.0,
|
194
235
|
self.getPixelPitch(point[1]).radians(),
|
195
236
|
self.getPixelYaw(point[0]).radians(),
|
196
237
|
)
|
197
238
|
|
198
|
-
def getCorrectedPixelRot(self, point: typing.
|
239
|
+
def getCorrectedPixelRot(self, point: cv.typing.Point2f) -> Rotation3d:
|
240
|
+
"""Gives the yaw and pitch of the line intersecting the camera lens and the given pixel
|
241
|
+
coordinates on the sensor. Yaw is positive left, and pitch positive down.
|
242
|
+
|
243
|
+
The pitch traditionally calculated from pixel offsets do not correctly account for non-zero
|
244
|
+
values of yaw because of perspective distortion (not to be confused with lens distortion)-- for
|
245
|
+
example, the pitch angle is naively calculated as:
|
246
|
+
|
247
|
+
<pre>pitch = arctan(pixel y offset / focal length y)</pre>
|
248
|
+
|
249
|
+
However, using focal length as a side of the associated right triangle is not correct when the
|
250
|
+
pixel x value is not 0, because the distance from this pixel (projected on the x-axis) to the
|
251
|
+
camera lens increases. Projecting a line back out of the camera with these naive angles will
|
252
|
+
not intersect the 3d point that was originally projected into this 2d pixel. Instead, this
|
253
|
+
length should be:
|
254
|
+
|
255
|
+
<pre>focal length y ⟶ (focal length y / cos(arctan(pixel x offset / focal length x)))</pre>
|
256
|
+
|
257
|
+
:returns: Rotation3d with yaw and pitch of the line projected out of the camera from the given
|
258
|
+
pixel (roll is zero).
|
259
|
+
"""
|
260
|
+
|
199
261
|
fx = self.camIntrinsics[0, 0]
|
200
262
|
cx = self.camIntrinsics[0, 2]
|
201
263
|
xOffset = cx - point[0]
|
@@ -209,11 +271,13 @@ class SimCameraProperties:
|
|
209
271
|
return Rotation3d(0.0, pitch.radians(), yaw.radians())
|
210
272
|
|
211
273
|
def getHorizFOV(self) -> Rotation2d:
|
274
|
+
# sum of FOV left and right principal point
|
212
275
|
left = self.getPixelYaw(0)
|
213
276
|
right = self.getPixelYaw(self.resWidth)
|
214
277
|
return left - right
|
215
278
|
|
216
279
|
def getVertFOV(self) -> Rotation2d:
|
280
|
+
# sum of FOV above and below principal point
|
217
281
|
above = self.getPixelPitch(0)
|
218
282
|
below = self.getPixelPitch(self.resHeight)
|
219
283
|
return below - above
|
@@ -226,9 +290,34 @@ class SimCameraProperties:
|
|
226
290
|
def getVisibleLine(
|
227
291
|
self, camRt: RotTrlTransform3d, a: Translation3d, b: Translation3d
|
228
292
|
) -> typing.Tuple[float | None, float | None]:
|
229
|
-
|
230
|
-
|
231
|
-
|
293
|
+
"""Determines where the line segment defined by the two given translations intersects the camera's
|
294
|
+
frustum/field-of-vision, if at all.
|
295
|
+
|
296
|
+
The line is parametrized so any of its points <code>p = t * (b - a) + a</code>. This method
|
297
|
+
returns these values of t, minimum first, defining the region of the line segment which is
|
298
|
+
visible in the frustum. If both ends of the line segment are visible, this simply returns {0,
|
299
|
+
1}. If, for example, point b is visible while a is not, and half of the line segment is inside
|
300
|
+
the camera frustum, {0.5, 1} would be returned.
|
301
|
+
|
302
|
+
:param camRt: The change in basis from world coordinates to camera coordinates. See {@link
|
303
|
+
RotTrlTransform3d#makeRelativeTo(Pose3d)}.
|
304
|
+
:param a: The initial translation of the line
|
305
|
+
:param b: The final translation of the line
|
306
|
+
|
307
|
+
:returns: A Pair of Doubles. The values may be null:
|
308
|
+
|
309
|
+
- {Double, Double} : Two parametrized values(t), minimum first, representing which
|
310
|
+
segment of the line is visible in the camera frustum.
|
311
|
+
- {Double, null} : One value(t) representing a single intersection point. For example,
|
312
|
+
the line only intersects the intersection of two adjacent viewplanes.
|
313
|
+
- {null, null} : No values. The line segment is not visible in the camera frustum.
|
314
|
+
"""
|
315
|
+
|
316
|
+
# translations relative to the camera
|
317
|
+
relA = camRt.applyTranslation(a)
|
318
|
+
relB = camRt.applyTranslation(b)
|
319
|
+
|
320
|
+
# check if both ends are behind camera
|
232
321
|
if relA.X() <= 0.0 and relB.X() <= 0.0:
|
233
322
|
return (None, None)
|
234
323
|
|
@@ -239,6 +328,7 @@ class SimCameraProperties:
|
|
239
328
|
aVisible = True
|
240
329
|
bVisible = True
|
241
330
|
|
331
|
+
# check if the ends of the line segment are visible
|
242
332
|
for normal in self.viewplanes:
|
243
333
|
aVisibility = av.dot(normal)
|
244
334
|
if aVisibility < 0:
|
@@ -247,39 +337,55 @@ class SimCameraProperties:
|
|
247
337
|
bVisibility = bv.dot(normal)
|
248
338
|
if bVisibility < 0:
|
249
339
|
bVisible = False
|
340
|
+
# both ends are outside at least one of the same viewplane
|
250
341
|
if aVisibility <= 0 and bVisibility <= 0:
|
251
342
|
return (None, None)
|
252
343
|
|
344
|
+
# both ends are inside frustum
|
253
345
|
if aVisible and bVisible:
|
254
346
|
return (0.0, 1.0)
|
255
347
|
|
348
|
+
# parametrized (t=0 at a, t=1 at b) intersections with viewplanes
|
256
349
|
intersections = [float("nan"), float("nan"), float("nan"), float("nan")]
|
257
350
|
|
258
351
|
# Optionally 3x1 vector
|
259
352
|
ipts: typing.List[np.ndarray | None] = [None, None, None, None]
|
260
353
|
|
354
|
+
# find intersections
|
261
355
|
for i, normal in enumerate(self.viewplanes):
|
356
|
+
|
357
|
+
# // we want to know the value of t when the line intercepts this plane
|
358
|
+
# // parametrized: v = t * ab + a, where v lies on the plane
|
359
|
+
# // we can find the projection of a onto the plane normal
|
360
|
+
# // a_projn = normal.times(av.dot(normal) / normal.dot(normal));
|
262
361
|
a_projn = (av.dot(normal) / normal.dot(normal)) * normal
|
263
362
|
|
363
|
+
# // this projection lets us determine the scalar multiple t of ab where
|
364
|
+
# // (t * ab + a) is a vector which lies on the plane
|
264
365
|
if abs(abv.dot(normal)) < 1.0e-5:
|
265
366
|
continue
|
266
367
|
intersections[i] = a_projn.dot(a_projn) / -(abv.dot(a_projn))
|
267
368
|
|
369
|
+
# // vector a to the viewplane
|
268
370
|
apv = intersections[i] * abv
|
371
|
+
# av + apv = intersection point
|
269
372
|
intersectpt = av + apv
|
270
373
|
ipts[i] = intersectpt
|
271
374
|
|
375
|
+
# // discard intersections outside the camera frustum
|
272
376
|
for j in range(1, len(self.viewplanes)):
|
273
377
|
if j == 0:
|
274
378
|
continue
|
275
379
|
oi = (i + j) % len(self.viewplanes)
|
276
380
|
onormal = self.viewplanes[oi]
|
381
|
+
# if the dot of the intersection point with any plane normal is negative, it is outside
|
277
382
|
if intersectpt.dot(onormal) < 0:
|
278
383
|
intersections[i] = float("nan")
|
279
384
|
ipts[i] = None
|
280
385
|
break
|
281
386
|
|
282
|
-
|
387
|
+
# // discard duplicate intersections
|
388
|
+
if ipts[i] is None:
|
283
389
|
continue
|
284
390
|
|
285
391
|
for j in range(i - 1, 0 - 1):
|
@@ -293,6 +399,7 @@ class SimCameraProperties:
|
|
293
399
|
ipts[i] = None
|
294
400
|
break
|
295
401
|
|
402
|
+
# determine visible segment (minimum and maximum t)
|
296
403
|
inter1 = float("nan")
|
297
404
|
inter2 = float("nan")
|
298
405
|
for inter in intersections:
|
@@ -302,6 +409,7 @@ class SimCameraProperties:
|
|
302
409
|
else:
|
303
410
|
inter2 = inter
|
304
411
|
|
412
|
+
# // two viewplane intersections
|
305
413
|
if not math.isnan(inter2):
|
306
414
|
max_ = max(inter1, inter2)
|
307
415
|
min_ = min(inter1, inter2)
|
@@ -310,16 +418,19 @@ class SimCameraProperties:
|
|
310
418
|
if bVisible:
|
311
419
|
max_ = 1
|
312
420
|
return (min_, max_)
|
421
|
+
# // one viewplane intersection
|
313
422
|
elif not math.isnan(inter1):
|
314
423
|
if aVisible:
|
315
424
|
return (0, inter1)
|
316
425
|
if bVisible:
|
317
426
|
return (inter1, 1)
|
318
427
|
return (inter1, None)
|
428
|
+
# no intersections
|
319
429
|
else:
|
320
430
|
return (None, None)
|
321
431
|
|
322
432
|
def estPixelNoise(self, points: np.ndarray) -> np.ndarray:
|
433
|
+
"""Returns these points after applying this camera's estimated noise."""
|
323
434
|
assert points.shape[1] == 1, points.shape
|
324
435
|
assert points.shape[2] == 2, points.shape
|
325
436
|
if self.avgErrorPx == 0 and self.errorStdDevPx == 0:
|
@@ -327,6 +438,7 @@ class SimCameraProperties:
|
|
327
438
|
|
328
439
|
noisyPts: list[list] = []
|
329
440
|
for p in points:
|
441
|
+
# // error pixels in random direction
|
330
442
|
error = np.random.normal(self.avgErrorPx, self.errorStdDevPx, 1)[0]
|
331
443
|
errorAngle = np.random.uniform(-math.pi, math.pi)
|
332
444
|
noisyPts.append(
|
@@ -342,22 +454,31 @@ class SimCameraProperties:
|
|
342
454
|
return retval
|
343
455
|
|
344
456
|
def estLatency(self) -> seconds:
|
457
|
+
"""
|
458
|
+
:returns: Noisy estimation of a frame's processing latency
|
459
|
+
"""
|
460
|
+
|
345
461
|
return max(
|
346
462
|
float(np.random.normal(self.avgLatency, self.latencyStdDev, 1)[0]),
|
347
463
|
0.0,
|
348
464
|
)
|
349
465
|
|
350
466
|
def estSecUntilNextFrame(self) -> seconds:
|
467
|
+
"""
|
468
|
+
:returns: Estimate how long until the next frame should be processed in milliseconds
|
469
|
+
"""
|
470
|
+
# // exceptional processing latency blocks the next frame
|
351
471
|
return self.frameSpeed + max(0.0, self.estLatency() - self.frameSpeed)
|
352
472
|
|
353
473
|
@classmethod
|
354
474
|
def PERFECT_90DEG(cls) -> typing.Self:
|
475
|
+
"""960x720 resolution, 90 degree FOV, "perfect" lagless camera"""
|
355
476
|
return cls()
|
356
477
|
|
357
478
|
@classmethod
|
358
479
|
def PI4_LIFECAM_320_240(cls) -> typing.Self:
|
359
480
|
prop = cls()
|
360
|
-
prop.
|
481
|
+
prop.setCalibrationFromIntrinsics(
|
361
482
|
320,
|
362
483
|
240,
|
363
484
|
newCamIntrinsics=np.array(
|
@@ -391,7 +512,7 @@ class SimCameraProperties:
|
|
391
512
|
@classmethod
|
392
513
|
def PI4_LIFECAM_640_480(cls) -> typing.Self:
|
393
514
|
prop = cls()
|
394
|
-
prop.
|
515
|
+
prop.setCalibrationFromIntrinsics(
|
395
516
|
640,
|
396
517
|
480,
|
397
518
|
newCamIntrinsics=np.array(
|
@@ -425,7 +546,7 @@ class SimCameraProperties:
|
|
425
546
|
@classmethod
|
426
547
|
def LL2_640_480(cls) -> typing.Self:
|
427
548
|
prop = cls()
|
428
|
-
prop.
|
549
|
+
prop.setCalibrationFromIntrinsics(
|
429
550
|
640,
|
430
551
|
480,
|
431
552
|
newCamIntrinsics=np.array(
|
@@ -459,7 +580,7 @@ class SimCameraProperties:
|
|
459
580
|
@classmethod
|
460
581
|
def LL2_960_720(cls) -> typing.Self:
|
461
582
|
prop = cls()
|
462
|
-
prop.
|
583
|
+
prop.setCalibrationFromIntrinsics(
|
463
584
|
960,
|
464
585
|
720,
|
465
586
|
newCamIntrinsics=np.array(
|
@@ -493,7 +614,7 @@ class SimCameraProperties:
|
|
493
614
|
@classmethod
|
494
615
|
def LL2_1280_720(cls) -> typing.Self:
|
495
616
|
prop = cls()
|
496
|
-
prop.
|
617
|
+
prop.setCalibrationFromIntrinsics(
|
497
618
|
1280,
|
498
619
|
720,
|
499
620
|
newCamIntrinsics=np.array(
|
@@ -527,7 +648,7 @@ class SimCameraProperties:
|
|
527
648
|
@classmethod
|
528
649
|
def OV9281_640_480(cls) -> typing.Self:
|
529
650
|
prop = cls()
|
530
|
-
prop.
|
651
|
+
prop.setCalibrationFromIntrinsics(
|
531
652
|
640,
|
532
653
|
480,
|
533
654
|
newCamIntrinsics=np.array(
|
@@ -561,7 +682,7 @@ class SimCameraProperties:
|
|
561
682
|
@classmethod
|
562
683
|
def OV9281_800_600(cls) -> typing.Self:
|
563
684
|
prop = cls()
|
564
|
-
prop.
|
685
|
+
prop.setCalibrationFromIntrinsics(
|
565
686
|
800,
|
566
687
|
600,
|
567
688
|
newCamIntrinsics=np.array(
|
@@ -595,7 +716,7 @@ class SimCameraProperties:
|
|
595
716
|
@classmethod
|
596
717
|
def OV9281_1280_720(cls) -> typing.Self:
|
597
718
|
prop = cls()
|
598
|
-
prop.
|
719
|
+
prop.setCalibrationFromIntrinsics(
|
599
720
|
1280,
|
600
721
|
720,
|
601
722
|
newCamIntrinsics=np.array(
|
@@ -629,7 +750,7 @@ class SimCameraProperties:
|
|
629
750
|
@classmethod
|
630
751
|
def OV9281_1920_1080(cls) -> typing.Self:
|
631
752
|
prop = cls()
|
632
|
-
prop.
|
753
|
+
prop.setCalibrationFromIntrinsics(
|
633
754
|
1920,
|
634
755
|
1080,
|
635
756
|
newCamIntrinsics=np.array(
|